[NWD] Move EPPlus classes to a new namespace.

Also rename the assembly.

This will allow us to have both the legacy and new EPPlus version
referenced in AppSheet for a slow rollout.

Change-Id: Idf4c4d2423041d626d6e4185d7de53b7b786164f
Reviewed-on: https://gnocchi-internal-review.git.corp.google.com/c/third_party/epplus/+/229480
Reviewed-by: Hughes Hilton <hugheshilton@google.com>
diff --git a/AppsheetEpplus/AppsheetEpplus.csproj b/AppsheetEpplus/AppsheetEpplus.csproj
new file mode 100644
index 0000000..e8379f7
--- /dev/null
+++ b/AppsheetEpplus/AppsheetEpplus.csproj
@@ -0,0 +1,7 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <TargetFramework>net8.0</TargetFramework>
+    <PackageId>Appsheet.AppsheetEpplus</PackageId>
+    <Version>1.0.9</Version>
+  </PropertyGroup>
+</Project>
\ No newline at end of file
diff --git a/AppsheetEpplus/CellStore.cs b/AppsheetEpplus/CellStore.cs
new file mode 100644
index 0000000..8632da5
--- /dev/null
+++ b/AppsheetEpplus/CellStore.cs
@@ -0,0 +1,1492 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		    Added       		        2012-11-25
+ *******************************************************************************/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+internal class IndexBase : IComparable<IndexBase> {
+  internal short Index;
+
+  public int CompareTo(IndexBase other) {
+    return Index < other.Index
+        ? -1
+        : Index > other.Index
+            ? 1
+            : 0;
+  }
+}
+
+internal class IndexItem : IndexBase {
+  internal int IndexPointer { get; set; }
+}
+
+internal class ColumnIndex : IndexBase {
+  private readonly IndexBase _searchIx = new();
+
+  internal int GetPosition(int row) {
+    var page = (short)(row >> CellStore<int>._pageBits);
+    _searchIx.Index = page;
+    var res =
+        (_pages != null
+                && page >= 0
+                && page < PageCount
+                && page < _pages.Length
+                && _pages[page] != null
+                && _pages[page].Index == page)
+            ? page
+            : Array.BinarySearch(_pages, 0, PageCount, _searchIx);
+    if (res >= 0) {
+      GetPage(row, ref res);
+      return res;
+    }
+    var p = ~res;
+
+    if (GetPage(row, ref p)) {
+      return p;
+    }
+    return res;
+  }
+
+  private bool GetPage(int row, ref int res) {
+    if (res < PageCount && _pages[res].MinIndex <= row && _pages[res].MaxIndex >= row) {
+      return true;
+    }
+    if (res + 1 < PageCount && (_pages[res + 1].MinIndex <= row)) {
+      do {
+        res++;
+      } while (res + 1 < PageCount && _pages[res + 1].MinIndex <= row);
+      //if (res + 1 < PageCount && _pages[res + 1].MaxIndex >= Row)
+      //{
+      return true;
+      //}
+      //else
+      //{
+      //    return false;
+      //}
+    }
+    if (res - 1 >= 0 && _pages[res - 1].MaxIndex >= row) {
+      do {
+        res--;
+      } while (res - 1 > 0 && _pages[res - 1].MaxIndex >= row);
+      //if (res > 0)
+      //{
+      return true;
+      //}
+      //else
+      //{
+      //    return false;
+      //}
+    }
+    return false;
+  }
+
+  internal int GetNextRow(int row) {
+    //var page = (int)((ulong)row >> CellStore<int>.pageBits);
+    var p = GetPosition(row);
+    if (p < 0) {
+      p = ~p;
+      if (p >= PageCount) {
+        return -1;
+      }
+      if (_pages[p].IndexOffset + _pages[p].Rows[0].Index < row) {
+        if (p + 1 >= PageCount) {
+          return -1;
+        }
+        return _pages[p + 1].IndexOffset + _pages[p].Rows[0].Index;
+      }
+      return _pages[p].IndexOffset + _pages[p].Rows[0].Index;
+    }
+    if (p < PageCount) {
+      var r = _pages[p].GetNextRow(row);
+      if (r >= 0) {
+        return _pages[p].IndexOffset + _pages[p].Rows[r].Index;
+      } else {
+        if (++p < PageCount) {
+          return _pages[p].IndexOffset + _pages[p].Rows[0].Index;
+        } else {
+          return -1;
+        }
+      }
+    }
+    return -1;
+  }
+
+  internal PageIndex[] _pages = new PageIndex[CellStore<int>._pagesPerColumnMin];
+  internal int PageCount;
+}
+
+internal class PageIndex : IndexBase {
+  private readonly IndexBase _searchIx = new();
+
+  public PageIndex() {
+    Rows = new IndexItem[CellStore<int>._pageSizeMin];
+    RowCount = 0;
+  }
+
+  public PageIndex(IndexItem[] rows, int count) {
+    Rows = rows;
+    RowCount = count;
+  }
+
+  public PageIndex(PageIndex pageItem, int start, int size)
+      : this(pageItem, start, size, pageItem.Index, pageItem.Offset) {}
+
+  public PageIndex(PageIndex pageItem, int start, int size, short index, int offset) {
+    Rows = new IndexItem[CellStore<int>.GetSize(size)];
+    Array.Copy(pageItem.Rows, start, Rows, 0, size);
+    RowCount = size;
+    Index = index;
+    Offset = offset;
+  }
+
+  internal int Offset;
+
+  internal int IndexOffset => IndexExpanded + Offset;
+
+  internal int IndexExpanded => (Index << CellStore<int>._pageBits);
+
+  internal IndexItem[] Rows { get; set; }
+
+  internal int RowCount;
+
+  internal int GetPosition(int offset) {
+    _searchIx.Index = (short)offset;
+    return (Rows != null
+            && offset > 0
+            && offset - 1 < RowCount
+            && offset - 1 < Rows.Length
+            && Rows[offset - 1] != null
+            && Rows[offset - 1].Index == offset)
+        ? offset - 1
+        : Array.BinarySearch(Rows, 0, RowCount, _searchIx);
+  }
+
+  internal int GetNextRow(int row) {
+    int offset = row - IndexOffset;
+    var o = GetPosition(offset);
+    if (o < 0) {
+      o = ~o;
+      if (o < RowCount) {
+        return o;
+      }
+      return -1;
+    }
+    return o;
+  }
+
+  public int MinIndex {
+    get {
+      if (Rows.Length > 0) {
+        return IndexOffset + Rows[0].Index;
+      }
+      return -1;
+    }
+  }
+
+  public int MaxIndex {
+    get {
+      if (RowCount > 0) {
+        return IndexOffset + Rows[RowCount - 1].Index;
+      }
+      return -1;
+    }
+  }
+
+  public int GetIndex(int pos) {
+    return IndexOffset + Rows[pos].Index;
+  }
+}
+
+/// <summary>
+/// This is the store for all Rows, Columns and Cells.
+/// It is a Dictionary implementation that allows you to change the Key (the RowID, ColumnID or CellID )
+/// </summary>
+internal class CellStore<T> {
+  /**** Size constants ****/
+  internal const int _pageBits = 10; //13bits=8192  Note: Maximum is 13 bits since short is used (PageMax=16K)
+  internal const int _pageSize = 1 << _pageBits;
+  internal const int _pageSizeMin = 1 << 10;
+  internal const int _pageSizeMax = _pageSize << 1; //Double page size
+  internal const int _colSizeMin = 32;
+  internal const int _pagesPerColumnMin = 32;
+
+  private List<T> _values = new();
+  internal ColumnIndex[] _columnIndex = new ColumnIndex[_colSizeMin];
+  internal IndexBase _searchIx = new();
+  internal int ColumnCount;
+
+  ~CellStore() {
+    if (_values != null) {
+      _values.Clear();
+      _values = null;
+    }
+    _columnIndex = null;
+  }
+
+  internal int GetPosition(int column) {
+    _searchIx.Index = (short)column;
+    return (_columnIndex != null
+            && column > 0
+            && column - 1 < ColumnCount
+            && column - 1 < _columnIndex.Length
+            && _columnIndex[column - 1] != null
+            && _columnIndex[column - 1].Index == column)
+        ? column - 1
+        : Array.BinarySearch(_columnIndex, 0, ColumnCount, _searchIx);
+  }
+
+  internal bool GetDimension(out int fromRow, out int fromCol, out int toRow, out int toCol) {
+    if (ColumnCount == 0) {
+      fromRow = fromCol = toRow = toCol = 0;
+      return false;
+    }
+    fromCol = _columnIndex[0].Index;
+    var fromIndex = 0;
+    if (fromCol <= 0 && ColumnCount > 1) {
+      fromCol = _columnIndex[1].Index;
+      fromIndex = 1;
+    } else if (ColumnCount == 1 && fromCol <= 0) {
+      fromRow = fromCol = toRow = toCol = 0;
+      return false;
+    }
+    var col = ColumnCount - 1;
+    while (col > 0) {
+      if (_columnIndex[col].PageCount == 0
+          || _columnIndex[col]._pages[0].RowCount > 1
+          || _columnIndex[col]._pages[0].Rows[0].Index > 0) {
+        break;
+      }
+      col--;
+    }
+    toCol = _columnIndex[col].Index;
+    if (toCol == 0) {
+      fromRow = fromCol = toRow = toCol = 0;
+      return false;
+    }
+    fromRow = toRow = 0;
+
+    for (int c = fromIndex; c < ColumnCount; c++) {
+      int first,
+          last;
+      if (_columnIndex[c].PageCount == 0) {
+        continue;
+      }
+      if (_columnIndex[c]._pages[0].RowCount > 0 && _columnIndex[c]._pages[0].Rows[0].Index > 0) {
+        first = _columnIndex[c]._pages[0].IndexOffset + _columnIndex[c]._pages[0].Rows[0].Index;
+      } else {
+        if (_columnIndex[c]._pages[0].RowCount > 1) {
+          first = _columnIndex[c]._pages[0].IndexOffset + _columnIndex[c]._pages[0].Rows[1].Index;
+        } else if (_columnIndex[c].PageCount > 1) {
+          first = _columnIndex[c]._pages[0].IndexOffset + _columnIndex[c]._pages[1].Rows[0].Index;
+        } else {
+          first = 0;
+        }
+      }
+      var lp = _columnIndex[c].PageCount - 1;
+      while (_columnIndex[c]._pages[lp].RowCount == 0 && lp != 0) {
+        lp--;
+      }
+      var p = _columnIndex[c]._pages[lp];
+      if (p.RowCount > 0) {
+        last = p.IndexOffset + p.Rows[p.RowCount - 1].Index;
+      } else {
+        last = first;
+      }
+      if (first > 0 && (first < fromRow || fromRow == 0)) {
+        fromRow = first;
+      }
+      if (first > 0 && (last > toRow || toRow == 0)) {
+        toRow = last;
+      }
+    }
+    if (fromRow <= 0 || toRow <= 0) {
+      fromRow = fromCol = toRow = toCol = 0;
+      return false;
+    }
+    return true;
+  }
+
+  internal int FindNext(int column) {
+    var c = GetPosition(column);
+    if (c < 0) {
+      return ~c;
+    }
+    return c;
+  }
+
+  internal T GetValue(int row, int column) {
+    int i = GetPointer(row, column);
+    if (i >= 0) {
+      return _values[i];
+    }
+    return default(T);
+  }
+
+  private int GetPointer(int row, int column) {
+    var col = GetPosition(column);
+    if (col >= 0) {
+      var pos = _columnIndex[col].GetPosition(row);
+      if (pos >= 0 && pos < _columnIndex[col].PageCount) {
+        var pageItem = _columnIndex[col]._pages[pos];
+        if (pageItem.MinIndex > row) {
+          pos--;
+          if (pos < 0) {
+            return -1;
+          }
+          pageItem = _columnIndex[col]._pages[pos];
+        }
+        short ix = (short)(row - pageItem.IndexOffset);
+        _searchIx.Index = ix;
+        var cellPos =
+            (pageItem.Rows != null
+                    && ix > 0
+                    && ix - 1 < pageItem.RowCount
+                    && ix - 1 < pageItem.Rows.Length
+                    && pageItem.Rows[ix - 1] != null
+                    && pageItem.Rows[ix - 1].Index == ix)
+                ? ix - 1
+                : Array.BinarySearch(pageItem.Rows, 0, pageItem.RowCount, _searchIx);
+        if (cellPos >= 0) {
+          return pageItem.Rows[cellPos].IndexPointer;
+        } //Cell does not exist
+        return -1;
+      } //Page does not exist
+      return -1;
+    } //Column does not exist
+    return -1;
+  }
+
+  internal bool Exists(int row, int column) {
+    return GetPointer(row, column) >= 0;
+  }
+
+  internal bool Exists(int row, int column, ref T value) {
+    var p = GetPointer(row, column);
+    if (p >= 0) {
+      value = _values[p];
+      return true;
+    }
+    return false;
+  }
+
+  internal void SetValue(int row, int column, T value) {
+    var col =
+        (_columnIndex != null
+                && column > 0
+                && column - 1 < ColumnCount
+                && column - 1 < _columnIndex.Length
+                && _columnIndex[column - 1] != null
+                && _columnIndex[column - 1].Index == column)
+            ? column - 1
+            : Array.BinarySearch(
+                _columnIndex,
+                0,
+                ColumnCount,
+                new IndexBase {
+                  Index = (short)(column),
+                });
+    var page = (short)(row >> _pageBits);
+    if (col >= 0) {
+      //var pos = Array.BinarySearch(_columnIndex[col].Pages, 0, _columnIndex[col].Count, new IndexBase() { Index = page });
+      var pos = _columnIndex[col].GetPosition(row);
+      if (pos < 0) {
+        pos = ~pos;
+        if (pos - 1 < 0 || _columnIndex[col]._pages[pos - 1].IndexOffset + _pageSize - 1 < row) {
+          AddPage(_columnIndex[col], pos, page);
+        } else {
+          pos--;
+        }
+      }
+      if (pos >= _columnIndex[col].PageCount) {
+        AddPage(_columnIndex[col], pos, page);
+      }
+      var pageItem = _columnIndex[col]._pages[pos];
+      if (pageItem.IndexOffset > row) {
+        pos--;
+        page--;
+        if (pos < 0) {
+          throw (new("Unexpected error when setting value"));
+        }
+        pageItem = _columnIndex[col]._pages[pos];
+      }
+
+      short ix = (short)(row - ((pageItem.Index << _pageBits) + pageItem.Offset));
+      _searchIx.Index = ix;
+      var cellPos =
+          (pageItem.Rows != null
+                  && ix >= 0
+                  && ix < pageItem.RowCount
+                  && ix < pageItem.Rows.Length
+                  && pageItem.Rows[ix] != null
+                  && pageItem.Rows[ix].Index == ix)
+              ? ix
+              : Array.BinarySearch(pageItem.Rows, 0, pageItem.RowCount, _searchIx);
+      if (cellPos < 0) {
+        cellPos = ~cellPos;
+        AddCell(_columnIndex[col], pos, cellPos, ix, value);
+      } else {
+        _values[pageItem.Rows[cellPos].IndexPointer] = value;
+      }
+    } else //Column does not exist
+    {
+      col = ~col;
+      AddColumn(col, column);
+      AddPage(_columnIndex[col], 0, page);
+      short ix = (short)(row - (page << _pageBits));
+      AddCell(_columnIndex[col], 0, 0, ix, value);
+    }
+  }
+
+  internal void Insert(int fromRow, int fromCol, int rows, int columns) {
+    if (columns > 0) {
+      var col = GetPosition(fromCol);
+      if (col < 0) {
+        col = ~col;
+      }
+      for (var c = col; c < ColumnCount; c++) {
+        _columnIndex[c].Index += (short)columns;
+      }
+    } else {
+      var page = fromRow >> _pageBits;
+      for (int c = 0; c < ColumnCount; c++) {
+        var column = _columnIndex[c];
+        var pagePos = column.GetPosition(fromRow);
+        if (pagePos >= 0) {
+          if (fromRow >= column._pages[pagePos].MinIndex
+              && fromRow
+                  <= column._pages[pagePos].MaxIndex) //The row is inside the page
+          {
+            int offset = fromRow - column._pages[pagePos].IndexOffset;
+            var rowPos = column._pages[pagePos].GetPosition(offset);
+            if (rowPos < 0) {
+              rowPos = ~rowPos;
+            }
+            UpdateIndexOffset(column, pagePos, rowPos, fromRow, rows);
+          } else if (column._pages[pagePos].MinIndex > fromRow - 1
+              && pagePos
+                  > 0) //The row is on the page before.
+          {
+            int offset = fromRow - ((page - 1) << _pageBits);
+            var rowPos = column._pages[pagePos - 1].GetPosition(offset);
+            if (rowPos > 0 && pagePos > 0) {
+              UpdateIndexOffset(column, pagePos - 1, rowPos, fromRow, rows);
+            }
+          } else if (column.PageCount >= pagePos + 1) {
+            int offset = fromRow - column._pages[pagePos].IndexOffset;
+            var rowPos = column._pages[pagePos].GetPosition(offset);
+            if (rowPos < 0) {
+              rowPos = ~rowPos;
+            }
+            if (column._pages[pagePos].RowCount > rowPos) {
+              UpdateIndexOffset(column, pagePos, rowPos, fromRow, rows);
+            } else {
+              UpdateIndexOffset(column, pagePos + 1, 0, fromRow, rows);
+            }
+          }
+        } else {
+          UpdateIndexOffset(column, ~pagePos, 0, fromRow, rows);
+        }
+      }
+    }
+  }
+
+  internal void Clear(int fromRow, int fromCol, int rows, int columns) {
+    Delete(fromRow, fromCol, rows, columns, false);
+  }
+
+  internal void Delete(int fromRow, int fromCol, int rows, int columns) {
+    Delete(fromRow, fromCol, rows, columns, true);
+  }
+
+  internal void Delete(int fromRow, int fromCol, int rows, int columns, bool shift) {
+    if (columns > 0 && fromRow == 1 && rows >= ExcelPackage.MaxRows) {
+      DeleteColumns(fromCol, columns, shift);
+    } else {
+      var toCol = fromCol + columns - 1;
+      var pageFromRow = fromRow >> _pageBits;
+      for (int c = 0; c < ColumnCount; c++) {
+        var column = _columnIndex[c];
+        if (column.Index >= fromCol) {
+          if (column.Index > toCol) {
+            break;
+          }
+          var pagePos = column.GetPosition(fromRow);
+          if (pagePos < 0) {
+            pagePos = ~pagePos;
+          }
+          if (pagePos < column.PageCount) {
+            var page = column._pages[pagePos];
+            if (shift
+                && page.RowCount > 0
+                && page.MinIndex > fromRow
+                && page.MaxIndex >= fromRow + rows) {
+              var o = page.MinIndex - fromRow;
+              if (o < rows) {
+                rows -= o;
+                page.Offset -= o;
+                UpdatePageOffset(column, pagePos, o);
+              } else {
+                page.Offset -= rows;
+                UpdatePageOffset(column, pagePos, rows);
+                continue;
+              }
+            }
+            if (page.RowCount > 0
+                && page.MinIndex <= fromRow + rows - 1
+                && page.MaxIndex
+                    >= fromRow) //The row is inside the page
+            {
+              var endRow = fromRow + rows;
+              var delEndRow = DeleteCells(column._pages[pagePos], fromRow, endRow, shift);
+              if (shift && delEndRow != fromRow) {
+                UpdatePageOffset(column, pagePos, delEndRow - fromRow);
+              }
+              if (endRow > delEndRow
+                  && pagePos < column.PageCount
+                  && column._pages[pagePos].MinIndex < endRow) {
+                pagePos = (delEndRow == fromRow ? pagePos : pagePos + 1);
+                var rowsLeft = DeletePage(
+                    shift ? fromRow : delEndRow,
+                    endRow - delEndRow,
+                    column,
+                    pagePos,
+                    shift);
+                //if (shift) UpdatePageOffset(column, pagePos, endRow - fromRow - rowsLeft);
+                if (rowsLeft > 0) {
+                  var fr = shift ? fromRow : endRow - rowsLeft;
+                  pagePos = column.GetPosition(fr);
+                  DeleteCells(column._pages[pagePos], fr, shift ? fr + rowsLeft : endRow, shift);
+                  if (shift) {
+                    UpdatePageOffset(column, pagePos, rowsLeft);
+                  }
+                }
+              }
+            } else if (pagePos > 0
+                && column._pages[pagePos].IndexOffset
+                    > fromRow) //The row is on the page before.
+            {
+              int offset = fromRow + rows - 1 - ((pageFromRow - 1) << _pageBits);
+              var rowPos = column._pages[pagePos - 1].GetPosition(offset);
+              if (rowPos > 0 && pagePos > 0) {
+                if (shift) {
+                  UpdateIndexOffset(column, pagePos - 1, rowPos, fromRow + rows - 1, -rows);
+                }
+              }
+            } else {
+              if (shift && pagePos + 1 < column.PageCount) {
+                UpdateIndexOffset(
+                    column,
+                    pagePos + 1,
+                    0,
+                    column._pages[pagePos + 1].MinIndex,
+                    -rows);
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  private void UpdatePageOffset(ColumnIndex column, int pagePos, int rows) {
+    //Update Pageoffset
+
+    if (++pagePos < column.PageCount) {
+      for (int p = pagePos; p < column.PageCount; p++) {
+        if (column._pages[p].Offset - rows <= -_pageSize) {
+          column._pages[p].Index--;
+          column._pages[p].Offset -= rows - _pageSize;
+        } else {
+          column._pages[p].Offset -= rows;
+        }
+      }
+
+      if (Math.Abs(column._pages[pagePos].Offset) > _pageSize
+          || Math.Abs(column._pages[pagePos].Rows[column._pages[pagePos].RowCount - 1].Index)
+              > _pageSizeMax) //Split or Merge???
+      {
+        ResetPageOffset(column, pagePos, rows);
+      }
+    }
+  }
+
+  private void ResetPageOffset(ColumnIndex column, int pagePos, int rows) {
+    PageIndex fromPage = column._pages[pagePos];
+    PageIndex toPage;
+    short pageAdd = 0;
+    if (fromPage.Offset < -_pageSize) {
+      toPage = column._pages[pagePos - 1];
+      pageAdd = -1;
+      if (fromPage.Index - 1 == toPage.Index) {
+        if (fromPage.IndexOffset
+                + fromPage.Rows[fromPage.RowCount - 1].Index
+                - toPage.IndexOffset
+                + toPage.Rows[0].Index
+            <= _pageSizeMax) {
+          MergePage(column, pagePos - 1);
+        }
+      } else //No page after
+      {
+        fromPage.Index -= pageAdd;
+        fromPage.Offset += _pageSize;
+      }
+    } else if (fromPage.Offset > _pageSize) {
+      toPage = column._pages[pagePos + 1];
+      pageAdd = 1;
+      if (fromPage.Index + 1 == toPage.Index) {} else {
+        fromPage.Index += pageAdd;
+        fromPage.Offset += _pageSize;
+      }
+    }
+  }
+
+  private int DeletePage(int fromRow, int rows, ColumnIndex column, int pagePos, bool shift) {
+    PageIndex page = column._pages[pagePos];
+    var startRows = rows;
+    while (page != null
+            && page.MinIndex >= fromRow
+            && ((shift && page.MaxIndex < fromRow + rows)
+                    || (!shift && page.MaxIndex < fromRow + startRows))) {
+      //Delete entire page.
+      var delSize = page.MaxIndex - page.MinIndex + 1;
+      rows -= delSize;
+      var prevOffset = page.Offset;
+      Array.Copy(
+          column._pages,
+          pagePos + 1,
+          column._pages,
+          pagePos,
+          column.PageCount - pagePos + 1);
+      column.PageCount--;
+      if (column.PageCount == 0) {
+        return 0;
+      }
+      if (shift) {
+        for (int i = pagePos; i < column.PageCount; i++) {
+          column._pages[i].Offset -= delSize;
+          if (column._pages[i].Offset <= -_pageSize) {
+            column._pages[i].Index--;
+            column._pages[i].Offset += _pageSize;
+          }
+        }
+      }
+      if (column.PageCount > pagePos) {
+        page = column._pages[pagePos];
+        //page.Offset = pagePos == 0 ? 1 : prevOffset;  //First page can only reference to rows starting from Index == 1
+      } else {
+        //No more pages, return 0
+        return 0;
+      }
+    }
+    return rows;
+  }
+
+  private int DeleteCells(PageIndex page, int fromRow, int toRow, bool shift) {
+    var fromPos = page.GetPosition(fromRow - (page.IndexOffset));
+    if (fromPos < 0) {
+      fromPos = ~fromPos;
+    }
+    var maxRow = page.MaxIndex;
+    var offset = toRow - page.IndexOffset;
+    if (offset > _pageSizeMax) {
+      offset = _pageSizeMax;
+    }
+    var toPos = page.GetPosition(offset);
+    if (toPos < 0) {
+      toPos = ~toPos;
+    }
+
+    if (fromPos <= toPos && fromPos < page.RowCount && page.GetIndex(fromPos) < toRow) {
+      if (toRow > page.MaxIndex) {
+        if (fromRow
+            == page.MinIndex) //Delete entire page, late in the page delete method
+        {
+          return fromRow;
+        }
+        var r = page.MaxIndex;
+        var deletedRow = page.RowCount - fromPos;
+        page.RowCount -= deletedRow;
+        return r + 1;
+      }
+      var rows = toRow - fromRow;
+      if (shift) {
+        UpdateRowIndex(page, toPos, rows);
+      }
+      Array.Copy(page.Rows, toPos, page.Rows, fromPos, page.RowCount - toPos);
+      page.RowCount -= toPos - fromPos;
+
+      return toRow;
+    }
+    if (shift) {
+      UpdateRowIndex(page, toPos, toRow - fromRow);
+    }
+    return toRow < maxRow ? toRow : maxRow;
+  }
+
+  private static void UpdateRowIndex(PageIndex page, int toPos, int rows) {
+    for (int r = toPos; r < page.RowCount; r++) {
+      page.Rows[r].Index -= (short)rows;
+    }
+  }
+
+  private void DeleteColumns(int fromCol, int columns, bool shift) {
+    var fPos = GetPosition(fromCol);
+    if (fPos < 0) {
+      fPos = ~fPos;
+    }
+    int tPos = fPos;
+    for (var c = fPos; c <= ColumnCount; c++) {
+      tPos = c;
+      if (tPos == ColumnCount || _columnIndex[c].Index >= fromCol + columns) {
+        break;
+      }
+    }
+
+    if (ColumnCount <= fPos) {
+      return;
+    }
+
+    if (_columnIndex[fPos].Index >= fromCol && _columnIndex[fPos].Index <= fromCol + columns) {
+      if (tPos < ColumnCount) {
+        Array.Copy(_columnIndex, tPos, _columnIndex, fPos, ColumnCount - tPos);
+      }
+      ColumnCount -= (tPos - fPos);
+    }
+    if (shift) {
+      for (var c = fPos; c < ColumnCount; c++) {
+        _columnIndex[c].Index -= (short)columns;
+      }
+    }
+  }
+
+  private void UpdateIndexOffset(ColumnIndex column, int pagePos, int rowPos, int row, int rows) {
+    if (pagePos >= column.PageCount) {
+      return; //A page after last cell.
+    }
+    var page = column._pages[pagePos];
+    if (rows > _pageSize) {
+      short addPages = (short)(rows >> _pageBits);
+      int offset = +(rows - (_pageSize * addPages));
+      for (int p = pagePos + 1; p < column.PageCount; p++) {
+        if (column._pages[p].Offset + offset > _pageSize) {
+          column._pages[p].Index += (short)(addPages + 1);
+          column._pages[p].Offset += offset - _pageSize;
+        } else {
+          column._pages[p].Index += addPages;
+          column._pages[p].Offset += offset;
+        }
+      }
+
+      var size = page.RowCount - rowPos;
+      if (page.RowCount > rowPos) {
+        if (column.PageCount - 1
+            == pagePos) //No page after, create a new one.
+        {
+          //Copy rows to next page.
+          var newPage = CopyNew(page, rowPos, size);
+          newPage.Index = (short)((row + rows) >> _pageBits);
+          newPage.Offset = row + rows - (newPage.Index * _pageSize) - newPage.Rows[0].Index;
+          if (newPage.Offset > _pageSize) {
+            newPage.Index++;
+            newPage.Offset -= _pageSize;
+          }
+          AddPage(column, pagePos + 1, newPage);
+          page.RowCount = rowPos;
+        } else {
+          if (column._pages[pagePos + 1].RowCount + size
+              > _pageSizeMax) //Split Page
+          {
+            SplitPageInsert(column, pagePos, rowPos, rows, size, addPages);
+          } else //Copy Page.
+          {
+            CopyMergePage(page, rowPos, rows, size, column._pages[pagePos + 1]);
+          }
+        }
+      }
+    } else {
+      //Add to Pages.
+      for (int r = rowPos; r < page.RowCount; r++) {
+        page.Rows[r].Index += (short)rows;
+      }
+      if (page.Offset + page.Rows[page.RowCount - 1].Index
+          >= _pageSizeMax) //Can not be larger than the max size of the page.
+      {
+        AdjustIndex(column, pagePos);
+        if (page.Offset + page.Rows[page.RowCount - 1].Index >= _pageSizeMax) {
+          pagePos = SplitPage(column, pagePos);
+        }
+        //IndexItem[] newRows = new IndexItem[GetSize(page.RowCount - page.Rows[r].Index)];
+        //var newPage = new PageIndex(newRows, r);
+        //newPage.Index = (short)(pagePos + 1);
+        //TODO: MoveRows to next page.
+      }
+
+      for (int p = pagePos + 1; p < column.PageCount; p++) {
+        if (column._pages[p].Offset + rows < _pageSize) {
+          column._pages[p].Offset += rows;
+        } else {
+          column._pages[p].Index++;
+          column._pages[p].Offset = (column._pages[p].Offset + rows) % _pageSize;
+        }
+      }
+    }
+  }
+
+  private void SplitPageInsert(
+      ColumnIndex column,
+      int pagePos,
+      int rowPos,
+      int rows,
+      int size,
+      int addPages) {
+    var newRows = new IndexItem[GetSize(size)];
+    var page = column._pages[pagePos];
+
+    var rStart = -1;
+    for (int r = rowPos; r < page.RowCount; r++) {
+      if (page.IndexExpanded - (page.Rows[r].Index + rows) > _pageSize) {
+        rStart = r;
+        break;
+      }
+      page.Rows[r].Index += (short)rows;
+    }
+    var rc = page.RowCount - rStart;
+    page.RowCount = rStart;
+    if (rc > 0) {
+      //Copy to a new page
+      var row = page.IndexOffset;
+      var newPage = CopyNew(page, rStart, rc);
+      var ix = (short)(page.Index + addPages);
+      var offset = page.IndexOffset + rows - (ix * _pageSize);
+      if (offset > _pageSize) {
+        ix += (short)(offset / _pageSize);
+        offset %= _pageSize;
+      }
+      newPage.Index = ix;
+      newPage.Offset = offset;
+      AddPage(column, pagePos + 1, newPage);
+    }
+
+    //Copy from next Row
+  }
+
+  private void CopyMergePage(PageIndex page, int rowPos, int rows, int size, PageIndex toPage) {
+    var startRow = page.IndexOffset + page.Rows[rowPos].Index + rows;
+    var newRows = new IndexItem[GetSize(toPage.RowCount + size)];
+    page.RowCount -= size;
+    Array.Copy(page.Rows, rowPos, newRows, 0, size);
+    for (int r = 0; r < size; r++) {
+      newRows[r].Index += (short)(page.IndexOffset + rows - toPage.IndexOffset);
+    }
+
+    Array.Copy(toPage.Rows, 0, newRows, size, toPage.RowCount);
+    toPage.Rows = newRows;
+    toPage.RowCount += size;
+  }
+
+  private void MergePage(ColumnIndex column, int pagePos) {
+    PageIndex page1 = column._pages[pagePos];
+    PageIndex page2 = column._pages[pagePos + 1];
+
+    var newPage = new PageIndex(page1, 0, page1.RowCount + page2.RowCount);
+    newPage.RowCount = page1.RowCount + page2.RowCount;
+    Array.Copy(page1.Rows, 0, newPage.Rows, 0, page1.RowCount);
+    Array.Copy(page2.Rows, 0, newPage.Rows, page1.RowCount, page2.RowCount);
+    for (int r = page1.RowCount; r < newPage.RowCount; r++) {
+      newPage.Rows[r].Index += (short)(page2.IndexOffset - page1.IndexOffset);
+    }
+
+    column._pages[pagePos] = newPage;
+    column.PageCount--;
+
+    if (column.PageCount > (pagePos + 1)) {
+      Array.Copy(
+          column._pages,
+          pagePos + 2,
+          column._pages,
+          pagePos + 1,
+          column.PageCount - (pagePos + 1));
+      for (int p = pagePos + 1; p < column.PageCount; p++) {
+        column._pages[p].Index--;
+        column._pages[p].Offset += _pageSize;
+      }
+    }
+  }
+
+  private PageIndex CopyNew(PageIndex pageFrom, int rowPos, int size) {
+    IndexItem[] newRows = new IndexItem[GetSize(size)];
+    Array.Copy(pageFrom.Rows, rowPos, newRows, 0, size);
+    return new(newRows, size);
+  }
+
+  internal static int GetSize(int size) {
+    var newSize = 256;
+    while (newSize < size) {
+      newSize <<= 1;
+    }
+    return newSize;
+  }
+
+  private void AddCell(ColumnIndex columnIndex, int pagePos, int pos, short ix, T value) {
+    PageIndex pageItem = columnIndex._pages[pagePos];
+    if (pageItem.RowCount == pageItem.Rows.Length) {
+      if (pageItem.RowCount
+          == _pageSizeMax) //Max size-->Split
+      {
+        pagePos = SplitPage(columnIndex, pagePos);
+        if (columnIndex._pages[pagePos - 1].RowCount > pos) {
+          pagePos--;
+        } else {
+          pos -= columnIndex._pages[pagePos - 1].RowCount;
+        }
+        pageItem = columnIndex._pages[pagePos];
+      } else //Expand to double size.
+      {
+        var rowsTmp = new IndexItem[pageItem.Rows.Length << 1];
+        Array.Copy(pageItem.Rows, 0, rowsTmp, 0, pageItem.RowCount);
+        pageItem.Rows = rowsTmp;
+      }
+    }
+    if (pos < pageItem.RowCount) {
+      Array.Copy(pageItem.Rows, pos, pageItem.Rows, pos + 1, pageItem.RowCount - pos);
+    }
+    pageItem.Rows[pos] = new() {
+      Index = ix,
+      IndexPointer = _values.Count,
+    };
+    _values.Add(value);
+    pageItem.RowCount++;
+  }
+
+  private int SplitPage(ColumnIndex columnIndex, int pagePos) {
+    var page = columnIndex._pages[pagePos];
+    if (page.Offset != 0) {
+      var offset = page.Offset;
+      page.Offset = 0;
+      for (int r = 0; r < page.RowCount; r++) {
+        page.Rows[r].Index -= (short)offset;
+      }
+    }
+    //Find Split pos
+    int splitPos = 0;
+    for (int r = 0; r < page.RowCount; r++) {
+      if (page.Rows[r].Index > _pageSize) {
+        splitPos = r;
+        break;
+      }
+    }
+    var newPage = new PageIndex(page, 0, splitPos);
+    var nextPage = new PageIndex(
+        page,
+        splitPos,
+        page.RowCount - splitPos,
+        (short)(page.Index + 1),
+        page.Offset);
+
+    for (int r = 0; r < nextPage.RowCount; r++) {
+      nextPage.Rows[r].Index = (short)(nextPage.Rows[r].Index - _pageSize);
+    }
+
+    columnIndex._pages[pagePos] = newPage;
+    if (columnIndex.PageCount + 1 > columnIndex._pages.Length) {
+      var pageTmp = new PageIndex[columnIndex._pages.Length << 1];
+      Array.Copy(columnIndex._pages, 0, pageTmp, 0, columnIndex.PageCount);
+      columnIndex._pages = pageTmp;
+    }
+    Array.Copy(
+        columnIndex._pages,
+        pagePos + 1,
+        columnIndex._pages,
+        pagePos + 2,
+        columnIndex.PageCount - pagePos - 1);
+    columnIndex._pages[pagePos + 1] = nextPage;
+    page = nextPage;
+    //pos -= PageSize;
+    columnIndex.PageCount++;
+    return pagePos + 1;
+  }
+
+  private PageIndex AdjustIndex(ColumnIndex columnIndex, int pagePos) {
+    PageIndex page = columnIndex._pages[pagePos];
+    //First Adjust indexes
+    if (page.Offset + page.Rows[0].Index >= _pageSize
+        || page.Offset >= _pageSize
+        || page.Rows[0].Index >= _pageSize) {
+      page.Index++;
+      page.Offset -= _pageSize;
+    } else if (page.Offset + page.Rows[0].Index <= -_pageSize
+        || page.Offset <= -_pageSize
+        || page.Rows[0].Index <= -_pageSize) {
+      page.Index--;
+      page.Offset += _pageSize;
+    }
+    return page;
+  }
+
+  private void AddPage(ColumnIndex column, int pos, short index) {
+    AddPage(column, pos);
+    column._pages[pos] = new() {
+      Index = index,
+    };
+    if (pos > 0) {
+      var pp = column._pages[pos - 1];
+      if (pp.RowCount > 0 && pp.Rows[pp.RowCount - 1].Index > _pageSize) {
+        column._pages[pos].Offset = pp.Rows[pp.RowCount - 1].Index - _pageSize;
+      }
+    }
+  }
+
+  /// <summary>
+  /// Add a new page to the collection
+  /// </summary>
+  /// <param name="column">The column</param>
+  /// <param name="pos">Position</param>
+  /// <param name="page">The new page object to add</param>
+  private void AddPage(ColumnIndex column, int pos, PageIndex page) {
+    AddPage(column, pos);
+    column._pages[pos] = page;
+  }
+
+  /// <summary>
+  /// Add a new page to the collection
+  /// </summary>
+  /// <param name="column">The column</param>
+  /// <param name="pos">Position</param>
+  private void AddPage(ColumnIndex column, int pos) {
+    if (column.PageCount == column._pages.Length) {
+      var pageTmp = new PageIndex[column._pages.Length * 2];
+      Array.Copy(column._pages, 0, pageTmp, 0, column.PageCount);
+      column._pages = pageTmp;
+    }
+    if (pos < column.PageCount) {
+      Array.Copy(column._pages, pos, column._pages, pos + 1, column.PageCount - pos);
+    }
+    column.PageCount++;
+  }
+
+  private void AddColumn(int pos, int column) {
+    if (ColumnCount == _columnIndex.Length) {
+      var colTmp = new ColumnIndex[_columnIndex.Length * 2];
+      Array.Copy(_columnIndex, 0, colTmp, 0, ColumnCount);
+      _columnIndex = colTmp;
+    }
+    if (pos < ColumnCount) {
+      Array.Copy(_columnIndex, pos, _columnIndex, pos + 1, ColumnCount - pos);
+    }
+    _columnIndex[pos] = new() {
+      Index = (short)(column),
+    };
+    ColumnCount++;
+  }
+
+  internal bool NextCell(ref int row, ref int col) {
+    return NextCell(ref row, ref col, 0, 0, ExcelPackage.MaxRows, ExcelPackage.MaxColumns);
+  }
+
+  internal bool NextCell(
+      ref int row,
+      ref int col,
+      int minRow,
+      int minColPos,
+      int maxRow,
+      int maxColPos) {
+    if (minColPos >= ColumnCount) {
+      return false;
+    }
+    if (maxColPos >= ColumnCount) {
+      maxColPos = ColumnCount - 1;
+    }
+    var c = GetPosition(col);
+    if (c >= 0) {
+      if (c > maxColPos) {
+        if (col <= minColPos) {
+          return false;
+        }
+        col = minColPos;
+        return NextCell(ref row, ref col);
+      }
+      var r = GetNextCell(ref row, ref c, minColPos, maxRow, maxColPos);
+      col = _columnIndex[c].Index;
+      return r;
+    }
+    c = ~c;
+    if (c > _columnIndex[c].Index) {
+      if (col <= minColPos) {
+        return false;
+      }
+      col = minColPos;
+      return NextCell(ref row, ref col, minRow, minColPos, maxRow, maxColPos);
+    }
+    {
+      var r = GetNextCell(ref c, ref row, minColPos, maxRow, maxColPos);
+      col = _columnIndex[c].Index;
+      return r;
+    }
+  }
+
+  internal bool GetNextCell(
+      ref int row,
+      ref int colPos,
+      int startColPos,
+      int endRow,
+      int endColPos) {
+    if (ColumnCount == 0) {
+      return false;
+    }
+    if (++colPos < ColumnCount && colPos <= endColPos) {
+      var r = _columnIndex[colPos].GetNextRow(row);
+      if (r
+          == row) //Exists next Row
+      {
+        return true;
+      }
+      int minRow,
+          minCol;
+      if (r > row) {
+        minRow = r;
+        minCol = colPos;
+      } else {
+        minRow = int.MaxValue;
+        minCol = 0;
+      }
+
+      var c = colPos + 1;
+      while (c < ColumnCount && c <= endColPos) {
+        r = _columnIndex[c].GetNextRow(row);
+        if (r
+            == row) //Exists next Row
+        {
+          colPos = c;
+          return true;
+        }
+        if (r > row && r < minRow) {
+          minRow = r;
+          minCol = c;
+        }
+        c++;
+      }
+      c = startColPos;
+      if (row < endRow) {
+        row++;
+        while (c < colPos) {
+          r = _columnIndex[c].GetNextRow(row);
+          if (r
+              == row) //Exists next Row
+          {
+            colPos = c;
+            return true;
+          }
+          if (r > row && (r < minRow || (r == minRow && c < minCol)) && r <= endRow) {
+            minRow = r;
+            minCol = c;
+          }
+          c++;
+        }
+      }
+
+      if (minRow == int.MaxValue || minRow > endRow) {
+        return false;
+      }
+      row = minRow;
+      colPos = minCol;
+      return true;
+    }
+    if (colPos <= startColPos || row >= endRow) {
+      return false;
+    }
+    colPos = startColPos - 1;
+    row++;
+    return GetNextCell(ref row, ref colPos, startColPos, endRow, endColPos);
+  }
+
+  internal bool PrevCell(ref int row, ref int col) {
+    return PrevCell(ref row, ref col, 0, 0, ExcelPackage.MaxRows, ExcelPackage.MaxColumns);
+  }
+
+  private bool PrevCell(
+      ref int row,
+      ref int col,
+      int minRow,
+      int minColPos,
+      int maxRow,
+      int maxColPos) {
+    if (minColPos >= ColumnCount) {
+      return false;
+    }
+    if (maxColPos >= ColumnCount) {
+      maxColPos = ColumnCount - 1;
+    }
+    var c = GetPosition(col);
+    if (c >= 0) {
+      if (c == 0) {
+        if (col >= maxColPos) {
+          return false;
+        }
+        if (row == minRow) {
+          return false;
+        }
+        row--;
+        col = maxColPos;
+        return PrevCell(ref row, ref col, minRow, minColPos, maxRow, maxColPos);
+      }
+      var ret = GetPrevCell(ref row, ref c, minRow, minColPos, maxColPos);
+      if (ret) {
+        col = _columnIndex[c].Index;
+      }
+      return ret;
+    }
+    c = ~c;
+    if (c == 0) {
+      if (col >= maxColPos || row <= 0) {
+        return false;
+      }
+      col = maxColPos;
+      row--;
+      return PrevCell(ref row, ref col, minRow, minColPos, maxRow, maxColPos);
+    }
+    {
+      var ret = GetPrevCell(ref row, ref c, minRow, minColPos, maxColPos);
+      if (ret) {
+        col = _columnIndex[c].Index;
+      }
+      return ret;
+    }
+  }
+
+  internal bool GetPrevCell(
+      ref int row,
+      ref int colPos,
+      int startRow,
+      int startColPos,
+      int endColPos) {
+    if (ColumnCount == 0) {
+      return false;
+    }
+    if (--colPos >= startColPos)
+    //                if (++colPos < ColumnCount && colPos <= endColPos)
+    {
+      var r = _columnIndex[colPos].GetNextRow(row);
+      if (r
+          == row) //Exists next Row
+      {
+        return true;
+      }
+      int minRow,
+          minCol;
+      if (r > row && r >= startRow) {
+        minRow = r;
+        minCol = colPos;
+      } else {
+        minRow = int.MaxValue;
+        minCol = 0;
+      }
+
+      var c = colPos - 1;
+      if (c >= startColPos) {
+        while (c >= startColPos) {
+          r = _columnIndex[c].GetNextRow(row);
+          if (r
+              == row) //Exists next Row
+          {
+            colPos = c;
+            return true;
+          }
+          if (r > row && r < minRow && r >= startRow) {
+            minRow = r;
+            minCol = c;
+          }
+          c--;
+        }
+      }
+      if (row > startRow) {
+        c = endColPos;
+        row--;
+        while (c > colPos) {
+          r = _columnIndex[c].GetNextRow(row);
+          if (r
+              == row) //Exists next Row
+          {
+            colPos = c;
+            return true;
+          }
+          if (r > row && r < minRow && r >= startRow) {
+            minRow = r;
+            minCol = c;
+          }
+          c--;
+        }
+      }
+      if (minRow == int.MaxValue || startRow < minRow) {
+        return false;
+      }
+      row = minRow;
+      colPos = minCol;
+      return true;
+    }
+    colPos = ColumnCount;
+    row--;
+    if (row < startRow) {
+      return false;
+    }
+    return GetPrevCell(ref colPos, ref row, startRow, startColPos, endColPos);
+  }
+}
+
+internal class CellsStoreEnumerator<T> : IEnumerable<T>, IEnumerator<T> {
+  private readonly CellStore<T> _cellStore;
+  private int row,
+      colPos;
+  private int[] pagePos,
+      cellPos;
+  private readonly int _startRow;
+  private readonly int _startCol;
+  private readonly int _endRow;
+  private readonly int _endCol;
+  private int minRow,
+      minColPos,
+      maxRow,
+      maxColPos;
+
+  public CellsStoreEnumerator(CellStore<T> cellStore)
+      : this(cellStore, 0, 0, ExcelPackage.MaxRows, ExcelPackage.MaxColumns) {}
+
+  public CellsStoreEnumerator(
+      CellStore<T> cellStore,
+      int startRow,
+      int startCol,
+      int endRow,
+      int endCol) {
+    _cellStore = cellStore;
+
+    _startRow = startRow;
+    _startCol = startCol;
+    _endRow = endRow;
+    _endCol = endCol;
+
+    Init();
+  }
+
+  internal void Init() {
+    minRow = _startRow;
+    maxRow = _endRow;
+
+    minColPos = _cellStore.GetPosition(_startCol);
+    if (minColPos < 0) {
+      minColPos = ~minColPos;
+    }
+    maxColPos = _cellStore.GetPosition(_endCol);
+    if (maxColPos < 0) {
+      maxColPos = ~maxColPos - 1;
+    }
+    row = minRow;
+    colPos = minColPos - 1;
+
+    var cols = maxColPos - minColPos + 1;
+    pagePos = new int[cols];
+    cellPos = new int[cols];
+    for (int i = 0; i < cols; i++) {
+      pagePos[i] = -1;
+      cellPos[i] = -1;
+    }
+  }
+
+  internal int Row => row;
+
+  internal int Column {
+    get {
+      if (colPos == -1) {
+        MoveNext();
+      }
+      if (colPos == -1) {
+        return 0;
+      }
+      return _cellStore._columnIndex[colPos].Index;
+    }
+  }
+
+  internal T Value {
+    get => _cellStore.GetValue(row, Column);
+    set => _cellStore.SetValue(row, Column, value);
+  }
+
+  internal bool Next() {
+    return _cellStore.GetNextCell(ref row, ref colPos, minColPos, maxRow, maxColPos);
+  }
+
+  public string CellAddress => ExcelCellBase.GetAddress(Row, Column);
+
+  public IEnumerator<T> GetEnumerator() {
+    Reset();
+    return this;
+  }
+
+  IEnumerator IEnumerable.GetEnumerator() {
+    Reset();
+    return this;
+  }
+
+  public T Current => Value;
+
+  public void Dispose() {}
+
+  object IEnumerator.Current {
+    get {
+      Reset();
+      return this;
+    }
+  }
+
+  public bool MoveNext() {
+    return Next();
+  }
+
+  public void Reset() {
+    Init();
+  }
+}
+
+internal class FlagCellStore : CellStore<byte> {
+  internal void SetFlagValue(int row, int col, bool value, CellFlags cellFlags) {
+    CellFlags currentValue = (CellFlags)GetValue(row, col);
+    if (value) {
+      SetValue(row, col, (byte)(currentValue | cellFlags)); // add the CellFlag bit
+    } else {
+      SetValue(row, col, (byte)(currentValue & ~cellFlags)); // remove the CellFlag bit
+    }
+  }
+
+  internal bool GetFlagValue(int row, int col, CellFlags cellFlags) {
+    return !(((byte)cellFlags & GetValue(row, col)) == 0);
+  }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingAverageGroup.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingAverageGroup.cs
new file mode 100644
index 0000000..af3a6db
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingAverageGroup.cs
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingAverageGroup
+/// </summary>
+public interface IExcelConditionalFormattingAverageGroup : IExcelConditionalFormattingRule {}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingBeginsWith.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingBeginsWith.cs
new file mode 100644
index 0000000..9d81d07
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingBeginsWith.cs
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingBeginsWith
+/// </summary>
+public interface IExcelConditionalFormattingBeginsWith
+    : IExcelConditionalFormattingRule,
+      IExcelConditionalFormattingWithText {}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingBetween.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingBetween.cs
new file mode 100644
index 0000000..acfaf5e
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingBetween.cs
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingBetween
+/// </summary>
+public interface IExcelConditionalFormattingBetween
+    : IExcelConditionalFormattingRule,
+      IExcelConditionalFormattingWithFormula2 {}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingColorScaleGroup.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingColorScaleGroup.cs
new file mode 100644
index 0000000..085cf48
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingColorScaleGroup.cs
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingColorScaleGroup
+/// </summary>
+public interface IExcelConditionalFormattingColorScaleGroup : IExcelConditionalFormattingRule {}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsBlanks.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsBlanks.cs
new file mode 100644
index 0000000..f6e38f2
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsBlanks.cs
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingContainsBlanks
+/// </summary>
+public interface IExcelConditionalFormattingContainsBlanks : IExcelConditionalFormattingRule {}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsErrors.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsErrors.cs
new file mode 100644
index 0000000..58c62fd
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsErrors.cs
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingContainsErrors
+/// </summary>
+public interface IExcelConditionalFormattingContainsErrors : IExcelConditionalFormattingRule {}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsText.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsText.cs
new file mode 100644
index 0000000..1472a81
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsText.cs
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingContainsText
+/// </summary>
+public interface IExcelConditionalFormattingContainsText
+    : IExcelConditionalFormattingRule,
+      IExcelConditionalFormattingWithText {}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingDataBarGroup.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingDataBarGroup.cs
new file mode 100644
index 0000000..f8452d0
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingDataBarGroup.cs
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingDataBar
+/// </summary>
+public interface IExcelConditionalFormattingDataBarGroup : IExcelConditionalFormattingRule {
+  /// <summary>
+  /// ShowValue
+  /// </summary>
+  bool ShowValue { get; set; }
+
+  /// <summary>
+  /// Databar Low Value
+  /// </summary>
+  ExcelConditionalFormattingIconDataBarValue LowValue { get; }
+
+  /// <summary>
+  /// Databar High Value
+  /// </summary>
+  ExcelConditionalFormattingIconDataBarValue HighValue { get; }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingDuplicateValues.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingDuplicateValues.cs
new file mode 100644
index 0000000..518f650
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingDuplicateValues.cs
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingDuplicateValues
+/// </summary>
+public interface IExcelConditionalFormattingDuplicateValues : IExcelConditionalFormattingRule {}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingEndsWith.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingEndsWith.cs
new file mode 100644
index 0000000..37df3d1
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingEndsWith.cs
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingEndsWith
+/// </summary>
+public interface IExcelConditionalFormattingEndsWith
+    : IExcelConditionalFormattingRule,
+      IExcelConditionalFormattingWithText {}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingEqual.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingEqual.cs
new file mode 100644
index 0000000..4859bcc
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingEqual.cs
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingEqual
+/// </summary>
+public interface IExcelConditionalFormattingEqual
+    : IExcelConditionalFormattingRule,
+      IExcelConditionalFormattingWithFormula {}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingExpression.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingExpression.cs
new file mode 100644
index 0000000..3e69ce6
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingExpression.cs
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingExpression
+/// </summary>
+public interface IExcelConditionalFormattingExpression
+    : IExcelConditionalFormattingRule,
+      IExcelConditionalFormattingWithFormula {}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingFiveIconSet.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingFiveIconSet.cs
new file mode 100644
index 0000000..fd4e8cc
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingFiveIconSet.cs
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingFiveIconSet
+/// </summary>eExcelconditionalFormatting4IconsSetType
+public interface IExcelConditionalFormattingFiveIconSet
+    : IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting5IconsSetType> {
+  /// <summary>
+  /// Icon5 (part of the 5 Icon Set)
+  /// </summary>
+  ExcelConditionalFormattingIconDataBarValue Icon5 { get; }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingFourIconSet.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingFourIconSet.cs
new file mode 100644
index 0000000..c0ec540
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingFourIconSet.cs
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingFourIconSet
+/// </summary>
+public interface IExcelConditionalFormattingFourIconSet<T>
+    : IExcelConditionalFormattingThreeIconSet<T> {
+  /// <summary>
+  /// Icon4 (part of the 4 ou 5 Icon Set)
+  /// </summary>
+  ExcelConditionalFormattingIconDataBarValue Icon4 { get; }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingGreaterThan.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingGreaterThan.cs
new file mode 100644
index 0000000..e466a6c
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingGreaterThan.cs
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingGreaterThan
+/// </summary>
+public interface IExcelConditionalFormattingGreaterThan
+    : IExcelConditionalFormattingRule,
+      IExcelConditionalFormattingWithFormula {}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingGreaterThanOrEqual.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingGreaterThanOrEqual.cs
new file mode 100644
index 0000000..f5517df
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingGreaterThanOrEqual.cs
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingGreaterThanOrEqual
+/// </summary>
+public interface IExcelConditionalFormattingGreaterThanOrEqual
+    : IExcelConditionalFormattingRule,
+      IExcelConditionalFormattingWithFormula {}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingIconSetGroup.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingIconSetGroup.cs
new file mode 100644
index 0000000..783f729
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingIconSetGroup.cs
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingIconSetGroup
+/// </summary>
+public interface IExcelConditionalFormattingIconSetGroup<T> : IExcelConditionalFormattingRule {
+  /// <summary>
+  /// Reverse
+  /// </summary>
+  bool Reverse { get; set; }
+
+  /// <summary>
+  /// ShowValue
+  /// </summary>
+  bool ShowValue { get; set; }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingLessThan.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingLessThan.cs
new file mode 100644
index 0000000..2458a89
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingLessThan.cs
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingLessThan
+/// </summary>
+public interface IExcelConditionalFormattingLessThan
+    : IExcelConditionalFormattingRule,
+      IExcelConditionalFormattingWithFormula {}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingLessThanOrEqual.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingLessThanOrEqual.cs
new file mode 100644
index 0000000..8d20da4
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingLessThanOrEqual.cs
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingGreaterThanOrEqual
+/// </summary>
+public interface IExcelConditionalFormattingLessThanOrEqual
+    : IExcelConditionalFormattingRule,
+      IExcelConditionalFormattingWithFormula {}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotBetween.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotBetween.cs
new file mode 100644
index 0000000..496fb6e
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotBetween.cs
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingNotBetween
+/// </summary>
+public interface IExcelConditionalFormattingNotBetween
+    : IExcelConditionalFormattingRule,
+      IExcelConditionalFormattingWithFormula2 {}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsBlanks.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsBlanks.cs
new file mode 100644
index 0000000..1a07b2a
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsBlanks.cs
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingNotContainsBlanks
+/// </summary>
+public interface IExcelConditionalFormattingNotContainsBlanks : IExcelConditionalFormattingRule {}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsErrors.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsErrors.cs
new file mode 100644
index 0000000..a021cd9
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsErrors.cs
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingNotContainsErrors
+/// </summary>
+public interface IExcelConditionalFormattingNotContainsErrors : IExcelConditionalFormattingRule {}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsText.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsText.cs
new file mode 100644
index 0000000..aa7a884
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsText.cs
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingNotContainsText
+/// </summary>
+public interface IExcelConditionalFormattingNotContainsText
+    : IExcelConditionalFormattingRule,
+      IExcelConditionalFormattingWithText {}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotEqual.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotEqual.cs
new file mode 100644
index 0000000..cc62e8b
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotEqual.cs
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingNotEqual
+/// </summary>
+public interface IExcelConditionalFormattingNotEqual
+    : IExcelConditionalFormattingRule,
+      IExcelConditionalFormattingWithFormula {}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingRule.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingRule.cs
new file mode 100644
index 0000000..52c1f33
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingRule.cs
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						              Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting         2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Interface for conditional formatting rule
+/// </summary>
+public interface IExcelConditionalFormattingRule {
+  /// <summary>
+  /// The 'cfRule' XML node
+  /// </summary>
+  XmlNode Node { get; }
+
+  /// <summary>
+  /// Type of conditional formatting rule. ST_CfType §18.18.12.
+  /// </summary>
+  eExcelConditionalFormattingRuleType Type { get; }
+
+  /// <summary>
+  /// <para>Range over which these conditional formatting rules apply.</para>
+  /// <para>The possible values for this attribute are defined by the
+  /// ST_Sqref simple type (§18.18.76).</para>
+  /// </summary>
+  ExcelAddress Address { get; set; }
+
+  /// <summary>
+  /// The priority of this conditional formatting rule. This value is used to determine
+  /// which format should be evaluated and rendered. Lower numeric values are higher
+  /// priority than higher numeric values, where 1 is the highest priority.
+  /// </summary>
+  int Priority { get; set; }
+
+  /// <summary>
+  /// If this flag is 1, no rules with lower priority shall be applied over this rule,
+  /// when this rule evaluates to true.
+  /// </summary>
+  bool StopIfTrue { get; set; }
+
+  ///// <summary>
+  ///// <para>This is an index to a dxf element in the Styles Part indicating which cell
+  ///// formatting to apply when the conditional formatting rule criteria is met.</para>
+  ///// <para>The possible values for this attribute are defined by the ST_DxfId simple type
+  ///// (§18.18.25).</para>
+  ///// </summary>
+  //    int DxfId { get; set; }
+  /// <summary>
+  /// Gives access to the differencial styling (DXF) for the rule.
+  /// </summary>
+  ExcelDxfStyleConditionalFormatting Style { get; }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingStdDevGroup.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingStdDevGroup.cs
new file mode 100644
index 0000000..84c592e
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingStdDevGroup.cs
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingStdDevGroup
+/// </summary>
+public interface IExcelConditionalFormattingStdDevGroup
+    : IExcelConditionalFormattingRule,
+      IExcelConditionalFormattingWithStdDev {}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingThreeColorScale.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingThreeColorScale.cs
new file mode 100644
index 0000000..790f408
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingThreeColorScale.cs
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingThreeColorScale
+/// </summary>
+public interface IExcelConditionalFormattingThreeColorScale
+    : IExcelConditionalFormattingTwoColorScale {
+  /// <summary>
+  /// Three Color Scale Middle Value
+  /// </summary>
+  ExcelConditionalFormattingColorScaleValue MiddleValue { get; set; }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingThreeIconSet.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingThreeIconSet.cs
new file mode 100644
index 0000000..cc37c30
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingThreeIconSet.cs
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingThreeIconSet
+/// </summary>
+public interface IExcelConditionalFormattingThreeIconSet<T>
+    : IExcelConditionalFormattingIconSetGroup<T> {
+  /// <summary>
+  /// Icon1 (part of the 3, 4 ou 5 Icon Set)
+  /// </summary>
+  ExcelConditionalFormattingIconDataBarValue Icon1 { get; }
+
+  /// <summary>
+  /// Icon2 (part of the 3, 4 ou 5 Icon Set)
+  /// </summary>
+  ExcelConditionalFormattingIconDataBarValue Icon2 { get; }
+
+  /// <summary>
+  /// Icon3 (part of the 3, 4 ou 5 Icon Set)
+  /// </summary>
+  ExcelConditionalFormattingIconDataBarValue Icon3 { get; }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTimePeriodGroup.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTimePeriodGroup.cs
new file mode 100644
index 0000000..e60ec34
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTimePeriodGroup.cs
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingTimePeriod
+/// </summary>
+public interface IExcelConditionalFormattingTimePeriodGroup : IExcelConditionalFormattingRule {}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTopBottomGroup.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTopBottomGroup.cs
new file mode 100644
index 0000000..58a7b7e
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTopBottomGroup.cs
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingTopBottomGroup
+/// </summary>
+public interface IExcelConditionalFormattingTopBottomGroup
+    : IExcelConditionalFormattingRule,
+      IExcelConditionalFormattingWithRank {}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTwoColorScale.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTwoColorScale.cs
new file mode 100644
index 0000000..0c0b888
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTwoColorScale.cs
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingTwoColorScale
+/// </summary>
+public interface IExcelConditionalFormattingTwoColorScale
+    : IExcelConditionalFormattingColorScaleGroup {
+  /// <summary>
+  /// Two Color Scale Low Value
+  /// </summary>
+  ExcelConditionalFormattingColorScaleValue LowValue { get; set; }
+
+  /// <summary>
+  /// Two Color Scale High Value
+  /// </summary>
+  ExcelConditionalFormattingColorScaleValue HighValue { get; set; }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingUniqueValues.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingUniqueValues.cs
new file mode 100644
index 0000000..5318d5a
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingUniqueValues.cs
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingUniqueValues
+/// </summary>
+public interface IExcelConditionalFormattingUniqueValues : IExcelConditionalFormattingRule {}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithFormula.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithFormula.cs
new file mode 100644
index 0000000..a834dbf
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithFormula.cs
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingWithFormula
+/// </summary>
+public interface IExcelConditionalFormattingWithFormula {
+  /// <summary>
+  /// Formula Attribute
+  /// </summary>
+  string Formula { get; set; }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithFormula2.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithFormula2.cs
new file mode 100644
index 0000000..da089d3
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithFormula2.cs
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingWithFormula2
+/// </summary>
+public interface IExcelConditionalFormattingWithFormula2 : IExcelConditionalFormattingWithFormula {
+  /// <summary>
+  /// Formula2 Attribute
+  /// </summary>
+  string Formula2 { get; set; }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithRank.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithRank.cs
new file mode 100644
index 0000000..01ca261
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithRank.cs
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+using System;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingWithRank
+/// </summary>
+public interface IExcelConditionalFormattingWithRank {
+  /// <summary>
+  /// Rank Attribute
+  /// </summary>
+  UInt16 Rank { get; set; }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithReverse.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithReverse.cs
new file mode 100644
index 0000000..81f42c0
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithReverse.cs
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingWithReverse
+/// </summary>
+public interface IExcelConditionalFormattingWithReverse {
+  /// <summary>
+  /// Reverse Attribute
+  /// </summary>
+  bool Reverse { get; set; }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithShowValue.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithShowValue.cs
new file mode 100644
index 0000000..0be6a7c
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithShowValue.cs
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingWithShowValue
+/// </summary>
+public interface IExcelConditionalFormattingWithShowValue {
+  /// <summary>
+  /// ShowValue Attribute
+  /// </summary>
+  bool ShowValue { get; set; }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithStdDev.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithStdDev.cs
new file mode 100644
index 0000000..cd9bc01
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithStdDev.cs
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+using System;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingWithStdDev
+/// </summary>
+public interface IExcelConditionalFormattingWithStdDev {
+  /// <summary>
+  /// StdDev Attribute
+  /// </summary>
+  UInt16 StdDev { get; set; }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithText.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithText.cs
new file mode 100644
index 0000000..b64e9a4
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithText.cs
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// IExcelConditionalFormattingWithText
+/// </summary>
+public interface IExcelConditionalFormattingWithText {
+  /// <summary>
+  /// Text Attribute
+  /// </summary>
+  string Text { get; set; }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Contracts/IRangeConditionalFormatting.cs b/AppsheetEpplus/ConditionalFormatting/Contracts/IRangeConditionalFormatting.cs
new file mode 100644
index 0000000..02ee298
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Contracts/IRangeConditionalFormatting.cs
@@ -0,0 +1,285 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author             Change                    Date
+ * ******************************************************************************
+ * Eyal Seagull		    Conditional Formatting    2012-04-03
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Provides functionality for adding Conditional Formatting to a range (<see cref="ExcelRangeBase"/>).
+/// Each method will return a configurable condtional formatting type.
+/// </summary>
+public interface IRangeConditionalFormatting {
+  /// <summary>
+  /// Adds a Above Average rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingAverageGroup AddAboveAverage();
+
+  /// <summary>
+  /// Adds a Above Or Equal Average rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingAverageGroup AddAboveOrEqualAverage();
+
+  /// <summary>
+  /// Adds a Below Average rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingAverageGroup AddBelowAverage();
+
+  /// <summary>
+  /// Adds a Below Or Equal Average rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingAverageGroup AddBelowOrEqualAverage();
+
+  /// <summary>
+  /// Adds a Above StdDev rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingStdDevGroup AddAboveStdDev();
+
+  /// <summary>
+  /// Adds a Below StdDev rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingStdDevGroup AddBelowStdDev();
+
+  /// <summary>
+  /// Adds a Bottom rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingTopBottomGroup AddBottom();
+
+  /// <summary>
+  /// Adds a Bottom Percent rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingTopBottomGroup AddBottomPercent();
+
+  /// <summary>
+  /// Adds a Top rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingTopBottomGroup AddTop();
+
+  /// <summary>
+  /// Adds a Top Percent rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingTopBottomGroup AddTopPercent();
+
+  /// <summary>
+  /// Adds a Last 7 Days rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingTimePeriodGroup AddLast7Days();
+
+  /// <summary>
+  /// Adds a Last Month rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingTimePeriodGroup AddLastMonth();
+
+  /// <summary>
+  /// Adds a Last Week rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingTimePeriodGroup AddLastWeek();
+
+  /// <summary>
+  /// Adds a Next Month rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingTimePeriodGroup AddNextMonth();
+
+  /// <summary>
+  /// Adds a Next Week rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingTimePeriodGroup AddNextWeek();
+
+  /// <summary>
+  /// Adds a This Month rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingTimePeriodGroup AddThisMonth();
+
+  /// <summary>
+  /// Adds a This Week rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingTimePeriodGroup AddThisWeek();
+
+  /// <summary>
+  /// Adds a Today rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingTimePeriodGroup AddToday();
+
+  /// <summary>
+  /// Adds a Tomorrow rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingTimePeriodGroup AddTomorrow();
+
+  /// <summary>
+  /// Adds a Yesterday rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingTimePeriodGroup AddYesterday();
+
+  /// <summary>
+  /// Adds a Begins With rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingBeginsWith AddBeginsWith();
+
+  /// <summary>
+  /// Adds a Between rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingBetween AddBetween();
+
+  /// <summary>
+  /// Adds a ContainsBlanks rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingContainsBlanks AddContainsBlanks();
+
+  /// <summary>
+  /// Adds a ContainsErrors rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingContainsErrors AddContainsErrors();
+
+  /// <summary>
+  /// Adds a ContainsText rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingContainsText AddContainsText();
+
+  /// <summary>
+  /// Adds a DuplicateValues rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingDuplicateValues AddDuplicateValues();
+
+  /// <summary>
+  /// Adds a EndsWith rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingEndsWith AddEndsWith();
+
+  /// <summary>
+  /// Adds a Equal rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingEqual AddEqual();
+
+  /// <summary>
+  /// Adds a Expression rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingExpression AddExpression();
+
+  /// <summary>
+  /// Adds a GreaterThan rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingGreaterThan AddGreaterThan();
+
+  /// <summary>
+  /// Adds a GreaterThanOrEqual rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingGreaterThanOrEqual AddGreaterThanOrEqual();
+
+  /// <summary>
+  /// Adds a LessThan rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingLessThan AddLessThan();
+
+  /// <summary>
+  /// Adds a LessThanOrEqual rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingLessThanOrEqual AddLessThanOrEqual();
+
+  /// <summary>
+  /// Adds a NotBetween rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingNotBetween AddNotBetween();
+
+  /// <summary>
+  /// Adds a NotContainsBlanks rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingNotContainsBlanks AddNotContainsBlanks();
+
+  /// <summary>
+  /// Adds a NotContainsErrors rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingNotContainsErrors AddNotContainsErrors();
+
+  /// <summary>
+  /// Adds a NotContainsText rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingNotContainsText AddNotContainsText();
+
+  /// <summary>
+  /// Adds a NotEqual rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingNotEqual AddNotEqual();
+
+  /// <summary>
+  /// Adds a UniqueValues rule to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingUniqueValues AddUniqueValues();
+
+  /// <summary>
+  /// Adds a <see cref="ExcelConditionalFormattingThreeColorScale"/> to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingThreeColorScale AddThreeColorScale();
+
+  /// <summary>
+  /// Adds a <see cref="ExcelConditionalFormattingTwoColorScale"/> to the range
+  /// </summary>
+  /// <returns></returns>
+  IExcelConditionalFormattingTwoColorScale AddTwoColorScale();
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingCollection.cs b/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingCollection.cs
new file mode 100644
index 0000000..fb6ad7c
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingCollection.cs
@@ -0,0 +1,770 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author					Change						                Date
+ * ******************************************************************************
+ * Eyal Seagull		Conditional Formatting            2012-04-03
+ *******************************************************************************/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Collection of <see cref="ExcelConditionalFormattingRule"/>.
+/// This class is providing the API for EPPlus conditional formatting.
+/// </summary>
+/// <remarks>
+/// <para>
+/// The public methods of this class (Add[...]ConditionalFormatting) will create a ConditionalFormatting/CfRule entry in the worksheet. When this
+/// Conditional Formatting has been created changes to the properties will affect the workbook immediately.
+/// </para>
+/// <para>
+/// Each type of Conditional Formatting Rule has diferente set of properties.
+/// </para>
+/// <code>
+/// // Add a Three Color Scale conditional formatting
+/// var cf = worksheet.ConditionalFormatting.AddThreeColorScale(new ExcelAddress("A1:C10"));
+/// // Set the conditional formatting properties
+/// cf.LowValue.Type = ExcelConditionalFormattingValueObjectType.Min;
+/// cf.LowValue.Color = Color.White;
+/// cf.MiddleValue.Type = ExcelConditionalFormattingValueObjectType.Percent;
+/// cf.MiddleValue.Value = 50;
+/// cf.MiddleValue.Color = Color.Blue;
+/// cf.HighValue.Type = ExcelConditionalFormattingValueObjectType.Max;
+/// cf.HighValue.Color = Color.Black;
+/// </code>
+/// </remarks>
+public class ExcelConditionalFormattingCollection
+    : XmlHelper,
+      IEnumerable<IExcelConditionalFormattingRule> {
+  private readonly List<IExcelConditionalFormattingRule> _rules = new();
+  private readonly ExcelWorksheet _worksheet;
+
+  protected override ImmutableArray<string> SchemaNodeOrder =>
+    ExcelWorksheet.WorksheetSchemaNodeOrder;
+
+  /// <summary>
+  /// Initialize the <see cref="ExcelConditionalFormattingCollection"/>
+  /// </summary>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingCollection(ExcelWorksheet worksheet)
+      : base(worksheet.NameSpaceManager, worksheet.WorksheetXml.DocumentElement) {
+    ArgumentNullException.ThrowIfNull(worksheet);
+
+    _worksheet = worksheet;
+
+    // Look for all the <conditionalFormatting>
+    var conditionalFormattingNodes = TopNode.SelectNodes(
+        "//" + ExcelConditionalFormattingConstants.Paths._conditionalFormatting,
+        _worksheet.NameSpaceManager);
+
+    // Check if we found at least 1 node
+    if ((conditionalFormattingNodes != null) && (conditionalFormattingNodes.Count > 0)) {
+      // Foreach <conditionalFormatting>
+      foreach (XmlNode conditionalFormattingNode in conditionalFormattingNodes) {
+        // Check if @sqref attribute exists
+        if (conditionalFormattingNode.Attributes[ExcelConditionalFormattingConstants
+                  .Attributes
+                  ._sqref] == null) {
+          throw new(ExcelConditionalFormattingConstants.Errors._missingSqrefAttribute);
+        }
+
+        // Get the @sqref attribute
+        ExcelAddress address = new ExcelAddress(
+            conditionalFormattingNode.Attributes[ExcelConditionalFormattingConstants
+                  .Attributes
+                  ._sqref].Value);
+
+        // Check for all the <cfRules> nodes and load them
+        var cfRuleNodes = conditionalFormattingNode.SelectNodes(
+            ExcelConditionalFormattingConstants.Paths._cfRule,
+            _worksheet.NameSpaceManager);
+
+        // Foreach <cfRule> inside the current <conditionalFormatting>
+        foreach (XmlNode cfRuleNode in cfRuleNodes) {
+          // Check if @type attribute exists
+          if (cfRuleNode.Attributes[ExcelConditionalFormattingConstants.Attributes._type] == null) {
+            throw new(ExcelConditionalFormattingConstants.Errors._missingTypeAttribute);
+          }
+
+          // Check if @priority attribute exists
+          if (cfRuleNode.Attributes[ExcelConditionalFormattingConstants.Attributes._priority]
+              == null) {
+            throw new(ExcelConditionalFormattingConstants.Errors._missingPriorityAttribute);
+          }
+
+          // Get the <cfRule> main attributes
+          string typeAttribute = ExcelConditionalFormattingHelper.GetAttributeString(
+              cfRuleNode,
+              ExcelConditionalFormattingConstants.Attributes._type);
+
+          int priority = ExcelConditionalFormattingHelper.GetAttributeInt(
+              cfRuleNode,
+              ExcelConditionalFormattingConstants.Attributes._priority);
+
+          // Transform the @type attribute to EPPlus Rule Type (slighty diferente)
+          var type = ExcelConditionalFormattingRuleType.GetTypeByAttrbiute(
+              typeAttribute,
+              cfRuleNode,
+              _worksheet.NameSpaceManager);
+
+          // Create the Rule according to the correct type, address and priority
+          var cfRule = ExcelConditionalFormattingRuleFactory.Create(
+              type,
+              address,
+              priority,
+              _worksheet,
+              cfRuleNode);
+
+          // Add the new rule to the list
+          if (cfRule != null) {
+            _rules.Add(cfRule);
+          }
+        }
+      }
+    }
+  }
+
+  private void EnsureRootElementExists() {
+    // Find the <worksheet> node
+    if (_worksheet.WorksheetXml.DocumentElement == null) {
+      throw new(ExcelConditionalFormattingConstants.Errors._missingWorksheetNode);
+    }
+  }
+
+  /// <summary>
+  /// Validates address - not empty (collisions are allowded)
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  private ExcelAddress ValidateAddress(ExcelAddress address) {
+    ArgumentNullException.ThrowIfNull(address);
+
+    //TODO: Are there any other validation we need to do?
+    return address;
+  }
+
+  /// <summary>
+  /// Get the next priority sequencial number
+  /// </summary>
+  /// <returns></returns>
+  private int GetNextPriority() {
+    // Consider zero as the last priority when we have no CF rules
+    int lastPriority = 0;
+
+    // Search for the last priority
+    foreach (var cfRule in _rules) {
+      if (cfRule.Priority > lastPriority) {
+        lastPriority = cfRule.Priority;
+      }
+    }
+
+    // Our next priority is the last plus one
+    return lastPriority + 1;
+  }
+
+  /// <summary>
+  /// Number of validations
+  /// </summary>
+  public int Count => _rules.Count;
+
+  /// <summary>
+  /// Index operator, returns by 0-based index
+  /// </summary>
+  /// <param name="index"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingRule this[int index] {
+    get => _rules[index];
+    set => _rules[index] = value;
+  }
+
+  /// <summary>
+  /// Get the 'cfRule' enumerator
+  /// </summary>
+  /// <returns></returns>
+  IEnumerator<IExcelConditionalFormattingRule> IEnumerable<IExcelConditionalFormattingRule>.GetEnumerator() {
+    return _rules.GetEnumerator();
+  }
+
+  /// <summary>
+  /// Get the 'cfRule' enumerator
+  /// </summary>
+  /// <returns></returns>
+  IEnumerator IEnumerable.GetEnumerator() {
+    return _rules.GetEnumerator();
+  }
+
+  /// <summary>
+  /// Removes all 'cfRule' from the collection and from the XML.
+  /// <remarks>
+  /// This is the same as removing all the 'conditionalFormatting' nodes.
+  /// </remarks>
+  /// </summary>
+  public void RemoveAll() {
+    // Look for all the <conditionalFormatting> nodes
+    var conditionalFormattingNodes = TopNode.SelectNodes(
+        "//" + ExcelConditionalFormattingConstants.Paths._conditionalFormatting,
+        _worksheet.NameSpaceManager);
+
+    // Remove all the <conditionalFormatting> nodes one by one
+    foreach (XmlNode conditionalFormattingNode in conditionalFormattingNodes) {
+      conditionalFormattingNode.ParentNode.RemoveChild(conditionalFormattingNode);
+    }
+
+    // Clear the <cfRule> item list
+    _rules.Clear();
+  }
+
+  /// <summary>
+  /// Remove a Conditional Formatting Rule by its object
+  /// </summary>
+  /// <param name="item"></param>
+  public void Remove(IExcelConditionalFormattingRule item) {
+    ArgumentNullException.ThrowIfNull(item);
+
+    try {
+      // Point to the parent node
+      var oldParentNode = item.Node.ParentNode;
+
+      // Remove the <cfRule> from the old <conditionalFormatting> parent node
+      oldParentNode.RemoveChild(item.Node);
+
+      // Check if the old <conditionalFormatting> parent node has <cfRule> node inside it
+      if (!oldParentNode.HasChildNodes) {
+        // Remove the old parent node
+        oldParentNode.ParentNode.RemoveChild(oldParentNode);
+      }
+
+      _rules.Remove(item);
+    } catch {
+      throw new(ExcelConditionalFormattingConstants.Errors._invalidRemoveRuleOperation);
+    }
+  }
+
+  /// <summary>
+  /// Remove a Conditional Formatting Rule by its priority
+  /// </summary>
+  /// <param name="priority"></param>
+  public void RemoveByPriority(int priority) {
+    try {
+      Remove(RulesByPriority(priority));
+    } catch {}
+  }
+
+  /// <summary>
+  /// Get a rule by its priority
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingRule RulesByPriority(int priority) {
+    return _rules.Find(x => x.Priority == priority);
+  }
+
+  /// <summary>
+  /// Add rule (internal)
+  /// </summary>
+  /// <param name="type"></param>
+  /// <param name="address"></param>
+  /// <returns></returns>F
+  internal IExcelConditionalFormattingRule AddRule(
+      eExcelConditionalFormattingRuleType type,
+      ExcelAddress address) {
+    ArgumentNullException.ThrowIfNull(address);
+
+    address = ValidateAddress(address);
+    EnsureRootElementExists();
+
+    // Create the Rule according to the correct type, address and priority
+    IExcelConditionalFormattingRule cfRule = ExcelConditionalFormattingRuleFactory.Create(
+        type,
+        address,
+        GetNextPriority(),
+        _worksheet,
+        null);
+
+    // Add the newly created rule to the list
+    _rules.Add(cfRule);
+
+    // Return the newly created rule
+    return cfRule;
+  }
+
+  /// <summary>
+  /// Add AboveAverage Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingAverageGroup AddAboveAverage(ExcelAddress address) {
+    return (IExcelConditionalFormattingAverageGroup)AddRule(
+        eExcelConditionalFormattingRuleType.AboveAverage,
+        address);
+  }
+
+  /// <summary>
+  /// Add AboveOrEqualAverage Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingAverageGroup AddAboveOrEqualAverage(ExcelAddress address) {
+    return (IExcelConditionalFormattingAverageGroup)AddRule(
+        eExcelConditionalFormattingRuleType.AboveOrEqualAverage,
+        address);
+  }
+
+  /// <summary>
+  /// Add BelowAverage Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingAverageGroup AddBelowAverage(ExcelAddress address) {
+    return (IExcelConditionalFormattingAverageGroup)AddRule(
+        eExcelConditionalFormattingRuleType.BelowAverage,
+        address);
+  }
+
+  /// <summary>
+  /// Add BelowOrEqualAverage Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingAverageGroup AddBelowOrEqualAverage(ExcelAddress address) {
+    return (IExcelConditionalFormattingAverageGroup)AddRule(
+        eExcelConditionalFormattingRuleType.BelowOrEqualAverage,
+        address);
+  }
+
+  /// <summary>
+  /// Add AboveStdDev Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingStdDevGroup AddAboveStdDev(ExcelAddress address) {
+    return (IExcelConditionalFormattingStdDevGroup)AddRule(
+        eExcelConditionalFormattingRuleType.AboveStdDev,
+        address);
+  }
+
+  /// <summary>
+  /// Add BelowStdDev Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingStdDevGroup AddBelowStdDev(ExcelAddress address) {
+    return (IExcelConditionalFormattingStdDevGroup)AddRule(
+        eExcelConditionalFormattingRuleType.BelowStdDev,
+        address);
+  }
+
+  /// <summary>
+  /// Add Bottom Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingTopBottomGroup AddBottom(ExcelAddress address) {
+    return (IExcelConditionalFormattingTopBottomGroup)AddRule(
+        eExcelConditionalFormattingRuleType.Bottom,
+        address);
+  }
+
+  /// <summary>
+  /// Add BottomPercent Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingTopBottomGroup AddBottomPercent(ExcelAddress address) {
+    return (IExcelConditionalFormattingTopBottomGroup)AddRule(
+        eExcelConditionalFormattingRuleType.BottomPercent,
+        address);
+  }
+
+  /// <summary>
+  /// Add Top Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingTopBottomGroup AddTop(ExcelAddress address) {
+    return (IExcelConditionalFormattingTopBottomGroup)AddRule(
+        eExcelConditionalFormattingRuleType.Top,
+        address);
+  }
+
+  /// <summary>
+  /// Add TopPercent Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingTopBottomGroup AddTopPercent(ExcelAddress address) {
+    return (IExcelConditionalFormattingTopBottomGroup)AddRule(
+        eExcelConditionalFormattingRuleType.TopPercent,
+        address);
+  }
+
+  /// <summary>
+  /// Add Last7Days Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingTimePeriodGroup AddLast7Days(ExcelAddress address) {
+    return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
+        eExcelConditionalFormattingRuleType.Last7Days,
+        address);
+  }
+
+  /// <summary>
+  /// Add LastMonth Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingTimePeriodGroup AddLastMonth(ExcelAddress address) {
+    return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
+        eExcelConditionalFormattingRuleType.LastMonth,
+        address);
+  }
+
+  /// <summary>
+  /// Add LastWeek Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingTimePeriodGroup AddLastWeek(ExcelAddress address) {
+    return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
+        eExcelConditionalFormattingRuleType.LastWeek,
+        address);
+  }
+
+  /// <summary>
+  /// Add NextMonth Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingTimePeriodGroup AddNextMonth(ExcelAddress address) {
+    return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
+        eExcelConditionalFormattingRuleType.NextMonth,
+        address);
+  }
+
+  /// <summary>
+  /// Add NextWeek Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingTimePeriodGroup AddNextWeek(ExcelAddress address) {
+    return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
+        eExcelConditionalFormattingRuleType.NextWeek,
+        address);
+  }
+
+  /// <summary>
+  /// Add ThisMonth Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingTimePeriodGroup AddThisMonth(ExcelAddress address) {
+    return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
+        eExcelConditionalFormattingRuleType.ThisMonth,
+        address);
+  }
+
+  /// <summary>
+  /// Add ThisWeek Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingTimePeriodGroup AddThisWeek(ExcelAddress address) {
+    return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
+        eExcelConditionalFormattingRuleType.ThisWeek,
+        address);
+  }
+
+  /// <summary>
+  /// Add Today Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingTimePeriodGroup AddToday(ExcelAddress address) {
+    return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
+        eExcelConditionalFormattingRuleType.Today,
+        address);
+  }
+
+  /// <summary>
+  /// Add Tomorrow Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingTimePeriodGroup AddTomorrow(ExcelAddress address) {
+    return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
+        eExcelConditionalFormattingRuleType.Tomorrow,
+        address);
+  }
+
+  /// <summary>
+  /// Add Yesterday Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingTimePeriodGroup AddYesterday(ExcelAddress address) {
+    return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
+        eExcelConditionalFormattingRuleType.Yesterday,
+        address);
+  }
+
+  /// <summary>
+  /// Add BeginsWith Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingBeginsWith AddBeginsWith(ExcelAddress address) {
+    return (IExcelConditionalFormattingBeginsWith)AddRule(
+        eExcelConditionalFormattingRuleType.BeginsWith,
+        address);
+  }
+
+  /// <summary>
+  /// Add Between Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingBetween AddBetween(ExcelAddress address) {
+    return (IExcelConditionalFormattingBetween)AddRule(
+        eExcelConditionalFormattingRuleType.Between,
+        address);
+  }
+
+  /// <summary>
+  /// Add ContainsBlanks Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingContainsBlanks AddContainsBlanks(ExcelAddress address) {
+    return (IExcelConditionalFormattingContainsBlanks)AddRule(
+        eExcelConditionalFormattingRuleType.ContainsBlanks,
+        address);
+  }
+
+  /// <summary>
+  /// Add ContainsErrors Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingContainsErrors AddContainsErrors(ExcelAddress address) {
+    return (IExcelConditionalFormattingContainsErrors)AddRule(
+        eExcelConditionalFormattingRuleType.ContainsErrors,
+        address);
+  }
+
+  /// <summary>
+  /// Add ContainsText Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingContainsText AddContainsText(ExcelAddress address) {
+    return (IExcelConditionalFormattingContainsText)AddRule(
+        eExcelConditionalFormattingRuleType.ContainsText,
+        address);
+  }
+
+  /// <summary>
+  /// Add DuplicateValues Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingDuplicateValues AddDuplicateValues(ExcelAddress address) {
+    return (IExcelConditionalFormattingDuplicateValues)AddRule(
+        eExcelConditionalFormattingRuleType.DuplicateValues,
+        address);
+  }
+
+  /// <summary>
+  /// Add EndsWith Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingEndsWith AddEndsWith(ExcelAddress address) {
+    return (IExcelConditionalFormattingEndsWith)AddRule(
+        eExcelConditionalFormattingRuleType.EndsWith,
+        address);
+  }
+
+  /// <summary>
+  /// Add Equal Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingEqual AddEqual(ExcelAddress address) {
+    return (IExcelConditionalFormattingEqual)AddRule(
+        eExcelConditionalFormattingRuleType.Equal,
+        address);
+  }
+
+  /// <summary>
+  /// Add Expression Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingExpression AddExpression(ExcelAddress address) {
+    return (IExcelConditionalFormattingExpression)AddRule(
+        eExcelConditionalFormattingRuleType.Expression,
+        address);
+  }
+
+  /// <summary>
+  /// Add GreaterThan Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingGreaterThan AddGreaterThan(ExcelAddress address) {
+    return (IExcelConditionalFormattingGreaterThan)AddRule(
+        eExcelConditionalFormattingRuleType.GreaterThan,
+        address);
+  }
+
+  /// <summary>
+  /// Add GreaterThanOrEqual Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingGreaterThanOrEqual AddGreaterThanOrEqual(ExcelAddress address) {
+    return (IExcelConditionalFormattingGreaterThanOrEqual)AddRule(
+        eExcelConditionalFormattingRuleType.GreaterThanOrEqual,
+        address);
+  }
+
+  /// <summary>
+  /// Add LessThan Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingLessThan AddLessThan(ExcelAddress address) {
+    return (IExcelConditionalFormattingLessThan)AddRule(
+        eExcelConditionalFormattingRuleType.LessThan,
+        address);
+  }
+
+  /// <summary>
+  /// Add LessThanOrEqual Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingLessThanOrEqual AddLessThanOrEqual(ExcelAddress address) {
+    return (IExcelConditionalFormattingLessThanOrEqual)AddRule(
+        eExcelConditionalFormattingRuleType.LessThanOrEqual,
+        address);
+  }
+
+  /// <summary>
+  /// Add NotBetween Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingNotBetween AddNotBetween(ExcelAddress address) {
+    return (IExcelConditionalFormattingNotBetween)AddRule(
+        eExcelConditionalFormattingRuleType.NotBetween,
+        address);
+  }
+
+  /// <summary>
+  /// Add NotContainsBlanks Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingNotContainsBlanks AddNotContainsBlanks(ExcelAddress address) {
+    return (IExcelConditionalFormattingNotContainsBlanks)AddRule(
+        eExcelConditionalFormattingRuleType.NotContainsBlanks,
+        address);
+  }
+
+  /// <summary>
+  /// Add NotContainsErrors Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingNotContainsErrors AddNotContainsErrors(ExcelAddress address) {
+    return (IExcelConditionalFormattingNotContainsErrors)AddRule(
+        eExcelConditionalFormattingRuleType.NotContainsErrors,
+        address);
+  }
+
+  /// <summary>
+  /// Add NotContainsText Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingNotContainsText AddNotContainsText(ExcelAddress address) {
+    return (IExcelConditionalFormattingNotContainsText)AddRule(
+        eExcelConditionalFormattingRuleType.NotContainsText,
+        address);
+  }
+
+  /// <summary>
+  /// Add NotEqual Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingNotEqual AddNotEqual(ExcelAddress address) {
+    return (IExcelConditionalFormattingNotEqual)AddRule(
+        eExcelConditionalFormattingRuleType.NotEqual,
+        address);
+  }
+
+  /// <summary>
+  /// Add Unique Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingUniqueValues AddUniqueValues(ExcelAddress address) {
+    return (IExcelConditionalFormattingUniqueValues)AddRule(
+        eExcelConditionalFormattingRuleType.UniqueValues,
+        address);
+  }
+
+  /// <summary>
+  /// Add ThreeColorScale Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingThreeColorScale AddThreeColorScale(ExcelAddress address) {
+    return (IExcelConditionalFormattingThreeColorScale)AddRule(
+        eExcelConditionalFormattingRuleType.ThreeColorScale,
+        address);
+  }
+
+  /// <summary>
+  /// Add TwoColorScale Rule
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public IExcelConditionalFormattingTwoColorScale AddTwoColorScale(ExcelAddress address) {
+    return (IExcelConditionalFormattingTwoColorScale)AddRule(
+        eExcelConditionalFormattingRuleType.TwoColorScale,
+        address);
+  }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingColorScaleValue.cs b/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingColorScaleValue.cs
new file mode 100644
index 0000000..c1155b9
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingColorScaleValue.cs
@@ -0,0 +1,407 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System;
+using System.Collections.Immutable;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// 18.3.1.11 cfvo (Conditional Format Value Object)
+/// Describes the values of the interpolation points in a gradient scale.
+/// </summary>
+public class ExcelConditionalFormattingColorScaleValue : XmlHelper {
+  private eExcelConditionalFormattingValueObjectPosition _position;
+  private eExcelConditionalFormattingRuleType _ruleType;
+  private readonly ExcelWorksheet _worksheet;
+
+  protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
+    ExcelConditionalFormattingConstants.Nodes._cfvo,
+    ExcelConditionalFormattingConstants.Nodes._color,
+  ];
+
+  /// <summary>
+  /// Initialize the cfvo (§18.3.1.11) node
+  /// </summary>
+  /// <param name="position"></param>
+  /// <param name="type"></param>
+  /// <param name="color"></param>
+  /// <param name="value"></param>
+  /// <param name="formula"></param>
+  /// <param name="ruleType"></param>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode">The cfvo (§18.3.1.11) node parent. Can be any of the following:
+  /// colorScale (§18.3.1.16); dataBar (§18.3.1.28); iconSet (§18.3.1.49)</param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingColorScaleValue(
+      eExcelConditionalFormattingValueObjectPosition position,
+      eExcelConditionalFormattingValueObjectType type,
+      double value,
+      string formula,
+      eExcelConditionalFormattingRuleType ruleType,
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(namespaceManager, itemElementNode) {
+    ArgumentOutOfRangeException.ThrowIfLessThan(priority, 1);
+    ArgumentNullException.ThrowIfNull(address);
+    ArgumentNullException.ThrowIfNull(worksheet);
+
+    // Save the worksheet for private methods to use
+    _worksheet = worksheet;
+
+    // Check if the parent does not exists
+    if (itemElementNode == null) {
+      // Get the parent node path by the rule type
+      string parentNodePath = ExcelConditionalFormattingValueObjectType.GetParentPathByRuleType(
+          ruleType);
+
+      // Check for en error (rule type does not have <cfvo>)
+      if (parentNodePath == string.Empty) {
+        throw new(ExcelConditionalFormattingConstants.Errors._missingCfvoParentNode);
+      }
+
+      // Point to the <cfvo> parent node
+      itemElementNode = _worksheet.WorksheetXml.SelectSingleNode(
+          string.Format(
+              "//{0}[{1}='{2}']/{3}[{4}='{5}']/{6}",
+              // {0}
+              ExcelConditionalFormattingConstants.Paths._conditionalFormatting,
+              // {1}
+              ExcelConditionalFormattingConstants.Paths._sqrefAttribute,
+              // {2}
+              address.Address,
+              // {3}
+              ExcelConditionalFormattingConstants.Paths._cfRule,
+              // {4}
+              ExcelConditionalFormattingConstants.Paths._priorityAttribute,
+              // {5}
+              priority,
+              // {6}
+              parentNodePath),
+          _worksheet.NameSpaceManager);
+
+      // Check for en error (rule type does not have <cfvo>)
+      if (itemElementNode == null) {
+        throw new(ExcelConditionalFormattingConstants.Errors._missingCfvoParentNode);
+      }
+    }
+
+    // Point to the <cfvo> parent node (<colorScale>, <dataBar> or <iconSet>)
+    // This is different than normal, as TopNode does not point to the node itself but to
+    // its PARENT. Later, in the CreateNodeByOrdem method the TopNode will be updated.
+    TopNode = itemElementNode;
+
+    // Save the attributes
+    Position = position;
+    RuleType = ruleType;
+    Type = type;
+    Value = value;
+    Formula = formula;
+  }
+
+  /// <summary>
+  /// Initialize the <see cref="ExcelConditionalFormattingColorScaleValue"/>
+  /// </summary>
+  /// <param name="position"></param>
+  /// <param name="type"></param>
+  /// <param name="color"></param>
+  /// <param name="value"></param>
+  /// <param name="formula"></param>
+  /// <param name="ruleType"></param>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingColorScaleValue(
+      eExcelConditionalFormattingValueObjectPosition position,
+      eExcelConditionalFormattingValueObjectType type,
+      double value,
+      string formula,
+      eExcelConditionalFormattingRuleType ruleType,
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNamespaceManager namespaceManager)
+      : this(
+          position,
+          type,
+          value,
+          formula,
+          ruleType,
+          address,
+          priority,
+          worksheet,
+          null,
+          namespaceManager) {}
+
+  /// <summary>
+  /// Initialize the <see cref="ExcelConditionalFormattingColorScaleValue"/>
+  /// </summary>
+  /// <param name="position"></param>
+  /// <param name="type"></param>
+  /// <param name="color"></param>
+  /// <param name="ruleType"></param>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingColorScaleValue(
+      eExcelConditionalFormattingValueObjectPosition position,
+      eExcelConditionalFormattingValueObjectType type,
+      eExcelConditionalFormattingRuleType ruleType,
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNamespaceManager namespaceManager)
+      : this(
+          position,
+          type,
+          0,
+          null,
+          ruleType,
+          address,
+          priority,
+          worksheet,
+          null,
+          namespaceManager) {}
+
+  /// <summary>
+  /// Get the node order (1, 2 ou 3) according to the Position (Low, Middle and High)
+  /// and the Rule Type (TwoColorScale ou ThreeColorScale).
+  /// </summary>
+  /// <returns></returns>
+  private int GetNodeOrder() {
+    return ExcelConditionalFormattingValueObjectType.GetOrderByPosition(Position, RuleType);
+  }
+
+  /// <summary>
+  /// Create the 'cfvo'/'color' nodes in the right order. They should appear like this:
+  ///		"cfvo"   --> Low Value (value object)
+  ///		"cfvo"   --> Middle Value (value object)
+  ///		"cfvo"   --> High Value (value object)
+  ///		"color"  --> Low Value (color)
+  ///		"color"  --> Middle Value (color)
+  ///		"color"  --> High Value (color)
+  /// </summary>
+  /// <param name="nodeType"></param>
+  /// <param name="attributePath"></param>
+  /// <param name="attributeValue"></param>
+  private void CreateNodeByOrdem(
+      eExcelConditionalFormattingValueObjectNodeType nodeType,
+      string attributePath,
+      string attributeValue) {
+    // Save the current TopNode
+    XmlNode currentTopNode = TopNode;
+
+    string nodePath = ExcelConditionalFormattingValueObjectType.GetNodePathByNodeType(nodeType);
+    int nodeOrder = GetNodeOrder();
+    eNodeInsertOrder nodeInsertOrder = eNodeInsertOrder.SchemaOrder;
+    XmlNode referenceNode = null;
+
+    if (nodeOrder > 1) {
+      // Find the node just before the one we need to include
+      referenceNode = TopNode.SelectSingleNode(
+          string.Format(
+              "{0}[position()={1}]",
+              // {0}
+              nodePath,
+              // {1}
+              nodeOrder - 1),
+          _worksheet.NameSpaceManager);
+
+      // Only if the prepend node exists than insert after
+      if (referenceNode != null) {
+        nodeInsertOrder = eNodeInsertOrder.After;
+      }
+    }
+
+    // Create the node in the right order
+    var node = CreateComplexNode(
+        TopNode,
+        string.Format(
+            "{0}[position()={1}]",
+            // {0}
+            nodePath,
+            // {1}
+            nodeOrder),
+        nodeInsertOrder,
+        referenceNode);
+
+    // Point to the new node as the temporary TopNode (we need it for the XmlHelper functions)
+    TopNode = node;
+
+    // Add/Remove the attribute (if the attributeValue is empty then it will be removed)
+    SetXmlNodeString(node, attributePath, attributeValue, true);
+
+    // Point back to the <cfvo>/<color> parent node
+    TopNode = currentTopNode;
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  internal eExcelConditionalFormattingValueObjectPosition Position {
+    get => _position;
+    set => _position = value;
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  internal eExcelConditionalFormattingRuleType RuleType {
+    get => _ruleType;
+    set => _ruleType = value;
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  public eExcelConditionalFormattingValueObjectType Type {
+    get {
+      var typeAttribute = GetXmlNodeString(
+          string.Format(
+              "{0}[position()={1}]/{2}",
+              // {0}
+              ExcelConditionalFormattingConstants.Paths._cfvo,
+              // {1}
+              GetNodeOrder(),
+              // {2}
+              ExcelConditionalFormattingConstants.Paths._typeAttribute));
+
+      return ExcelConditionalFormattingValueObjectType.GetTypeByAttrbiute(typeAttribute);
+    }
+    set {
+      CreateNodeByOrdem(
+          eExcelConditionalFormattingValueObjectNodeType.Cfvo,
+          ExcelConditionalFormattingConstants.Paths._typeAttribute,
+          ExcelConditionalFormattingValueObjectType.GetAttributeByType(value));
+
+      bool removeValAttribute = false;
+
+      // Make sure unnecessary attributes are removed (occures when we change
+      // the value object type)
+      switch (Type) {
+        case eExcelConditionalFormattingValueObjectType.Min:
+        case eExcelConditionalFormattingValueObjectType.Max:
+          removeValAttribute = true;
+          break;
+      }
+
+      // Check if we need to remove the @val attribute
+      if (removeValAttribute) {
+        string nodePath = ExcelConditionalFormattingValueObjectType.GetNodePathByNodeType(
+            eExcelConditionalFormattingValueObjectNodeType.Cfvo);
+        int nodeOrder = GetNodeOrder();
+
+        // Remove the attribute (removed when the value = '')
+        CreateComplexNode(
+            TopNode,
+            string.Format(
+                "{0}[position()={1}]/{2}=''",
+                // {0}
+                nodePath,
+                // {1}
+                nodeOrder,
+                // {2}
+                ExcelConditionalFormattingConstants.Paths._valAttribute));
+      }
+    }
+  }
+
+  /// <summary>
+  /// Get/Set the 'cfvo' node @val attribute
+  /// </summary>
+  public Double Value {
+    get =>
+      GetXmlNodeDouble(
+          string.Format(
+              "{0}[position()={1}]/{2}",
+              // {0}
+              ExcelConditionalFormattingConstants.Paths._cfvo,
+              // {1}
+              GetNodeOrder(),
+              // {2}
+              ExcelConditionalFormattingConstants.Paths._valAttribute));
+    set {
+      string valueToStore = string.Empty;
+
+      // Only some types use the @val attribute
+      if ((Type == eExcelConditionalFormattingValueObjectType.Num)
+          || (Type == eExcelConditionalFormattingValueObjectType.Percent)
+          || (Type == eExcelConditionalFormattingValueObjectType.Percentile)) {
+        valueToStore = value.ToString();
+      }
+
+      CreateNodeByOrdem(
+          eExcelConditionalFormattingValueObjectNodeType.Cfvo,
+          ExcelConditionalFormattingConstants.Paths._valAttribute,
+          valueToStore);
+    }
+  }
+
+  /// <summary>
+  /// Get/Set the Formula of the Object Value (uses the same attribute as the Value)
+  /// </summary>
+  public string Formula {
+    get {
+      // Return empty if the Object Value type is not Formula
+      if (Type != eExcelConditionalFormattingValueObjectType.Formula) {
+        return string.Empty;
+      }
+
+      // Excel stores the formula in the @val attribute
+      return GetXmlNodeString(
+          string.Format(
+              "{0}[position()={1}]/{2}",
+              // {0}
+              ExcelConditionalFormattingConstants.Paths._cfvo,
+              // {1}
+              GetNodeOrder(),
+              // {2}
+              ExcelConditionalFormattingConstants.Paths._valAttribute));
+    }
+    set {
+      // Only store the formula if the Object Value type is Formula
+      if (Type == eExcelConditionalFormattingValueObjectType.Formula) {
+        CreateNodeByOrdem(
+            eExcelConditionalFormattingValueObjectNodeType.Cfvo,
+            ExcelConditionalFormattingConstants.Paths._valAttribute,
+            value ?? string.Empty);
+      }
+    }
+  }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingConstants.cs b/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingConstants.cs
new file mode 100644
index 0000000..b8578ec
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingConstants.cs
@@ -0,0 +1,259 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// The conditional formatting constants
+/// </summary>
+internal static class ExcelConditionalFormattingConstants {
+  internal class Errors {
+    internal const string _commaSeparatedAddresses =
+        "Multiple addresses may not be commaseparated, use space instead";
+    internal const string _invalidPriority = "Invalid priority number. Must be bigger than zero";
+    internal const string _invalidRemoveRuleOperation = "Invalid remove rule operation";
+    internal const string _missingCfvoNode = "Missing 'cfvo' node in Conditional Formatting";
+    internal const string _missingCfvoParentNode =
+        "Missing 'cfvo' parent node in Conditional Formatting";
+    internal const string _missingConditionalFormattingNode =
+        "Missing 'conditionalFormatting' node in Conditional Formatting";
+    internal const string _missingItemRuleList =
+        "Missing item with address '{0}' in Conditional Formatting Rule List";
+    internal const string _missingPriorityAttribute =
+        "Missing 'priority' attribute in Conditional Formatting Rule";
+    internal const string _missingRuleType =
+        "Missing eExcelConditionalFormattingRuleType Type in Conditional Formatting";
+    internal const string _missingSqrefAttribute =
+        "Missing 'sqref' attribute in Conditional Formatting";
+    internal const string _missingTypeAttribute =
+        "Missing 'type' attribute in Conditional Formatting Rule";
+    internal const string _missingWorksheetNode = "Missing 'worksheet' node";
+    internal const string _nonSupportedRuleType = "Non supported conditionalFormattingType: {0}";
+    internal const string _unexistentCfvoTypeAttribute =
+        "Unexistent eExcelConditionalFormattingValueObjectType attribute in Conditional Formatting";
+    internal const string _unexistentOperatorTypeAttribute =
+        "Unexistent eExcelConditionalFormattingOperatorType attribute in Conditional Formatting";
+    internal const string _unexistentTimePeriodTypeAttribute =
+        "Unexistent eExcelConditionalFormattingTimePeriodType attribute in Conditional Formatting";
+    internal const string _unexpectedRuleTypeAttribute =
+        "Unexpected eExcelConditionalFormattingRuleType attribute in Conditional Formatting Rule";
+    internal const string _wrongNumberCfvoColorNodes =
+        "Wrong number of 'cfvo'/'color' nodes in Conditional Formatting Rule";
+  }
+
+  internal class Nodes {
+    internal const string _worksheet = "worksheet";
+    internal const string _conditionalFormatting = "conditionalFormatting";
+    internal const string _cfRule = "cfRule";
+    internal const string _colorScale = "colorScale";
+    internal const string _cfvo = "cfvo";
+    internal const string _color = "color";
+    internal const string _dataBar = "dataBar";
+    internal const string _iconSet = "iconSet";
+    internal const string _formula = "formula";
+  }
+
+  internal class Attributes {
+    internal const string _aboveAverage = "aboveAverage";
+    internal const string _bottom = "bottom";
+    internal const string _dxfId = "dxfId";
+    internal const string _equalAverage = "equalAverage";
+    internal const string _iconSet = "iconSet";
+    internal const string _operator = "operator";
+    internal const string _percent = "percent";
+    internal const string _priority = "priority";
+    internal const string _rank = "rank";
+    internal const string _reverse = "reverse";
+    internal const string _rgb = "rgb";
+    internal const string _showValue = "showValue";
+    internal const string _sqref = "sqref";
+    internal const string _stdDev = "stdDev";
+    internal const string _stopIfTrue = "stopIfTrue";
+    internal const string _text = "text";
+    internal const string _theme = "theme";
+    internal const string _timePeriod = "timePeriod";
+    internal const string _tint = "tint";
+    internal const string _type = "type";
+    internal const string _val = "val";
+  }
+
+  internal class Paths {
+    // Main node and attributes
+    internal const string _worksheet = "d:" + Nodes._worksheet;
+
+    // <conditionalFormatting> §18.3.1.18 node
+    // can appear more than once in a worksheet
+    internal const string _conditionalFormatting = "d:" + Nodes._conditionalFormatting;
+
+    // <cfRule> §18.3.1.10 node
+    // can appear more than once in a <conditionalFormatting>
+    internal const string _cfRule = "d:" + Nodes._cfRule;
+
+    // <colorScale> §18.3.1.16 node
+    internal const string _colorScale = "d:" + Nodes._colorScale;
+
+    // <cfvo> §18.3.1.11 node
+    internal const string _cfvo = "d:" + Nodes._cfvo;
+
+    // <color> §18.3.1.15 node
+    internal const string _color = "d:" + Nodes._color;
+
+    // <dataBar> §18.3.1.28 node
+    internal const string _dataBar = "d:" + Nodes._dataBar;
+
+    // <iconSet> §18.3.1.49 node
+    internal const string _iconSet = "d:" + Nodes._iconSet;
+
+    // <formula> §18.3.1.43 node
+    internal const string _formula = "d:" + Nodes._formula;
+
+    // Attributes (for all the nodes)
+    internal const string _aboveAverageAttribute = "@" + Attributes._aboveAverage;
+    internal const string _bottomAttribute = "@" + Attributes._bottom;
+    internal const string _dxfIdAttribute = "@" + Attributes._dxfId;
+    internal const string _equalAverageAttribute = "@" + Attributes._equalAverage;
+    internal const string _iconSetAttribute = "@" + Attributes._iconSet;
+    internal const string _operatorAttribute = "@" + Attributes._operator;
+    internal const string _percentAttribute = "@" + Attributes._percent;
+    internal const string _priorityAttribute = "@" + Attributes._priority;
+    internal const string _rankAttribute = "@" + Attributes._rank;
+    internal const string _reverseAttribute = "@" + Attributes._reverse;
+    internal const string _rgbAttribute = "@" + Attributes._rgb;
+    internal const string _showValueAttribute = "@" + Attributes._showValue;
+    internal const string _sqrefAttribute = "@" + Attributes._sqref;
+    internal const string _stdDevAttribute = "@" + Attributes._stdDev;
+    internal const string _stopIfTrueAttribute = "@" + Attributes._stopIfTrue;
+    internal const string _textAttribute = "@" + Attributes._text;
+    internal const string _themeAttribute = "@" + Attributes._theme;
+    internal const string _timePeriodAttribute = "@" + Attributes._timePeriod;
+    internal const string _tintAttribute = "@" + Attributes._tint;
+    internal const string _typeAttribute = "@" + Attributes._type;
+    internal const string _valAttribute = "@" + Attributes._val;
+  }
+
+  internal class RuleType {
+    internal const string _aboveAverage = "aboveAverage";
+    internal const string _beginsWith = "beginsWith";
+    internal const string _cellIs = "cellIs";
+    internal const string _colorScale = "colorScale";
+    internal const string _containsBlanks = "containsBlanks";
+    internal const string _containsErrors = "containsErrors";
+    internal const string _containsText = "containsText";
+    internal const string _dataBar = "dataBar";
+    internal const string _duplicateValues = "duplicateValues";
+    internal const string _endsWith = "endsWith";
+    internal const string _expression = "expression";
+    internal const string _iconSet = "iconSet";
+    internal const string _notContainsBlanks = "notContainsBlanks";
+    internal const string _notContainsErrors = "notContainsErrors";
+    internal const string _notContainsText = "notContainsText";
+    internal const string _timePeriod = "timePeriod";
+    internal const string _top10 = "top10";
+    internal const string _uniqueValues = "uniqueValues";
+
+    // EPPlus Extended Types
+    internal const string _aboveOrEqualAverage = "aboveOrEqualAverage";
+    internal const string _aboveStdDev = "aboveStdDev";
+    internal const string _belowAverage = "belowAverage";
+    internal const string _belowOrEqualAverage = "belowOrEqualAverage";
+    internal const string _belowStdDev = "belowStdDev";
+    internal const string _between = "between";
+    internal const string _bottom = "bottom";
+    internal const string _bottomPercent = "bottomPercent";
+    internal const string _equal = "equal";
+    internal const string _greaterThan = "greaterThan";
+    internal const string _greaterThanOrEqual = "greaterThanOrEqual";
+    internal const string _iconSet3 = "iconSet3";
+    internal const string _iconSet4 = "iconSet4";
+    internal const string _iconSet5 = "iconSet5";
+    internal const string _last7Days = "last7Days";
+    internal const string _lastMonth = "lastMonth";
+    internal const string _lastWeek = "lastWeek";
+    internal const string _lessThan = "lessThan";
+    internal const string _lessThanOrEqual = "lessThanOrEqual";
+    internal const string _nextMonth = "nextMonth";
+    internal const string _nextWeek = "nextWeek";
+    internal const string _notBetween = "notBetween";
+    internal const string _notEqual = "notEqual";
+    internal const string _thisMonth = "thisMonth";
+    internal const string _thisWeek = "thisWeek";
+    internal const string _threeColorScale = "threeColorScale";
+    internal const string _today = "today";
+    internal const string _tomorrow = "tomorrow";
+    internal const string _top = "top";
+    internal const string _topPercent = "topPercent";
+    internal const string _twoColorScale = "twoColorScale";
+    internal const string _yesterday = "yesterday";
+  }
+
+  internal class CfvoType {
+    internal const string _min = "min";
+    internal const string _max = "max";
+    internal const string _num = "num";
+    internal const string _formula = "formula";
+    internal const string _percent = "percent";
+    internal const string _percentile = "percentile";
+  }
+
+  internal class Operators {
+    internal const string _beginsWith = "beginsWith";
+    internal const string _between = "between";
+    internal const string _containsText = "containsText";
+    internal const string _endsWith = "endsWith";
+    internal const string _equal = "equal";
+    internal const string _greaterThan = "greaterThan";
+    internal const string _greaterThanOrEqual = "greaterThanOrEqual";
+    internal const string _lessThan = "lessThan";
+    internal const string _lessThanOrEqual = "lessThanOrEqual";
+    internal const string _notBetween = "notBetween";
+    internal const string _notContains = "notContains";
+    internal const string _notEqual = "notEqual";
+  }
+
+  internal class TimePeriods {
+    internal const string _last7Days = "last7Days";
+    internal const string _lastMonth = "lastMonth";
+    internal const string _lastWeek = "lastWeek";
+    internal const string _nextMonth = "nextMonth";
+    internal const string _nextWeek = "nextWeek";
+    internal const string _thisMonth = "thisMonth";
+    internal const string _thisWeek = "thisWeek";
+    internal const string _today = "today";
+    internal const string _tomorrow = "tomorrow";
+    internal const string _yesterday = "yesterday";
+  }
+
+  internal class Colors {
+    internal const string _cfvoLowValue = "#FFF8696B";
+    internal const string _cfvoMiddleValue = "#FFFFEB84";
+    internal const string _cfvoHighValue = "#FF63BE7B";
+  }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingEnums.cs b/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingEnums.cs
new file mode 100644
index 0000000..a53524d
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingEnums.cs
@@ -0,0 +1,753 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Enum for Conditional Format Type ST_CfType §18.18.12. With some changes.
+/// </summary>
+public enum eExcelConditionalFormattingRuleType {
+  /// <summary>
+  /// This conditional formatting rule highlights cells that are above the average
+  /// for all values in the range.
+  /// </summary>
+  /// <remarks>AboveAverage Excel CF Rule Type</remarks>
+  AboveAverage,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells that are above or equal
+  /// the average for all values in the range.
+  /// </summary>
+  /// <remarks>AboveAverage Excel CF Rule Type</remarks>
+  AboveOrEqualAverage,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells that are below the average
+  /// for all values in the range.
+  /// </summary>
+  /// <remarks>AboveAverage Excel CF Rule Type</remarks>
+  BelowAverage,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells that are below or equal
+  /// the average for all values in the range.
+  /// </summary>
+  /// <remarks>AboveAverage Excel CF Rule Type</remarks>
+  BelowOrEqualAverage,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells that are above the standard
+  /// deviationa for all values in the range.
+  /// <remarks>AboveAverage Excel CF Rule Type</remarks>
+  /// </summary>
+  AboveStdDev,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells that are below the standard
+  /// deviationa for all values in the range.
+  /// </summary>
+  /// <remarks>AboveAverage Excel CF Rule Type</remarks>
+  BelowStdDev,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells whose values fall in the
+  /// bottom N bracket as specified.
+  /// </summary>
+  /// <remarks>Top10 Excel CF Rule Type</remarks>
+  Bottom,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells whose values fall in the
+  /// bottom N percent as specified.
+  /// </summary>
+  /// <remarks>Top10 Excel CF Rule Type</remarks>
+  BottomPercent,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells whose values fall in the
+  /// top N bracket as specified.
+  /// </summary>
+  /// <remarks>Top10 Excel CF Rule Type</remarks>
+  Top,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells whose values fall in the
+  /// top N percent as specified.
+  /// </summary>
+  /// <remarks>Top10 Excel CF Rule Type</remarks>
+  TopPercent,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells containing dates in the
+  /// last 7 days.
+  /// </summary>
+  /// <remarks>TimePeriod Excel CF Rule Type</remarks>
+  Last7Days,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells containing dates in the
+  /// last month.
+  /// </summary>
+  /// <remarks>TimePeriod Excel CF Rule Type</remarks>
+  LastMonth,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells containing dates in the
+  /// last week.
+  /// </summary>
+  /// <remarks>TimePeriod Excel CF Rule Type</remarks>
+  LastWeek,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells containing dates in the
+  /// next month.
+  /// </summary>
+  /// <remarks>TimePeriod Excel CF Rule Type</remarks>
+  NextMonth,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells containing dates in the
+  /// next week.
+  /// </summary>
+  /// <remarks>TimePeriod Excel CF Rule Type</remarks>
+  NextWeek,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells containing dates in this
+  /// month.
+  /// </summary>
+  /// <remarks>TimePeriod Excel CF Rule Type</remarks>
+  ThisMonth,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells containing dates in this
+  /// week.
+  /// </summary>
+  /// <remarks>TimePeriod Excel CF Rule Type</remarks>
+  ThisWeek,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells containing today dates.
+  /// </summary>
+  /// <remarks>TimePeriod Excel CF Rule Type</remarks>
+  Today,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells containing tomorrow dates.
+  /// </summary>
+  /// <remarks>TimePeriod Excel CF Rule Type</remarks>
+  Tomorrow,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells containing yesterday dates.
+  /// </summary>
+  /// <remarks>TimePeriod Excel CF Rule Type</remarks>
+  Yesterday,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells in the range that begin with
+  /// the given text.
+  /// </summary>
+  /// <remarks>
+  /// Equivalent to using the LEFT() sheet function and comparing values.
+  /// </remarks>
+  /// <remarks>BeginsWith Excel CF Rule Type</remarks>
+  BeginsWith,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells in the range between the
+  /// given two formulas.
+  /// </summary>
+  /// <remarks>CellIs Excel CF Rule Type</remarks>
+  Between,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells that are completely blank.
+  /// </summary>
+  /// <remarks>
+  /// Equivalent of using LEN(TRIM()). This means that if the cell contains only
+  /// characters that TRIM() would remove, then it is considered blank. An empty cell
+  /// is also considered blank.
+  /// </remarks>
+  /// <remarks>ContainsBlanks Excel CF Rule Type</remarks>
+  ContainsBlanks,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells with formula errors.
+  /// </summary>
+  /// <remarks>
+  /// Equivalent to using ISERROR() sheet function to determine if there is
+  /// a formula error.
+  /// </remarks>
+  /// <remarks>ContainsErrors Excel CF Rule Type</remarks>
+  ContainsErrors,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells in the range that begin with
+  /// the given text.
+  /// </summary>
+  /// <remarks>
+  /// Equivalent to using the LEFT() sheet function and comparing values.
+  /// </remarks>
+  /// <remarks>ContainsText Excel CF Rule Type</remarks>
+  ContainsText,
+
+  /// <summary>
+  /// This conditional formatting rule highlights duplicated values.
+  /// </summary>
+  /// <remarks>DuplicateValues Excel CF Rule Type</remarks>
+  DuplicateValues,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells ending with given text.
+  /// </summary>
+  /// <remarks>
+  /// Equivalent to using the RIGHT() sheet function and comparing values.
+  /// </remarks>
+  /// <remarks>EndsWith Excel CF Rule Type</remarks>
+  EndsWith,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells equals to with given formula.
+  /// </summary>
+  /// <remarks>CellIs Excel CF Rule Type</remarks>
+  Equal,
+
+  /// <summary>
+  /// This conditional formatting rule contains a formula to evaluate. When the
+  /// formula result is true, the cell is highlighted.
+  /// </summary>
+  /// <remarks>Expression Excel CF Rule Type</remarks>
+  Expression,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells greater than the given formula.
+  /// </summary>
+  /// <remarks>CellIs Excel CF Rule Type</remarks>
+  GreaterThan,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells greater than or equal the
+  /// given formula.
+  /// </summary>
+  /// <remarks>CellIs Excel CF Rule Type</remarks>
+  GreaterThanOrEqual,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells less than the given formula.
+  /// </summary>
+  /// <remarks>CellIs Excel CF Rule Type</remarks>
+  LessThan,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells less than or equal the
+  /// given formula.
+  /// </summary>
+  /// <remarks>CellIs Excel CF Rule Type</remarks>
+  LessThanOrEqual,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells outside the range in
+  /// given two formulas.
+  /// </summary>
+  /// <remarks>CellIs Excel CF Rule Type</remarks>
+  NotBetween,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells that does not contains the
+  /// given formula.
+  /// </summary>
+  /// <remarks>CellIs Excel CF Rule Type</remarks>
+  NotContains,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells that are not blank.
+  /// </summary>
+  /// <remarks>
+  /// Equivalent of using LEN(TRIM()). This means that if the cell contains only
+  /// characters that TRIM() would remove, then it is considered blank. An empty cell
+  /// is also considered blank.
+  /// </remarks>
+  /// <remarks>NotContainsBlanks Excel CF Rule Type</remarks>
+  NotContainsBlanks,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells without formula errors.
+  /// </summary>
+  /// <remarks>
+  /// Equivalent to using ISERROR() sheet function to determine if there is a
+  /// formula error.
+  /// </remarks>
+  /// <remarks>NotContainsErrors Excel CF Rule Type</remarks>
+  NotContainsErrors,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells that do not contain
+  /// the given text.
+  /// </summary>
+  /// <remarks>
+  /// Equivalent to using the SEARCH() sheet function.
+  /// </remarks>
+  /// <remarks>NotContainsText Excel CF Rule Type</remarks>
+  NotContainsText,
+
+  /// <summary>
+  /// This conditional formatting rule highlights cells not equals to with
+  /// given formula.
+  /// </summary>
+  /// <remarks>CellIs Excel CF Rule Type</remarks>
+  NotEqual,
+
+  /// <summary>
+  /// This conditional formatting rule highlights unique values in the range.
+  /// </summary>
+  /// <remarks>UniqueValues Excel CF Rule Type</remarks>
+  UniqueValues,
+
+  /// <summary>
+  /// Three Color Scale (Low, Middle and High Color Scale)
+  /// </summary>
+  /// <remarks>ColorScale Excel CF Rule Type</remarks>
+  ThreeColorScale,
+
+  /// <summary>
+  /// Two Color Scale (Low and High Color Scale)
+  /// </summary>
+  /// <remarks>ColorScale Excel CF Rule Type</remarks>
+  TwoColorScale,
+
+  /// <summary>
+  /// This conditional formatting rule applies a 3 set icons to cells according
+  /// to their values.
+  /// </summary>
+  /// <remarks>IconSet Excel CF Rule Type</remarks>
+  ThreeIconSet,
+
+  /// <summary>
+  /// This conditional formatting rule applies a 4 set icons to cells according
+  /// to their values.
+  /// </summary>
+  /// <remarks>IconSet Excel CF Rule Type</remarks>
+  FourIconSet,
+
+  /// <summary>
+  /// This conditional formatting rule applies a 5 set icons to cells according
+  /// to their values.
+  /// </summary>
+  /// <remarks>IconSet Excel CF Rule Type</remarks>
+  FiveIconSet,
+
+  /// <summary>
+  /// This conditional formatting rule displays a gradated data bar in the range of cells.
+  /// </summary>
+  /// <remarks>DataBar Excel CF Rule Type</remarks>
+  DataBar,
+}
+
+/// <summary>
+/// Enum for Conditional Format Value Object Type ST_CfvoType §18.18.13
+/// </summary>
+public enum eExcelConditionalFormattingValueObjectType {
+  /// <summary>
+  /// Formula
+  /// </summary>
+  Formula,
+
+  /// <summary>
+  /// Maximum Value
+  /// </summary>
+  Max,
+
+  /// <summary>
+  /// Minimum Value
+  /// </summary>
+  Min,
+
+  /// <summary>
+  /// Number Value
+  /// </summary>
+  Num,
+
+  /// <summary>
+  /// Percent
+  /// </summary>
+  Percent,
+
+  /// <summary>
+  /// Percentile
+  /// </summary>
+  Percentile,
+}
+
+/// <summary>
+/// Enum for Conditional Formatting Value Object Position
+/// </summary>
+public enum eExcelConditionalFormattingValueObjectPosition {
+  /// <summary>
+  /// The lower position for both TwoColorScale and ThreeColorScale
+  /// </summary>
+  Low,
+
+  /// <summary>
+  /// The middle position only for ThreeColorScale
+  /// </summary>
+  Middle,
+
+  /// <summary>
+  /// The highest position for both TwoColorScale and ThreeColorScale
+  /// </summary>
+  High,
+}
+
+/// <summary>
+/// Enum for Conditional Formatting Value Object Node Type
+/// </summary>
+public enum eExcelConditionalFormattingValueObjectNodeType {
+  /// <summary>
+  /// 'cfvo' node
+  /// </summary>
+  Cfvo,
+
+  /// <summary>
+  /// 'color' node
+  /// </summary>
+  Color,
+}
+
+/// <summary>
+/// Enum for Conditional Formatting Operartor Type ST_ConditionalFormattingOperator §18.18.15
+/// </summary>
+public enum eExcelConditionalFormattingOperatorType {
+  /// <summary>
+  /// Begins With. 'Begins with' operator
+  /// </summary>
+  BeginsWith,
+
+  /// <summary>
+  /// Between. 'Between' operator
+  /// </summary>
+  Between,
+
+  /// <summary>
+  /// Contains. 'Contains' operator
+  /// </summary>
+  ContainsText,
+
+  /// <summary>
+  /// Ends With. 'Ends with' operator
+  /// </summary>
+  EndsWith,
+
+  /// <summary>
+  /// Equal. 'Equal to' operator
+  /// </summary>
+  Equal,
+
+  /// <summary>
+  /// Greater Than. 'Greater than' operator
+  /// </summary>
+  GreaterThan,
+
+  /// <summary>
+  /// Greater Than Or Equal. 'Greater than or equal to' operator
+  /// </summary>
+  GreaterThanOrEqual,
+
+  /// <summary>
+  /// Less Than. 'Less than' operator
+  /// </summary>
+  LessThan,
+
+  /// <summary>
+  /// Less Than Or Equal. 'Less than or equal to' operator
+  /// </summary>
+  LessThanOrEqual,
+
+  /// <summary>
+  /// Not Between. 'Not between' operator
+  /// </summary>
+  NotBetween,
+
+  /// <summary>
+  /// Does Not Contain. 'Does not contain' operator
+  /// </summary>
+  NotContains,
+
+  /// <summary>
+  /// Not Equal. 'Not equal to' operator
+  /// </summary>
+  NotEqual,
+}
+
+/// <summary>
+/// Enum for Conditional Formatting Time Period Type ST_TimePeriod §18.18.82
+/// </summary>
+public enum eExcelConditionalFormattingTimePeriodType {
+  /// <summary>
+  /// Last 7 Days. A date in the last seven days.
+  /// </summary>
+  Last7Days,
+
+  /// <summary>
+  /// Last Month. A date occuring in the last calendar month.
+  /// </summary>
+  LastMonth,
+
+  /// <summary>
+  /// Last Week. A date occuring last week.
+  /// </summary>
+  LastWeek,
+
+  /// <summary>
+  /// Next Month. A date occuring in the next calendar month.
+  /// </summary>
+  NextMonth,
+
+  /// <summary>
+  /// Next Week. A date occuring next week.
+  /// </summary>
+  NextWeek,
+
+  /// <summary>
+  /// This Month. A date occuring in this calendar month.
+  /// </summary>
+  ThisMonth,
+
+  /// <summary>
+  /// This Week. A date occuring this week.
+  /// </summary>
+  ThisWeek,
+
+  /// <summary>
+  /// Today. Today's date.
+  /// </summary>
+  Today,
+
+  /// <summary>
+  /// Tomorrow. Tomorrow's date.
+  /// </summary>
+  Tomorrow,
+
+  /// <summary>
+  /// Yesterday. Yesterday's date.
+  /// </summary>
+  Yesterday,
+}
+
+/// <summary>
+/// 18.18.42 ST_IconSetType (Icon Set Type) - Only 3 icons
+/// </summary>
+public enum eExcelconditionalFormatting3IconsSetType {
+  /// <summary>
+  /// (3 Arrows) 3 arrows icon set.
+  /// </summary>
+  Arrows,
+
+  /// <summary>
+  /// (3 Arrows (Gray)) 3 gray arrows icon set.
+  /// </summary>
+  ArrowsGray,
+
+  /// <summary>
+  /// (3 Flags) 3 flags icon set.
+  /// </summary>
+  Flags,
+
+  /// <summary>
+  /// (3 Signs) 3 signs icon set.
+  /// </summary>
+  Signs,
+
+  /// <summary>
+  /// (3 Symbols Circled) 3 symbols icon set.
+  /// </summary>
+  Symbols,
+
+  /// <summary>
+  /// (3 Symbols) 3 Symbols icon set.
+  /// </summary>
+  Symbols2,
+
+  /// <summary>
+  /// (3 Traffic Lights) 3 traffic lights icon set (#1).
+  /// </summary>
+  TrafficLights1,
+
+  /// <summary>
+  /// (3 Traffic Lights Black) 3 traffic lights icon set with thick black border.
+  /// </summary>
+  TrafficLights2,
+}
+
+/// <summary>
+/// 18.18.42 ST_IconSetType (Icon Set Type) - Only 4 icons
+/// </summary>
+public enum eExcelconditionalFormatting4IconsSetType {
+  /// <summary>
+  /// (4 Arrows) 4 arrows icon set.
+  /// </summary>
+  Arrows,
+
+  /// <summary>
+  /// (4 Arrows (Gray)) 4 gray arrows icon set.
+  /// </summary>
+  ArrowsGray,
+
+  /// <summary>
+  /// (4 Ratings) 4 ratings icon set.
+  /// </summary>
+  Rating,
+
+  /// <summary>
+  /// (4 Red To Black) 4 'red to black' icon set.
+  /// </summary>
+  RedToBlack,
+
+  /// <summary>
+  /// (4 Traffic Lights) 4 traffic lights icon set.
+  /// </summary>
+  TrafficLights,
+}
+
+/// <summary>
+/// 18.18.42 ST_IconSetType (Icon Set Type) - Only 5 icons
+/// </summary>
+public enum eExcelconditionalFormatting5IconsSetType {
+  /// <summary>
+  /// (5 Arrows) 5 arrows icon set.
+  /// </summary>
+  Arrows,
+
+  /// <summary>
+  /// (5 Arrows (Gray)) 5 gray arrows icon set.
+  /// </summary>
+  ArrowsGray,
+
+  /// <summary>
+  /// (5 Quarters) 5 quarters icon set.
+  /// </summary>
+  Quarters,
+
+  /// <summary>
+  /// (5 Ratings Icon Set) 5 rating icon set.
+  /// </summary>
+  Rating,
+}
+
+/// <summary>
+/// 18.18.42 ST_IconSetType (Icon Set Type)
+/// </summary>
+public enum eExcelconditionalFormattingIconsSetType {
+  /// <summary>
+  /// (3 Arrows) 3 arrows icon set.
+  /// </summary>
+  ThreeArrows,
+
+  /// <summary>
+  /// (3 Arrows (Gray)) 3 gray arrows icon set.
+  /// </summary>
+  ThreeArrowsGray,
+
+  /// <summary>
+  /// (3 Flags) 3 flags icon set.
+  /// </summary>
+  ThreeFlags,
+
+  /// <summary>
+  /// (3 Signs) 3 signs icon set.
+  /// </summary>
+  ThreeSigns,
+
+  /// <summary>
+  /// (3 Symbols Circled) 3 symbols icon set.
+  /// </summary>
+  ThreeSymbols,
+
+  /// <summary>
+  /// (3 Symbols) 3 Symbols icon set.
+  /// </summary>
+  ThreeSymbols2,
+
+  /// <summary>
+  /// (3 Traffic Lights) 3 traffic lights icon set (#1).
+  /// </summary>
+  ThreeTrafficLights1,
+
+  /// <summary>
+  /// (3 Traffic Lights Black) 3 traffic lights icon set with thick black border.
+  /// </summary>
+  ThreeTrafficLights2,
+
+  /// <summary>
+  /// (4 Arrows) 4 arrows icon set.
+  /// </summary>
+  FourArrows,
+
+  /// <summary>
+  /// (4 Arrows (Gray)) 4 gray arrows icon set.
+  /// </summary>
+  FourArrowsGray,
+
+  /// <summary>
+  /// (4 Ratings) 4 ratings icon set.
+  /// </summary>
+  FourRating,
+
+  /// <summary>
+  /// (4 Red To Black) 4 'red to black' icon set.
+  /// </summary>
+  FourRedToBlack,
+
+  /// <summary>
+  /// (4 Traffic Lights) 4 traffic lights icon set.
+  /// </summary>
+  FourTrafficLights,
+
+  /// <summary>
+  /// (5 Arrows) 5 arrows icon set.
+  /// </summary>
+  FiveArrows,
+
+  /// <summary>
+  /// (5 Arrows (Gray)) 5 gray arrows icon set.
+  /// </summary>
+  FiveArrowsGray,
+
+  /// <summary>
+  /// (5 Quarters) 5 quarters icon set.
+  /// </summary>
+  FiveQuarters,
+
+  /// <summary>
+  /// (5 Ratings Icon Set) 5 rating icon set.
+  /// </summary>
+  FiveRating,
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingHelper.cs b/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingHelper.cs
new file mode 100644
index 0000000..5947fbd
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingHelper.cs
@@ -0,0 +1,203 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System;
+using System.Globalization;
+using System.Text.RegularExpressions;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Conditional formatting helper
+/// </summary>
+internal static class ExcelConditionalFormattingHelper {
+  /// <summary>
+  /// Check and fix an address (string address)
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public static string CheckAndFixRangeAddress(string address) {
+    if (address.Contains(',')) {
+      throw new FormatException(
+          ExcelConditionalFormattingConstants.Errors._commaSeparatedAddresses);
+    }
+
+    address = address.ToUpper(CultureInfo.InvariantCulture);
+
+    if (Regex.IsMatch(address, "[A-Z]+:[A-Z]+")) {
+      address = AddressUtility.ParseEntireColumnSelections(address);
+    }
+
+    return address;
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="node"></param>
+  /// <param name="attribute"></param>
+  /// <returns></returns>
+  public static string GetAttributeString(XmlNode node, string attribute) {
+    try {
+      var value = node.Attributes[attribute].Value;
+      return value ?? string.Empty;
+    } catch {
+      return string.Empty;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="node"></param>
+  /// <param name="attribute"></param>
+  /// <returns></returns>
+  public static int GetAttributeInt(XmlNode node, string attribute) {
+    try {
+      var value = node.Attributes[attribute].Value;
+      return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture);
+    } catch {
+      return int.MinValue;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="node"></param>
+  /// <param name="attribute"></param>
+  /// <returns></returns>
+  public static int? GetAttributeIntNullable(XmlNode node, string attribute) {
+    try {
+      if (node.Attributes[attribute] == null) {
+        return null;
+      }
+      var value = node.Attributes[attribute].Value;
+      return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture);
+    } catch {
+      return null;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="node"></param>
+  /// <param name="attribute"></param>
+  /// <returns></returns>
+  public static bool GetAttributeBool(XmlNode node, string attribute) {
+    try {
+      var value = node.Attributes[attribute].Value;
+      return (value == "1"
+              || value == "-1"
+              || value.Equals("TRUE", StringComparison.InvariantCultureIgnoreCase));
+    } catch {
+      return false;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="node"></param>
+  /// <param name="attribute"></param>
+  /// <returns></returns>
+  public static bool? GetAttributeBoolNullable(XmlNode node, string attribute) {
+    try {
+      if (node.Attributes[attribute] == null) {
+        return null;
+      }
+      var value = node.Attributes[attribute].Value;
+      return (value == "1"
+              || value == "-1"
+              || value.Equals("TRUE", StringComparison.InvariantCultureIgnoreCase));
+    } catch {
+      return null;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="node"></param>
+  /// <param name="attribute"></param>
+  /// <returns></returns>
+  public static double GetAttributeDouble(XmlNode node, string attribute) {
+    try {
+      var value = node.Attributes[attribute].Value;
+      return double.Parse(value, NumberStyles.Number, CultureInfo.InvariantCulture);
+    } catch {
+      return double.NaN;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="node"></param>
+  /// <param name="attribute"></param>
+  /// <returns></returns>
+  public static decimal GetAttributeDecimal(XmlNode node, string attribute) {
+    try {
+      var value = node.Attributes[attribute].Value;
+      return decimal.Parse(value, NumberStyles.Any, CultureInfo.InvariantCulture);
+    } catch {
+      return decimal.MinValue;
+    }
+  }
+
+  /// <summary>
+  /// Encode to XML (special characteres: &apos; &quot; &gt; &lt; &amp;)
+  /// </summary>
+  /// <param name="s"></param>
+  /// <returns></returns>
+  public static string EncodeXml(this string s) {
+    return s.Replace("&", "&amp;")
+        .Replace("<", "&lt;")
+        .Replace(">", "&gt;")
+        .Replace("\"", "&quot;")
+        .Replace("'", "&apos;");
+  }
+
+  /// <summary>
+  /// Decode from XML (special characteres: &apos; &quot; &gt; &lt; &amp;)
+  /// </summary>
+  /// <param name="s"></param>
+  /// <returns></returns>
+  public static string DecodeXml(this string s) {
+    return s.Replace("'", "&apos;")
+        .Replace("\"", "&quot;")
+        .Replace(">", "&gt;")
+        .Replace("<", "&lt;")
+        .Replace("&", "&amp;");
+  }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingIconDatabarValue.cs b/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingIconDatabarValue.cs
new file mode 100644
index 0000000..ed367b3
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingIconDatabarValue.cs
@@ -0,0 +1,289 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System;
+using System.Collections.Immutable;
+using System.Drawing;
+using System.Globalization;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// 18.3.1.11 cfvo (Conditional Format Value Object)
+/// Describes the values of the interpolation points in a gradient scale.
+/// </summary>
+public class ExcelConditionalFormattingIconDataBarValue : XmlHelper {
+  private eExcelConditionalFormattingRuleType _ruleType;
+  private readonly ExcelWorksheet _worksheet;
+
+  /// <summary>
+  /// Initialize the cfvo (§18.3.1.11) node
+  /// </summary>
+  /// <param name="type"></param>
+  /// <param name="value"></param>
+  /// <param name="formula"></param>
+  /// <param name="ruleType"></param>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode">The cfvo (§18.3.1.11) node parent. Can be any of the following:
+  /// colorScale (§18.3.1.16); dataBar (§18.3.1.28); iconSet (§18.3.1.49)</param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingIconDataBarValue(
+      eExcelConditionalFormattingValueObjectType type,
+      double value,
+      string formula,
+      eExcelConditionalFormattingRuleType ruleType,
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : this(ruleType, address, worksheet, itemElementNode, namespaceManager) {
+    ArgumentOutOfRangeException.ThrowIfLessThan(priority, 1);
+
+    // Check if the parent does not exists
+    if (itemElementNode == null) {
+      // Get the parent node path by the rule type
+      string parentNodePath = ExcelConditionalFormattingValueObjectType.GetParentPathByRuleType(
+          ruleType);
+
+      // Check for en error (rule type does not have <cfvo>)
+      if (parentNodePath == string.Empty) {
+        throw new(ExcelConditionalFormattingConstants.Errors._missingCfvoParentNode);
+      }
+
+      // Point to the <cfvo> parent node
+      itemElementNode = _worksheet.WorksheetXml.SelectSingleNode(
+          string.Format(
+              "//{0}[{1}='{2}']/{3}[{4}='{5}']/{6}",
+              // {0}
+              ExcelConditionalFormattingConstants.Paths._conditionalFormatting,
+              // {1}
+              ExcelConditionalFormattingConstants.Paths._sqrefAttribute,
+              // {2}
+              address.Address,
+              // {3}
+              ExcelConditionalFormattingConstants.Paths._cfRule,
+              // {4}
+              ExcelConditionalFormattingConstants.Paths._priorityAttribute,
+              // {5}
+              priority,
+              // {6}
+              parentNodePath),
+          _worksheet.NameSpaceManager);
+
+      // Check for en error (rule type does not have <cfvo>)
+      if (itemElementNode == null) {
+        throw new(ExcelConditionalFormattingConstants.Errors._missingCfvoParentNode);
+      }
+    }
+
+    TopNode = itemElementNode;
+
+    // Save the attributes
+    RuleType = ruleType;
+    Type = type;
+    Value = value;
+    Formula = formula;
+  }
+
+  protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
+    ExcelConditionalFormattingConstants.Nodes._cfvo,
+  ];
+
+  /// <summary>
+  /// Initialize the cfvo (§18.3.1.11) node
+  /// </summary>
+  /// <param name="ruleType"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode">The cfvo (§18.3.1.11) node parent. Can be any of the following:
+  /// colorScale (§18.3.1.16); dataBar (§18.3.1.28); iconSet (§18.3.1.49)</param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingIconDataBarValue(
+      eExcelConditionalFormattingRuleType ruleType,
+      ExcelAddress address,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(namespaceManager, itemElementNode) {
+    ArgumentNullException.ThrowIfNull(address);
+    ArgumentNullException.ThrowIfNull(worksheet);
+
+    // Save the worksheet for private methods to use
+    _worksheet = worksheet;
+
+    //Check if the parent does not exists
+    if (itemElementNode == null) {
+      // Get the parent node path by the rule type
+      string parentNodePath = ExcelConditionalFormattingValueObjectType.GetParentPathByRuleType(
+          ruleType);
+
+      // Check for en error (rule type does not have <cfvo>)
+      if (parentNodePath == string.Empty) {
+        throw new(ExcelConditionalFormattingConstants.Errors._missingCfvoParentNode);
+      }
+    }
+    RuleType = ruleType;
+  }
+
+  /// <summary>
+  /// Initialize the <see cref="ExcelConditionalFormattingColorScaleValue"/>
+  /// </summary>
+  /// <param name="type"></param>
+  /// <param name="value"></param>
+  /// <param name="formula"></param>
+  /// <param name="ruleType"></param>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingIconDataBarValue(
+      eExcelConditionalFormattingValueObjectType type,
+      double value,
+      string formula,
+      eExcelConditionalFormattingRuleType ruleType,
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNamespaceManager namespaceManager)
+      : this(
+          type,
+          value,
+          formula,
+          ruleType,
+          address,
+          priority,
+          worksheet,
+          null,
+          namespaceManager) {}
+
+  /// <summary>
+  /// Initialize the <see cref="ExcelConditionalFormattingColorScaleValue"/>
+  /// </summary>
+  /// <param name="type"></param>
+  /// <param name="color"></param>
+  /// <param name="ruleType"></param>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingIconDataBarValue(
+      eExcelConditionalFormattingValueObjectType type,
+      Color color,
+      eExcelConditionalFormattingRuleType ruleType,
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNamespaceManager namespaceManager)
+      : this(type, 0, null, ruleType, address, priority, worksheet, null, namespaceManager) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  internal eExcelConditionalFormattingRuleType RuleType {
+    get => _ruleType;
+    set => _ruleType = value;
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  public eExcelConditionalFormattingValueObjectType Type {
+    get {
+      var typeAttribute = GetXmlNodeString(
+          ExcelConditionalFormattingConstants.Paths._typeAttribute);
+
+      return ExcelConditionalFormattingValueObjectType.GetTypeByAttrbiute(typeAttribute);
+    }
+    set {
+      if ((_ruleType == eExcelConditionalFormattingRuleType.ThreeIconSet
+                  || _ruleType == eExcelConditionalFormattingRuleType.FourIconSet
+                  || _ruleType == eExcelConditionalFormattingRuleType.FiveIconSet)
+          && (value == eExcelConditionalFormattingValueObjectType.Min
+                  || value == eExcelConditionalFormattingValueObjectType.Max)) {
+        throw (new ArgumentException("Value type can't be Min or Max for icon sets"));
+      }
+      SetXmlNodeString(
+          ExcelConditionalFormattingConstants.Paths._typeAttribute,
+          value.ToString().ToLower(CultureInfo.InvariantCulture));
+    }
+  }
+
+  /// <summary>
+  /// Get/Set the 'cfvo' node @val attribute
+  /// </summary>
+  public Double Value {
+    get {
+      if ((Type == eExcelConditionalFormattingValueObjectType.Num)
+          || (Type == eExcelConditionalFormattingValueObjectType.Percent)
+          || (Type == eExcelConditionalFormattingValueObjectType.Percentile)) {
+        return GetXmlNodeDouble(ExcelConditionalFormattingConstants.Paths._valAttribute);
+      }
+      return 0;
+    }
+    set {
+      string valueToStore = string.Empty;
+
+      // Only some types use the @val attribute
+      if ((Type == eExcelConditionalFormattingValueObjectType.Num)
+          || (Type == eExcelConditionalFormattingValueObjectType.Percent)
+          || (Type == eExcelConditionalFormattingValueObjectType.Percentile)) {
+        valueToStore = value.ToString(CultureInfo.InvariantCulture);
+      }
+
+      SetXmlNodeString(ExcelConditionalFormattingConstants.Paths._valAttribute, valueToStore);
+    }
+  }
+
+  /// <summary>
+  /// Get/Set the Formula of the Object Value (uses the same attribute as the Value)
+  /// </summary>
+  public string Formula {
+    get {
+      // Return empty if the Object Value type is not Formula
+      if (Type != eExcelConditionalFormattingValueObjectType.Formula) {
+        return string.Empty;
+      }
+
+      // Excel stores the formula in the @val attribute
+      return GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._valAttribute);
+    }
+    set {
+      // Only store the formula if the Object Value type is Formula
+      if (Type == eExcelConditionalFormattingValueObjectType.Formula) {
+        SetXmlNodeString(ExcelConditionalFormattingConstants.Paths._valAttribute, value);
+      }
+    }
+  }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingOperatorType.cs b/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingOperatorType.cs
new file mode 100644
index 0000000..486613b
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingOperatorType.cs
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-17
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Functions related to the <see cref="ExcelConditionalFormattingOperatorType"/>
+/// </summary>
+internal static class ExcelConditionalFormattingOperatorType {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="type"></param>
+  /// <returns></returns>
+  internal static string GetAttributeByType(eExcelConditionalFormattingOperatorType type) {
+    switch (type) {
+      case eExcelConditionalFormattingOperatorType.BeginsWith:
+        return ExcelConditionalFormattingConstants.Operators._beginsWith;
+
+      case eExcelConditionalFormattingOperatorType.Between:
+        return ExcelConditionalFormattingConstants.Operators._between;
+
+      case eExcelConditionalFormattingOperatorType.ContainsText:
+        return ExcelConditionalFormattingConstants.Operators._containsText;
+
+      case eExcelConditionalFormattingOperatorType.EndsWith:
+        return ExcelConditionalFormattingConstants.Operators._endsWith;
+
+      case eExcelConditionalFormattingOperatorType.Equal:
+        return ExcelConditionalFormattingConstants.Operators._equal;
+
+      case eExcelConditionalFormattingOperatorType.GreaterThan:
+        return ExcelConditionalFormattingConstants.Operators._greaterThan;
+
+      case eExcelConditionalFormattingOperatorType.GreaterThanOrEqual:
+        return ExcelConditionalFormattingConstants.Operators._greaterThanOrEqual;
+
+      case eExcelConditionalFormattingOperatorType.LessThan:
+        return ExcelConditionalFormattingConstants.Operators._lessThan;
+
+      case eExcelConditionalFormattingOperatorType.LessThanOrEqual:
+        return ExcelConditionalFormattingConstants.Operators._lessThanOrEqual;
+
+      case eExcelConditionalFormattingOperatorType.NotBetween:
+        return ExcelConditionalFormattingConstants.Operators._notBetween;
+
+      case eExcelConditionalFormattingOperatorType.NotContains:
+        return ExcelConditionalFormattingConstants.Operators._notContains;
+
+      case eExcelConditionalFormattingOperatorType.NotEqual:
+        return ExcelConditionalFormattingConstants.Operators._notEqual;
+    }
+
+    return string.Empty;
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// param name="attribute"
+  /// <returns></returns>
+  internal static eExcelConditionalFormattingOperatorType GetTypeByAttribute(string attribute) {
+    switch (attribute) {
+      case ExcelConditionalFormattingConstants.Operators._beginsWith:
+        return eExcelConditionalFormattingOperatorType.BeginsWith;
+
+      case ExcelConditionalFormattingConstants.Operators._between:
+        return eExcelConditionalFormattingOperatorType.Between;
+
+      case ExcelConditionalFormattingConstants.Operators._containsText:
+        return eExcelConditionalFormattingOperatorType.ContainsText;
+
+      case ExcelConditionalFormattingConstants.Operators._endsWith:
+        return eExcelConditionalFormattingOperatorType.EndsWith;
+
+      case ExcelConditionalFormattingConstants.Operators._equal:
+        return eExcelConditionalFormattingOperatorType.Equal;
+
+      case ExcelConditionalFormattingConstants.Operators._greaterThan:
+        return eExcelConditionalFormattingOperatorType.GreaterThan;
+
+      case ExcelConditionalFormattingConstants.Operators._greaterThanOrEqual:
+        return eExcelConditionalFormattingOperatorType.GreaterThanOrEqual;
+
+      case ExcelConditionalFormattingConstants.Operators._lessThan:
+        return eExcelConditionalFormattingOperatorType.LessThan;
+
+      case ExcelConditionalFormattingConstants.Operators._lessThanOrEqual:
+        return eExcelConditionalFormattingOperatorType.LessThanOrEqual;
+
+      case ExcelConditionalFormattingConstants.Operators._notBetween:
+        return eExcelConditionalFormattingOperatorType.NotBetween;
+
+      case ExcelConditionalFormattingConstants.Operators._notContains:
+        return eExcelConditionalFormattingOperatorType.NotContains;
+
+      case ExcelConditionalFormattingConstants.Operators._notEqual:
+        return eExcelConditionalFormattingOperatorType.NotEqual;
+    }
+
+    throw new(ExcelConditionalFormattingConstants.Errors._unexistentOperatorTypeAttribute);
+  }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingRuleFactory.cs b/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingRuleFactory.cs
new file mode 100644
index 0000000..a0023df
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingRuleFactory.cs
@@ -0,0 +1,357 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ *  * Author							Change						      Date
+ * ******************************************************************************
+ * Eyal Seagull		    Conditional Formatting      2012-04-03
+ *******************************************************************************/
+
+using System;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Factory class for ExcelConditionalFormatting.
+/// </summary>
+internal static class ExcelConditionalFormattingRuleFactory {
+  public static ExcelConditionalFormattingRule Create(
+      eExcelConditionalFormattingRuleType type,
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode) {
+    ArgumentNullException.ThrowIfNull(address);
+    ArgumentOutOfRangeException.ThrowIfLessThan(priority, 1);
+    ArgumentNullException.ThrowIfNull(worksheet);
+
+    // According the conditional formatting rule type
+    switch (type) {
+      case eExcelConditionalFormattingRuleType.AboveAverage:
+        return new ExcelConditionalFormattingAboveAverage(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.AboveOrEqualAverage:
+        return new ExcelConditionalFormattingAboveOrEqualAverage(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.BelowAverage:
+        return new ExcelConditionalFormattingBelowAverage(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.BelowOrEqualAverage:
+        return new ExcelConditionalFormattingBelowOrEqualAverage(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.AboveStdDev:
+        return new ExcelConditionalFormattingAboveStdDev(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.BelowStdDev:
+        return new ExcelConditionalFormattingBelowStdDev(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.Bottom:
+        return new ExcelConditionalFormattingBottom(address, priority, worksheet, itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.BottomPercent:
+        return new ExcelConditionalFormattingBottomPercent(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.Top:
+        return new ExcelConditionalFormattingTop(address, priority, worksheet, itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.TopPercent:
+        return new ExcelConditionalFormattingTopPercent(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.Last7Days:
+        return new ExcelConditionalFormattingLast7Days(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.LastMonth:
+        return new ExcelConditionalFormattingLastMonth(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.LastWeek:
+        return new ExcelConditionalFormattingLastWeek(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.NextMonth:
+        return new ExcelConditionalFormattingNextMonth(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.NextWeek:
+        return new ExcelConditionalFormattingNextWeek(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.ThisMonth:
+        return new ExcelConditionalFormattingThisMonth(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.ThisWeek:
+        return new ExcelConditionalFormattingThisWeek(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.Today:
+        return new ExcelConditionalFormattingToday(address, priority, worksheet, itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.Tomorrow:
+        return new ExcelConditionalFormattingTomorrow(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.Yesterday:
+        return new ExcelConditionalFormattingYesterday(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.BeginsWith:
+        return new ExcelConditionalFormattingBeginsWith(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.Between:
+        return new ExcelConditionalFormattingBetween(address, priority, worksheet, itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.ContainsBlanks:
+        return new ExcelConditionalFormattingContainsBlanks(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.ContainsErrors:
+        return new ExcelConditionalFormattingContainsErrors(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.ContainsText:
+        return new ExcelConditionalFormattingContainsText(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.DuplicateValues:
+        return new ExcelConditionalFormattingDuplicateValues(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.EndsWith:
+        return new ExcelConditionalFormattingEndsWith(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.Equal:
+        return new ExcelConditionalFormattingEqual(address, priority, worksheet, itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.Expression:
+        return new ExcelConditionalFormattingExpression(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.GreaterThan:
+        return new ExcelConditionalFormattingGreaterThan(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.GreaterThanOrEqual:
+        return new ExcelConditionalFormattingGreaterThanOrEqual(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.LessThan:
+        return new ExcelConditionalFormattingLessThan(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.LessThanOrEqual:
+        return new ExcelConditionalFormattingLessThanOrEqual(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.NotBetween:
+        return new ExcelConditionalFormattingNotBetween(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.NotContainsBlanks:
+        return new ExcelConditionalFormattingNotContainsBlanks(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.NotContainsErrors:
+        return new ExcelConditionalFormattingNotContainsErrors(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.NotContainsText:
+        return new ExcelConditionalFormattingNotContainsText(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.NotEqual:
+        return new ExcelConditionalFormattingNotEqual(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.UniqueValues:
+        return new ExcelConditionalFormattingUniqueValues(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.ThreeColorScale:
+        return new ExcelConditionalFormattingThreeColorScale(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+
+      case eExcelConditionalFormattingRuleType.TwoColorScale:
+        return new ExcelConditionalFormattingTwoColorScale(
+            address,
+            priority,
+            worksheet,
+            itemElementNode);
+      case eExcelConditionalFormattingRuleType.ThreeIconSet:
+        return new ExcelConditionalFormattingThreeIconSet(
+            address,
+            priority,
+            worksheet,
+            itemElementNode,
+            null);
+      case eExcelConditionalFormattingRuleType.FourIconSet:
+        return new ExcelConditionalFormattingFourIconSet(
+            address,
+            priority,
+            worksheet,
+            itemElementNode,
+            null);
+      case eExcelConditionalFormattingRuleType.FiveIconSet:
+        return new ExcelConditionalFormattingFiveIconSet(
+            address,
+            priority,
+            worksheet,
+            itemElementNode,
+            null);
+      case eExcelConditionalFormattingRuleType.DataBar:
+        return new ExcelConditionalFormattingDataBar(
+            eExcelConditionalFormattingRuleType.DataBar,
+            address,
+            priority,
+            worksheet,
+            itemElementNode,
+            null);
+
+      //TODO: Add DataBar
+    }
+
+    throw new InvalidOperationException(
+        string.Format(
+            ExcelConditionalFormattingConstants.Errors._nonSupportedRuleType,
+            type.ToString()));
+  }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingRuleType.cs b/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingRuleType.cs
new file mode 100644
index 0000000..62f928d
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingRuleType.cs
@@ -0,0 +1,494 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Functions related to the ExcelConditionalFormattingRule
+/// </summary>
+internal static class ExcelConditionalFormattingRuleType {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="attribute"></param>
+  /// <param name="topNode"></param>
+  /// <param name="nameSpaceManager"></param>
+  /// <returns></returns>
+  internal static eExcelConditionalFormattingRuleType GetTypeByAttrbiute(
+      string attribute,
+      XmlNode topNode,
+      XmlNamespaceManager nameSpaceManager) {
+    switch (attribute) {
+      case ExcelConditionalFormattingConstants.RuleType._aboveAverage:
+        return GetAboveAverageType(topNode, nameSpaceManager);
+
+      case ExcelConditionalFormattingConstants.RuleType._top10:
+        return GetTop10Type(topNode, nameSpaceManager);
+
+      case ExcelConditionalFormattingConstants.RuleType._timePeriod:
+        return GetTimePeriodType(topNode, nameSpaceManager);
+      case ExcelConditionalFormattingConstants.RuleType._cellIs:
+        return GetCellIs((XmlElement)topNode);
+      case ExcelConditionalFormattingConstants.RuleType._beginsWith:
+        return eExcelConditionalFormattingRuleType.BeginsWith;
+
+      //case ExcelConditionalFormattingConstants.RuleType.Between:
+      //  return eExcelConditionalFormattingRuleType.Between;
+
+      case ExcelConditionalFormattingConstants.RuleType._containsBlanks:
+        return eExcelConditionalFormattingRuleType.ContainsBlanks;
+
+      case ExcelConditionalFormattingConstants.RuleType._containsErrors:
+        return eExcelConditionalFormattingRuleType.ContainsErrors;
+
+      case ExcelConditionalFormattingConstants.RuleType._containsText:
+        return eExcelConditionalFormattingRuleType.ContainsText;
+
+      case ExcelConditionalFormattingConstants.RuleType._duplicateValues:
+        return eExcelConditionalFormattingRuleType.DuplicateValues;
+
+      case ExcelConditionalFormattingConstants.RuleType._endsWith:
+        return eExcelConditionalFormattingRuleType.EndsWith;
+
+      //case ExcelConditionalFormattingConstants.RuleType.Equal:
+      //  return eExcelConditionalFormattingRuleType.Equal;
+
+      case ExcelConditionalFormattingConstants.RuleType._expression:
+        return eExcelConditionalFormattingRuleType.Expression;
+
+      //case ExcelConditionalFormattingConstants.RuleType.GreaterThan:
+      //  return eExcelConditionalFormattingRuleType.GreaterThan;
+
+      //case ExcelConditionalFormattingConstants.RuleType.GreaterThanOrEqual:
+      //  return eExcelConditionalFormattingRuleType.GreaterThanOrEqual;
+
+      //case ExcelConditionalFormattingConstants.RuleType.LessThan:
+      //  return eExcelConditionalFormattingRuleType.LessThan;
+
+      //case ExcelConditionalFormattingConstants.RuleType.LessThanOrEqual:
+      //  return eExcelConditionalFormattingRuleType.LessThanOrEqual;
+
+      //case ExcelConditionalFormattingConstants.RuleType.NotBetween:
+      //  return eExcelConditionalFormattingRuleType.NotBetween;
+
+      case ExcelConditionalFormattingConstants.RuleType._notContainsBlanks:
+        return eExcelConditionalFormattingRuleType.NotContainsBlanks;
+
+      case ExcelConditionalFormattingConstants.RuleType._notContainsErrors:
+        return eExcelConditionalFormattingRuleType.NotContainsErrors;
+
+      case ExcelConditionalFormattingConstants.RuleType._notContainsText:
+        return eExcelConditionalFormattingRuleType.NotContainsText;
+
+      //case ExcelConditionalFormattingConstants.RuleType.NotEqual:
+      //  return eExcelConditionalFormattingRuleType.NotEqual;
+
+      case ExcelConditionalFormattingConstants.RuleType._uniqueValues:
+        return eExcelConditionalFormattingRuleType.UniqueValues;
+
+      case ExcelConditionalFormattingConstants.RuleType._colorScale:
+        return GetColorScaleType(topNode, nameSpaceManager);
+      case ExcelConditionalFormattingConstants.RuleType._iconSet:
+        return GetIconSetType(topNode, nameSpaceManager);
+      case ExcelConditionalFormattingConstants.RuleType._dataBar:
+        return eExcelConditionalFormattingRuleType.DataBar;
+    }
+
+    throw new(ExcelConditionalFormattingConstants.Errors._unexpectedRuleTypeAttribute);
+  }
+
+  private static eExcelConditionalFormattingRuleType GetCellIs(XmlElement node) {
+    switch (node.GetAttribute("operator")) {
+      case ExcelConditionalFormattingConstants.Operators._beginsWith:
+        return eExcelConditionalFormattingRuleType.BeginsWith;
+      case ExcelConditionalFormattingConstants.Operators._between:
+        return eExcelConditionalFormattingRuleType.Between;
+
+      case ExcelConditionalFormattingConstants.Operators._containsText:
+        return eExcelConditionalFormattingRuleType.ContainsText;
+
+      case ExcelConditionalFormattingConstants.Operators._endsWith:
+        return eExcelConditionalFormattingRuleType.EndsWith;
+
+      case ExcelConditionalFormattingConstants.Operators._equal:
+        return eExcelConditionalFormattingRuleType.Equal;
+
+      case ExcelConditionalFormattingConstants.Operators._greaterThan:
+        return eExcelConditionalFormattingRuleType.GreaterThan;
+
+      case ExcelConditionalFormattingConstants.Operators._greaterThanOrEqual:
+        return eExcelConditionalFormattingRuleType.GreaterThanOrEqual;
+
+      case ExcelConditionalFormattingConstants.Operators._lessThan:
+        return eExcelConditionalFormattingRuleType.LessThan;
+
+      case ExcelConditionalFormattingConstants.Operators._lessThanOrEqual:
+        return eExcelConditionalFormattingRuleType.LessThanOrEqual;
+
+      case ExcelConditionalFormattingConstants.Operators._notBetween:
+        return eExcelConditionalFormattingRuleType.NotBetween;
+
+      case ExcelConditionalFormattingConstants.Operators._notContains:
+        return eExcelConditionalFormattingRuleType.NotContains;
+
+      case ExcelConditionalFormattingConstants.Operators._notEqual:
+        return eExcelConditionalFormattingRuleType.NotEqual;
+      default:
+        throw new(ExcelConditionalFormattingConstants.Errors._unexistentOperatorTypeAttribute);
+    }
+  }
+
+  private static eExcelConditionalFormattingRuleType GetIconSetType(
+      XmlNode topNode,
+      XmlNamespaceManager nameSpaceManager) {
+    var node = topNode.SelectSingleNode("d:iconSet/@iconSet", nameSpaceManager);
+    if (node == null) {
+      return eExcelConditionalFormattingRuleType.ThreeIconSet;
+    }
+    var v = node.Value;
+
+    if (v[0] == '3') {
+      return eExcelConditionalFormattingRuleType.ThreeIconSet;
+    }
+    if (v[0] == '4') {
+      return eExcelConditionalFormattingRuleType.FourIconSet;
+    }
+    return eExcelConditionalFormattingRuleType.FiveIconSet;
+  }
+
+  /// <summary>
+  /// Get the "colorScale" rule type according to the number of "cfvo" and "color" nodes.
+  /// If we have excatly 2 "cfvo" and "color" childs, then we return "twoColorScale"
+  /// </summary>
+  /// <returns>TwoColorScale or ThreeColorScale</returns>
+  internal static eExcelConditionalFormattingRuleType GetColorScaleType(
+      XmlNode topNode,
+      XmlNamespaceManager nameSpaceManager) {
+    // Get the <cfvo> nodes
+    var cfvoNodes = topNode.SelectNodes(
+        string.Format(
+            "{0}/{1}",
+            ExcelConditionalFormattingConstants.Paths._colorScale,
+            ExcelConditionalFormattingConstants.Paths._cfvo),
+        nameSpaceManager);
+
+    // Get the <color> nodes
+    var colorNodes = topNode.SelectNodes(
+        string.Format(
+            "{0}/{1}",
+            ExcelConditionalFormattingConstants.Paths._colorScale,
+            ExcelConditionalFormattingConstants.Paths._color),
+        nameSpaceManager);
+
+    // We determine if it is "TwoColorScale" or "ThreeColorScale" by the
+    // number of <cfvo> and <color> inside the <colorScale> node
+    if ((cfvoNodes == null)
+        || (cfvoNodes.Count < 2)
+        || (cfvoNodes.Count > 3)
+        || (colorNodes == null)
+        || (colorNodes.Count < 2)
+        || (colorNodes.Count > 3)
+        || (cfvoNodes.Count != colorNodes.Count)) {
+      throw new(ExcelConditionalFormattingConstants.Errors._wrongNumberCfvoColorNodes);
+    }
+
+    // Return the corresponding rule type (TwoColorScale or ThreeColorScale)
+    return (cfvoNodes.Count == 2)
+        ? eExcelConditionalFormattingRuleType.TwoColorScale
+        : eExcelConditionalFormattingRuleType.ThreeColorScale;
+  }
+
+  /// <summary>
+  /// Get the "aboveAverage" rule type according to the follwoing attributes:
+  /// "AboveAverage", "EqualAverage" and "StdDev".
+  ///
+  /// @StdDev greater than "0"                              == AboveStdDev
+  /// @StdDev less than "0"                                 == BelowStdDev
+  /// @AboveAverage = "1"/null and @EqualAverage = "0"/null == AboveAverage
+  /// @AboveAverage = "1"/null and @EqualAverage = "1"      == AboveOrEqualAverage
+  /// @AboveAverage = "0" and @EqualAverage = "0"/null      == BelowAverage
+  /// @AboveAverage = "0" and @EqualAverage = "1"           == BelowOrEqualAverage
+  /// /// </summary>
+  /// <returns>AboveAverage, AboveOrEqualAverage, BelowAverage or BelowOrEqualAverage</returns>
+  internal static eExcelConditionalFormattingRuleType GetAboveAverageType(
+      XmlNode topNode,
+      XmlNamespaceManager nameSpaceManager) {
+    // Get @StdDev attribute
+    int? stdDev = ExcelConditionalFormattingHelper.GetAttributeIntNullable(
+        topNode,
+        ExcelConditionalFormattingConstants.Attributes._stdDev);
+
+    if (stdDev > 0) {
+      // @StdDev > "0" --> AboveStdDev
+      return eExcelConditionalFormattingRuleType.AboveStdDev;
+    }
+
+    if (stdDev < 0) {
+      // @StdDev < "0" --> BelowStdDev
+      return eExcelConditionalFormattingRuleType.BelowStdDev;
+    }
+
+    // Get @AboveAverage attribute
+    bool? isAboveAverage = ExcelConditionalFormattingHelper.GetAttributeBoolNullable(
+        topNode,
+        ExcelConditionalFormattingConstants.Attributes._aboveAverage);
+
+    // Get @EqualAverage attribute
+    bool? isEqualAverage = ExcelConditionalFormattingHelper.GetAttributeBoolNullable(
+        topNode,
+        ExcelConditionalFormattingConstants.Attributes._equalAverage);
+
+    if ((isAboveAverage == null) || (isAboveAverage == true)) {
+      if (isEqualAverage == true) {
+        // @AboveAverage = "1"/null and @EqualAverage = "1" == AboveOrEqualAverage
+        return eExcelConditionalFormattingRuleType.AboveOrEqualAverage;
+      }
+
+      // @AboveAverage = "1"/null and @EqualAverage = "0"/null == AboveAverage
+      return eExcelConditionalFormattingRuleType.AboveAverage;
+    }
+
+    if (isEqualAverage == true) {
+      // @AboveAverage = "0" and @EqualAverage = "1" == BelowOrEqualAverage
+      return eExcelConditionalFormattingRuleType.BelowOrEqualAverage;
+    }
+
+    // @AboveAverage = "0" and @EqualAverage = "0"/null == BelowAverage
+    return eExcelConditionalFormattingRuleType.BelowAverage;
+  }
+
+  /// <summary>
+  /// Get the "top10" rule type according to the follwoing attributes:
+  /// "Bottom" and "Percent"
+  ///
+  /// @Bottom = "1" and @Percent = "0"/null       == Bottom
+  /// @Bottom = "1" and @Percent = "1"            == BottomPercent
+  /// @Bottom = "0"/null and @Percent = "0"/null  == Top
+  /// @Bottom = "0"/null and @Percent = "1"       == TopPercent
+  /// /// </summary>
+  /// <returns>Top, TopPercent, Bottom or BottomPercent</returns>
+  public static eExcelConditionalFormattingRuleType GetTop10Type(
+      XmlNode topNode,
+      XmlNamespaceManager nameSpaceManager) {
+    // Get @Bottom attribute
+    bool? isBottom = ExcelConditionalFormattingHelper.GetAttributeBoolNullable(
+        topNode,
+        ExcelConditionalFormattingConstants.Attributes._bottom);
+
+    // Get @Percent attribute
+    bool? isPercent = ExcelConditionalFormattingHelper.GetAttributeBoolNullable(
+        topNode,
+        ExcelConditionalFormattingConstants.Attributes._percent);
+
+    if (isBottom == true) {
+      if (isPercent == true) {
+        // @Bottom = "1" and @Percent = "1" == BottomPercent
+        return eExcelConditionalFormattingRuleType.BottomPercent;
+      }
+
+      // @Bottom = "1" and @Percent = "0"/null == Bottom
+      return eExcelConditionalFormattingRuleType.Bottom;
+    }
+
+    if (isPercent == true) {
+      // @Bottom = "0"/null and @Percent = "1" == TopPercent
+      return eExcelConditionalFormattingRuleType.TopPercent;
+    }
+
+    // @Bottom = "0"/null and @Percent = "0"/null == Top
+    return eExcelConditionalFormattingRuleType.Top;
+  }
+
+  /// <summary>
+  /// Get the "timePeriod" rule type according to "TimePeriod" attribute.
+  /// /// </summary>
+  /// <returns>Last7Days, LastMonth etc.</returns>
+  public static eExcelConditionalFormattingRuleType GetTimePeriodType(
+      XmlNode topNode,
+      XmlNamespaceManager nameSpaceManager) {
+    eExcelConditionalFormattingTimePeriodType timePeriod =
+        ExcelConditionalFormattingTimePeriodType.GetTypeByAttribute(
+            ExcelConditionalFormattingHelper.GetAttributeString(
+                topNode,
+                ExcelConditionalFormattingConstants.Attributes._timePeriod));
+
+    switch (timePeriod) {
+      case eExcelConditionalFormattingTimePeriodType.Last7Days:
+        return eExcelConditionalFormattingRuleType.Last7Days;
+
+      case eExcelConditionalFormattingTimePeriodType.LastMonth:
+        return eExcelConditionalFormattingRuleType.LastMonth;
+
+      case eExcelConditionalFormattingTimePeriodType.LastWeek:
+        return eExcelConditionalFormattingRuleType.LastWeek;
+
+      case eExcelConditionalFormattingTimePeriodType.NextMonth:
+        return eExcelConditionalFormattingRuleType.NextMonth;
+
+      case eExcelConditionalFormattingTimePeriodType.NextWeek:
+        return eExcelConditionalFormattingRuleType.NextWeek;
+
+      case eExcelConditionalFormattingTimePeriodType.ThisMonth:
+        return eExcelConditionalFormattingRuleType.ThisMonth;
+
+      case eExcelConditionalFormattingTimePeriodType.ThisWeek:
+        return eExcelConditionalFormattingRuleType.ThisWeek;
+
+      case eExcelConditionalFormattingTimePeriodType.Today:
+        return eExcelConditionalFormattingRuleType.Today;
+
+      case eExcelConditionalFormattingTimePeriodType.Tomorrow:
+        return eExcelConditionalFormattingRuleType.Tomorrow;
+
+      case eExcelConditionalFormattingTimePeriodType.Yesterday:
+        return eExcelConditionalFormattingRuleType.Yesterday;
+    }
+
+    throw new(ExcelConditionalFormattingConstants.Errors._unexistentTimePeriodTypeAttribute);
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="type"></param>
+  /// <returns></returns>
+  public static string GetAttributeByType(eExcelConditionalFormattingRuleType type) {
+    switch (type) {
+      case eExcelConditionalFormattingRuleType.AboveAverage:
+      case eExcelConditionalFormattingRuleType.AboveOrEqualAverage:
+      case eExcelConditionalFormattingRuleType.BelowAverage:
+      case eExcelConditionalFormattingRuleType.BelowOrEqualAverage:
+      case eExcelConditionalFormattingRuleType.AboveStdDev:
+      case eExcelConditionalFormattingRuleType.BelowStdDev:
+        return ExcelConditionalFormattingConstants.RuleType._aboveAverage;
+
+      case eExcelConditionalFormattingRuleType.Bottom:
+      case eExcelConditionalFormattingRuleType.BottomPercent:
+      case eExcelConditionalFormattingRuleType.Top:
+      case eExcelConditionalFormattingRuleType.TopPercent:
+        return ExcelConditionalFormattingConstants.RuleType._top10;
+
+      case eExcelConditionalFormattingRuleType.Last7Days:
+      case eExcelConditionalFormattingRuleType.LastMonth:
+      case eExcelConditionalFormattingRuleType.LastWeek:
+      case eExcelConditionalFormattingRuleType.NextMonth:
+      case eExcelConditionalFormattingRuleType.NextWeek:
+      case eExcelConditionalFormattingRuleType.ThisMonth:
+      case eExcelConditionalFormattingRuleType.ThisWeek:
+      case eExcelConditionalFormattingRuleType.Today:
+      case eExcelConditionalFormattingRuleType.Tomorrow:
+      case eExcelConditionalFormattingRuleType.Yesterday:
+        return ExcelConditionalFormattingConstants.RuleType._timePeriod;
+
+      case eExcelConditionalFormattingRuleType.Between:
+      case eExcelConditionalFormattingRuleType.Equal:
+      case eExcelConditionalFormattingRuleType.GreaterThan:
+      case eExcelConditionalFormattingRuleType.GreaterThanOrEqual:
+      case eExcelConditionalFormattingRuleType.LessThan:
+      case eExcelConditionalFormattingRuleType.LessThanOrEqual:
+      case eExcelConditionalFormattingRuleType.NotBetween:
+      case eExcelConditionalFormattingRuleType.NotEqual:
+        return ExcelConditionalFormattingConstants.RuleType._cellIs;
+
+      case eExcelConditionalFormattingRuleType.ThreeIconSet:
+      case eExcelConditionalFormattingRuleType.FourIconSet:
+      case eExcelConditionalFormattingRuleType.FiveIconSet:
+        return ExcelConditionalFormattingConstants.RuleType._iconSet;
+
+      case eExcelConditionalFormattingRuleType.ThreeColorScale:
+      case eExcelConditionalFormattingRuleType.TwoColorScale:
+        return ExcelConditionalFormattingConstants.RuleType._colorScale;
+
+      case eExcelConditionalFormattingRuleType.BeginsWith:
+        return ExcelConditionalFormattingConstants.RuleType._beginsWith;
+
+      case eExcelConditionalFormattingRuleType.ContainsBlanks:
+        return ExcelConditionalFormattingConstants.RuleType._containsBlanks;
+
+      case eExcelConditionalFormattingRuleType.ContainsErrors:
+        return ExcelConditionalFormattingConstants.RuleType._containsErrors;
+
+      case eExcelConditionalFormattingRuleType.ContainsText:
+        return ExcelConditionalFormattingConstants.RuleType._containsText;
+
+      case eExcelConditionalFormattingRuleType.DuplicateValues:
+        return ExcelConditionalFormattingConstants.RuleType._duplicateValues;
+
+      case eExcelConditionalFormattingRuleType.EndsWith:
+        return ExcelConditionalFormattingConstants.RuleType._endsWith;
+
+      case eExcelConditionalFormattingRuleType.Expression:
+        return ExcelConditionalFormattingConstants.RuleType._expression;
+
+      case eExcelConditionalFormattingRuleType.NotContainsBlanks:
+        return ExcelConditionalFormattingConstants.RuleType._notContainsBlanks;
+
+      case eExcelConditionalFormattingRuleType.NotContainsErrors:
+        return ExcelConditionalFormattingConstants.RuleType._notContainsErrors;
+
+      case eExcelConditionalFormattingRuleType.NotContainsText:
+        return ExcelConditionalFormattingConstants.RuleType._notContainsText;
+
+      case eExcelConditionalFormattingRuleType.UniqueValues:
+        return ExcelConditionalFormattingConstants.RuleType._uniqueValues;
+
+      case eExcelConditionalFormattingRuleType.DataBar:
+        return ExcelConditionalFormattingConstants.RuleType._dataBar;
+    }
+
+    throw new(ExcelConditionalFormattingConstants.Errors._missingRuleType);
+  }
+
+  /// <summary>
+  /// Return cfvo §18.3.1.11 parent according to the rule type
+  /// </summary>
+  /// <param name="type"></param>
+  /// <returns></returns>
+  public static string GetCfvoParentPathByType(eExcelConditionalFormattingRuleType type) {
+    switch (type) {
+      case eExcelConditionalFormattingRuleType.TwoColorScale:
+      case eExcelConditionalFormattingRuleType.ThreeColorScale:
+        return ExcelConditionalFormattingConstants.Paths._colorScale;
+
+      case eExcelConditionalFormattingRuleType.ThreeIconSet:
+      case eExcelConditionalFormattingRuleType.FourIconSet:
+      case eExcelConditionalFormattingRuleType.FiveIconSet:
+        return ExcelConditionalFormattingConstants.RuleType._iconSet;
+
+      case eExcelConditionalFormattingRuleType.DataBar:
+        return ExcelConditionalFormattingConstants.RuleType._dataBar;
+    }
+
+    throw new(ExcelConditionalFormattingConstants.Errors._missingRuleType);
+  }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingTimePeriodType.cs b/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingTimePeriodType.cs
new file mode 100644
index 0000000..3959e61
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingTimePeriodType.cs
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-17
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Functions related to the <see cref="ExcelConditionalFormattingTimePeriodType"/>
+/// </summary>
+internal static class ExcelConditionalFormattingTimePeriodType {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="type"></param>
+  /// <returns></returns>
+  public static string GetAttributeByType(eExcelConditionalFormattingTimePeriodType type) {
+    switch (type) {
+      case eExcelConditionalFormattingTimePeriodType.Last7Days:
+        return ExcelConditionalFormattingConstants.TimePeriods._last7Days;
+
+      case eExcelConditionalFormattingTimePeriodType.LastMonth:
+        return ExcelConditionalFormattingConstants.TimePeriods._lastMonth;
+
+      case eExcelConditionalFormattingTimePeriodType.LastWeek:
+        return ExcelConditionalFormattingConstants.TimePeriods._lastWeek;
+
+      case eExcelConditionalFormattingTimePeriodType.NextMonth:
+        return ExcelConditionalFormattingConstants.TimePeriods._nextMonth;
+
+      case eExcelConditionalFormattingTimePeriodType.NextWeek:
+        return ExcelConditionalFormattingConstants.TimePeriods._nextWeek;
+
+      case eExcelConditionalFormattingTimePeriodType.ThisMonth:
+        return ExcelConditionalFormattingConstants.TimePeriods._thisMonth;
+
+      case eExcelConditionalFormattingTimePeriodType.ThisWeek:
+        return ExcelConditionalFormattingConstants.TimePeriods._thisWeek;
+
+      case eExcelConditionalFormattingTimePeriodType.Today:
+        return ExcelConditionalFormattingConstants.TimePeriods._today;
+
+      case eExcelConditionalFormattingTimePeriodType.Tomorrow:
+        return ExcelConditionalFormattingConstants.TimePeriods._tomorrow;
+
+      case eExcelConditionalFormattingTimePeriodType.Yesterday:
+        return ExcelConditionalFormattingConstants.TimePeriods._yesterday;
+    }
+
+    return string.Empty;
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="attribute"></param>
+  /// <returns></returns>
+  public static eExcelConditionalFormattingTimePeriodType GetTypeByAttribute(string attribute) {
+    switch (attribute) {
+      case ExcelConditionalFormattingConstants.TimePeriods._last7Days:
+        return eExcelConditionalFormattingTimePeriodType.Last7Days;
+
+      case ExcelConditionalFormattingConstants.TimePeriods._lastMonth:
+        return eExcelConditionalFormattingTimePeriodType.LastMonth;
+
+      case ExcelConditionalFormattingConstants.TimePeriods._lastWeek:
+        return eExcelConditionalFormattingTimePeriodType.LastWeek;
+
+      case ExcelConditionalFormattingConstants.TimePeriods._nextMonth:
+        return eExcelConditionalFormattingTimePeriodType.NextMonth;
+
+      case ExcelConditionalFormattingConstants.TimePeriods._nextWeek:
+        return eExcelConditionalFormattingTimePeriodType.NextWeek;
+
+      case ExcelConditionalFormattingConstants.TimePeriods._thisMonth:
+        return eExcelConditionalFormattingTimePeriodType.ThisMonth;
+
+      case ExcelConditionalFormattingConstants.TimePeriods._thisWeek:
+        return eExcelConditionalFormattingTimePeriodType.ThisWeek;
+
+      case ExcelConditionalFormattingConstants.TimePeriods._today:
+        return eExcelConditionalFormattingTimePeriodType.Today;
+
+      case ExcelConditionalFormattingConstants.TimePeriods._tomorrow:
+        return eExcelConditionalFormattingTimePeriodType.Tomorrow;
+
+      case ExcelConditionalFormattingConstants.TimePeriods._yesterday:
+        return eExcelConditionalFormattingTimePeriodType.Yesterday;
+    }
+
+    throw new(ExcelConditionalFormattingConstants.Errors._unexistentTimePeriodTypeAttribute);
+  }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingValueObjectType.cs b/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingValueObjectType.cs
new file mode 100644
index 0000000..221ec89
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/ExcelConditionalFormattingValueObjectType.cs
@@ -0,0 +1,199 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author          Change						                  Date
+ * ******************************************************************************
+ * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Functions related to the <see cref="ExcelConditionalFormattingColorScaleValue"/>
+/// </summary>
+internal static class ExcelConditionalFormattingValueObjectType {
+  /// <summary>
+  /// Get the sequencial order of a cfvo/color by its position.
+  /// </summary>
+  /// <param name="position"></param>
+  /// <param name="ruleType"></param>
+  /// <returns>1, 2 or 3</returns>
+  internal static int GetOrderByPosition(
+      eExcelConditionalFormattingValueObjectPosition position,
+      eExcelConditionalFormattingRuleType ruleType) {
+    switch (position) {
+      case eExcelConditionalFormattingValueObjectPosition.Low:
+        return 1;
+
+      case eExcelConditionalFormattingValueObjectPosition.Middle:
+        return 2;
+
+      case eExcelConditionalFormattingValueObjectPosition.High:
+        // Check if the rule type is TwoColorScale.
+        if (ruleType == eExcelConditionalFormattingRuleType.TwoColorScale) {
+          // There are only "Low" and "High". So "High" is the second
+          return 2;
+        }
+
+        // There are "Low", "Middle" and "High". So "High" is the third
+        return 3;
+    }
+
+    return 0;
+  }
+
+  /// <summary>
+  /// Get the CFVO type by its @type attribute
+  /// </summary>
+  /// <param name="attribute"></param>
+  /// <returns></returns>
+  public static eExcelConditionalFormattingValueObjectType GetTypeByAttrbiute(string attribute) {
+    switch (attribute) {
+      case ExcelConditionalFormattingConstants.CfvoType._min:
+        return eExcelConditionalFormattingValueObjectType.Min;
+
+      case ExcelConditionalFormattingConstants.CfvoType._max:
+        return eExcelConditionalFormattingValueObjectType.Max;
+
+      case ExcelConditionalFormattingConstants.CfvoType._num:
+        return eExcelConditionalFormattingValueObjectType.Num;
+
+      case ExcelConditionalFormattingConstants.CfvoType._formula:
+        return eExcelConditionalFormattingValueObjectType.Formula;
+
+      case ExcelConditionalFormattingConstants.CfvoType._percent:
+        return eExcelConditionalFormattingValueObjectType.Percent;
+
+      case ExcelConditionalFormattingConstants.CfvoType._percentile:
+        return eExcelConditionalFormattingValueObjectType.Percentile;
+    }
+
+    throw new(ExcelConditionalFormattingConstants.Errors._unexistentCfvoTypeAttribute);
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="position"></param>
+  ///<param name="ruleType"></param>
+  /// <param name="topNode"></param>
+  /// <param name="nameSpaceManager"></param>
+  /// <returns></returns>
+  public static XmlNode GetCfvoNodeByPosition(
+      eExcelConditionalFormattingValueObjectPosition position,
+      eExcelConditionalFormattingRuleType ruleType,
+      XmlNode topNode,
+      XmlNamespaceManager nameSpaceManager) {
+    // Get the corresponding <cfvo> node (by the position)
+    var node = topNode.SelectSingleNode(
+        string.Format(
+            "{0}[position()={1}]",
+            // {0}
+            ExcelConditionalFormattingConstants.Paths._cfvo,
+            // {1}
+            GetOrderByPosition(position, ruleType)),
+        nameSpaceManager);
+
+    if (node == null) {
+      throw new(ExcelConditionalFormattingConstants.Errors._missingCfvoNode);
+    }
+
+    return node;
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="type"></param>
+  /// <returns></returns>
+  public static string GetAttributeByType(eExcelConditionalFormattingValueObjectType type) {
+    switch (type) {
+      case eExcelConditionalFormattingValueObjectType.Min:
+        return ExcelConditionalFormattingConstants.CfvoType._min;
+
+      case eExcelConditionalFormattingValueObjectType.Max:
+        return ExcelConditionalFormattingConstants.CfvoType._max;
+
+      case eExcelConditionalFormattingValueObjectType.Num:
+        return ExcelConditionalFormattingConstants.CfvoType._num;
+
+      case eExcelConditionalFormattingValueObjectType.Formula:
+        return ExcelConditionalFormattingConstants.CfvoType._formula;
+
+      case eExcelConditionalFormattingValueObjectType.Percent:
+        return ExcelConditionalFormattingConstants.CfvoType._percent;
+
+      case eExcelConditionalFormattingValueObjectType.Percentile:
+        return ExcelConditionalFormattingConstants.CfvoType._percentile;
+    }
+
+    return string.Empty;
+  }
+
+  /// <summary>
+  /// Get the cfvo (§18.3.1.11) node parent by the rule type. Can be any of the following:
+  /// "colorScale" (§18.3.1.16); "dataBar" (§18.3.1.28); "iconSet" (§18.3.1.49)
+  /// </summary>
+  /// <param name="ruleType"></param>
+  /// <returns></returns>
+  public static string GetParentPathByRuleType(eExcelConditionalFormattingRuleType ruleType) {
+    switch (ruleType) {
+      case eExcelConditionalFormattingRuleType.TwoColorScale:
+      case eExcelConditionalFormattingRuleType.ThreeColorScale:
+        return ExcelConditionalFormattingConstants.Paths._colorScale;
+
+      case eExcelConditionalFormattingRuleType.ThreeIconSet:
+      case eExcelConditionalFormattingRuleType.FourIconSet:
+      case eExcelConditionalFormattingRuleType.FiveIconSet:
+        return ExcelConditionalFormattingConstants.Paths._iconSet;
+
+      case eExcelConditionalFormattingRuleType.DataBar:
+        return ExcelConditionalFormattingConstants.Paths._dataBar;
+    }
+
+    return string.Empty;
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="nodeType"></param>
+  /// <returns></returns>
+  public static string GetNodePathByNodeType(
+      eExcelConditionalFormattingValueObjectNodeType nodeType) {
+    switch (nodeType) {
+      case eExcelConditionalFormattingValueObjectNodeType.Cfvo:
+        return ExcelConditionalFormattingConstants.Paths._cfvo;
+
+      case eExcelConditionalFormattingValueObjectNodeType.Color:
+        return ExcelConditionalFormattingConstants.Paths._color;
+    }
+
+    return string.Empty;
+  }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/RangeConditionalFormatting.cs b/AppsheetEpplus/ConditionalFormatting/RangeConditionalFormatting.cs
new file mode 100644
index 0000000..3cb66b5
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/RangeConditionalFormatting.cs
@@ -0,0 +1,379 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author             Change                    Date
+ * ******************************************************************************
+ * Eyal Seagull       Conditional Formatting    2012-04-03
+ *******************************************************************************/
+
+using System;
+
+namespace AppsheetEpplus;
+
+internal class RangeConditionalFormatting : IRangeConditionalFormatting {
+  public ExcelWorksheet _worksheet;
+  public ExcelAddress _address;
+
+  public RangeConditionalFormatting(ExcelWorksheet worksheet, ExcelAddress address) {
+    ArgumentNullException.ThrowIfNull(worksheet);
+    ArgumentNullException.ThrowIfNull(address);
+
+    _worksheet = worksheet;
+    _address = address;
+  }
+
+  /// <summary>
+  /// Add AboveOrEqualAverage Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingAverageGroup AddAboveAverage() {
+    return _worksheet.ConditionalFormatting.AddAboveAverage(_address);
+  }
+
+  /// <summary>
+  /// Add AboveOrEqualAverage Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingAverageGroup AddAboveOrEqualAverage() {
+    return _worksheet.ConditionalFormatting.AddAboveOrEqualAverage(_address);
+  }
+
+  /// <summary>
+  /// Add BelowOrEqualAverage Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingAverageGroup AddBelowAverage() {
+    return _worksheet.ConditionalFormatting.AddBelowAverage(_address);
+  }
+
+  /// <summary>
+  /// Add BelowOrEqualAverage Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingAverageGroup AddBelowOrEqualAverage() {
+    return _worksheet.ConditionalFormatting.AddBelowOrEqualAverage(_address);
+  }
+
+  /// <summary>
+  /// Add AboveStdDev Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingStdDevGroup AddAboveStdDev() {
+    return _worksheet.ConditionalFormatting.AddAboveStdDev(_address);
+  }
+
+  /// <summary>
+  /// Add BelowStdDev Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingStdDevGroup AddBelowStdDev() {
+    return _worksheet.ConditionalFormatting.AddBelowStdDev(_address);
+  }
+
+  /// <summary>
+  /// Add Bottom Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingTopBottomGroup AddBottom() {
+    return _worksheet.ConditionalFormatting.AddBottom(_address);
+  }
+
+  /// <summary>
+  /// Add BottomPercent Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingTopBottomGroup AddBottomPercent() {
+    return _worksheet.ConditionalFormatting.AddBottomPercent(_address);
+  }
+
+  /// <summary>
+  /// Add Top Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingTopBottomGroup AddTop() {
+    return _worksheet.ConditionalFormatting.AddTop(_address);
+  }
+
+  /// <summary>
+  /// Add TopPercent Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingTopBottomGroup AddTopPercent() {
+    return _worksheet.ConditionalFormatting.AddTopPercent(_address);
+  }
+
+  /// <summary>
+  /// Add Last7Days Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingTimePeriodGroup AddLast7Days() {
+    return _worksheet.ConditionalFormatting.AddLast7Days(_address);
+  }
+
+  /// <summary>
+  /// Add LastMonth Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingTimePeriodGroup AddLastMonth() {
+    return _worksheet.ConditionalFormatting.AddLastMonth(_address);
+  }
+
+  /// <summary>
+  /// Add LastWeek Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingTimePeriodGroup AddLastWeek() {
+    return _worksheet.ConditionalFormatting.AddLastWeek(_address);
+  }
+
+  /// <summary>
+  /// Add NextMonth Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingTimePeriodGroup AddNextMonth() {
+    return _worksheet.ConditionalFormatting.AddNextMonth(_address);
+  }
+
+  /// <summary>
+  /// Add NextWeek Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingTimePeriodGroup AddNextWeek() {
+    return _worksheet.ConditionalFormatting.AddNextWeek(_address);
+  }
+
+  /// <summary>
+  /// Add ThisMonth Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingTimePeriodGroup AddThisMonth() {
+    return _worksheet.ConditionalFormatting.AddThisMonth(_address);
+  }
+
+  /// <summary>
+  /// Add ThisWeek Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingTimePeriodGroup AddThisWeek() {
+    return _worksheet.ConditionalFormatting.AddThisWeek(_address);
+  }
+
+  /// <summary>
+  /// Add Today Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingTimePeriodGroup AddToday() {
+    return _worksheet.ConditionalFormatting.AddToday(_address);
+  }
+
+  /// <summary>
+  /// Add Tomorrow Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingTimePeriodGroup AddTomorrow() {
+    return _worksheet.ConditionalFormatting.AddTomorrow(_address);
+  }
+
+  /// <summary>
+  /// Add Yesterday Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingTimePeriodGroup AddYesterday() {
+    return _worksheet.ConditionalFormatting.AddYesterday(_address);
+  }
+
+  /// <summary>
+  /// Add BeginsWith Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingBeginsWith AddBeginsWith() {
+    return _worksheet.ConditionalFormatting.AddBeginsWith(_address);
+  }
+
+  /// <summary>
+  /// Add Between Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingBetween AddBetween() {
+    return _worksheet.ConditionalFormatting.AddBetween(_address);
+  }
+
+  /// <summary>
+  /// Add ContainsBlanks Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingContainsBlanks AddContainsBlanks() {
+    return _worksheet.ConditionalFormatting.AddContainsBlanks(_address);
+  }
+
+  /// <summary>
+  /// Add ContainsErrors Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingContainsErrors AddContainsErrors() {
+    return _worksheet.ConditionalFormatting.AddContainsErrors(_address);
+  }
+
+  /// <summary>
+  /// Add ContainsText Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingContainsText AddContainsText() {
+    return _worksheet.ConditionalFormatting.AddContainsText(_address);
+  }
+
+  /// <summary>
+  /// Add DuplicateValues Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingDuplicateValues AddDuplicateValues() {
+    return _worksheet.ConditionalFormatting.AddDuplicateValues(_address);
+  }
+
+  /// <summary>
+  /// Add EndsWith Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingEndsWith AddEndsWith() {
+    return _worksheet.ConditionalFormatting.AddEndsWith(_address);
+  }
+
+  /// <summary>
+  /// Add Equal Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingEqual AddEqual() {
+    return _worksheet.ConditionalFormatting.AddEqual(_address);
+  }
+
+  /// <summary>
+  /// Add Expression Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingExpression AddExpression() {
+    return _worksheet.ConditionalFormatting.AddExpression(_address);
+  }
+
+  /// <summary>
+  /// Add GreaterThan Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingGreaterThan AddGreaterThan() {
+    return _worksheet.ConditionalFormatting.AddGreaterThan(_address);
+  }
+
+  /// <summary>
+  /// Add GreaterThanOrEqual Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingGreaterThanOrEqual AddGreaterThanOrEqual() {
+    return _worksheet.ConditionalFormatting.AddGreaterThanOrEqual(_address);
+  }
+
+  /// <summary>
+  /// Add LessThan Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingLessThan AddLessThan() {
+    return _worksheet.ConditionalFormatting.AddLessThan(_address);
+  }
+
+  /// <summary>
+  /// Add LessThanOrEqual Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingLessThanOrEqual AddLessThanOrEqual() {
+    return _worksheet.ConditionalFormatting.AddLessThanOrEqual(_address);
+  }
+
+  /// <summary>
+  /// Add NotBetween Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingNotBetween AddNotBetween() {
+    return _worksheet.ConditionalFormatting.AddNotBetween(_address);
+  }
+
+  /// <summary>
+  /// Add NotContainsBlanks Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingNotContainsBlanks AddNotContainsBlanks() {
+    return _worksheet.ConditionalFormatting.AddNotContainsBlanks(_address);
+  }
+
+  /// <summary>
+  /// Add NotContainsErrors Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingNotContainsErrors AddNotContainsErrors() {
+    return _worksheet.ConditionalFormatting.AddNotContainsErrors(_address);
+  }
+
+  /// <summary>
+  /// Add NotContainsText Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingNotContainsText AddNotContainsText() {
+    return _worksheet.ConditionalFormatting.AddNotContainsText(_address);
+  }
+
+  /// <summary>
+  /// Add NotEqual Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingNotEqual AddNotEqual() {
+    return _worksheet.ConditionalFormatting.AddNotEqual(_address);
+  }
+
+  /// <summary>
+  /// Add UniqueValues Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingUniqueValues AddUniqueValues() {
+    return _worksheet.ConditionalFormatting.AddUniqueValues(_address);
+  }
+
+  /// <summary>
+  /// Add ThreeColorScale Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingThreeColorScale AddThreeColorScale() {
+    return (IExcelConditionalFormattingThreeColorScale)(_worksheet.ConditionalFormatting.AddRule(
+        eExcelConditionalFormattingRuleType.ThreeColorScale,
+        _address));
+  }
+
+  /// <summary>
+  /// Add TwoColorScale Conditional Formatting
+  /// </summary>
+  ///  <returns></returns>
+  public IExcelConditionalFormattingTwoColorScale AddTwoColorScale() {
+    return (IExcelConditionalFormattingTwoColorScale)(_worksheet.ConditionalFormatting.AddRule(
+        eExcelConditionalFormattingRuleType.TwoColorScale,
+        _address));
+  }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveAverage.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveAverage.cs
new file mode 100644
index 0000000..2ab1df8
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveAverage.cs
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingAboveAverage
+/// </summary>
+public class ExcelConditionalFormattingAboveAverage : ExcelConditionalFormattingAverageGroup {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingAboveAverage(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.AboveAverage,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      AboveAverage = true;
+      EqualAverage = false;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingAboveAverage(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingAboveAverage(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveOrEqualAverage.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveOrEqualAverage.cs
new file mode 100644
index 0000000..d8e97db
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveOrEqualAverage.cs
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingAboveOrEqualAverage
+/// </summary>
+public class ExcelConditionalFormattingAboveOrEqualAverage
+    : ExcelConditionalFormattingAverageGroup {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingAboveOrEqualAverage(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.AboveOrEqualAverage,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      AboveAverage = true;
+      EqualAverage = true;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingAboveOrEqualAverage(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingAboveOrEqualAverage(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveStdDev.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveStdDev.cs
new file mode 100644
index 0000000..fe944f7
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveStdDev.cs
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingAboveStdDev
+/// </summary>
+public class ExcelConditionalFormattingAboveStdDev
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingStdDevGroup {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingAboveStdDev(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.AboveStdDev,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      AboveAverage = true;
+      StdDev = 1;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingAboveStdDev(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingAboveStdDev(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingAverageGroup.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingAverageGroup.cs
new file mode 100644
index 0000000..325ea97
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingAverageGroup.cs
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingAverageGroup
+/// </summary>
+public class ExcelConditionalFormattingAverageGroup
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingAverageGroup {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="type"></param>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingAverageGroup(
+      eExcelConditionalFormattingRuleType type,
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          type,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  ///<param name="type"></param>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingAverageGroup(
+      eExcelConditionalFormattingRuleType type,
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(type, address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  ///<param name="type"></param>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingAverageGroup(
+      eExcelConditionalFormattingRuleType type,
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(type, address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingBeginsWith.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingBeginsWith.cs
new file mode 100644
index 0000000..12e10eb
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingBeginsWith.cs
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingBeginsWith
+/// </summary>
+public class ExcelConditionalFormattingBeginsWith
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingBeginsWith {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingBeginsWith(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.BeginsWith,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      Operator = eExcelConditionalFormattingOperatorType.BeginsWith;
+      Text = string.Empty;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingBeginsWith(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingBeginsWith(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+
+  /// <summary>
+  /// The text to search in the beginning of the cell
+  /// </summary>
+  public string Text {
+    get => GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._textAttribute);
+    set {
+      SetXmlNodeString(ExcelConditionalFormattingConstants.Paths._textAttribute, value);
+
+      Formula = string.Format(
+          "LEFT({0},LEN(\"{1}\"))=\"{1}\"",
+          Address.Start.Address,
+          value.Replace("\"", "\"\""));
+    }
+  }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowAverage.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowAverage.cs
new file mode 100644
index 0000000..83fc5d5
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowAverage.cs
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingBelowAverage
+/// </summary>
+public class ExcelConditionalFormattingBelowAverage : ExcelConditionalFormattingAverageGroup {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingBelowAverage(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.BelowAverage,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      AboveAverage = false;
+      EqualAverage = false;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingBelowAverage(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingBelowAverage(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowOrEqualAverage.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowOrEqualAverage.cs
new file mode 100644
index 0000000..6f8e527
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowOrEqualAverage.cs
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingBelowOrEqualAverage
+/// </summary>
+public class ExcelConditionalFormattingBelowOrEqualAverage
+    : ExcelConditionalFormattingAverageGroup {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingBelowOrEqualAverage(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.BelowOrEqualAverage,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      AboveAverage = false;
+      EqualAverage = true;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingBelowOrEqualAverage(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingBelowOrEqualAverage(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowStdDev.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowStdDev.cs
new file mode 100644
index 0000000..7842e62
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowStdDev.cs
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingBelowStdDev
+/// </summary>
+public class ExcelConditionalFormattingBelowStdDev
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingStdDevGroup {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingBelowStdDev(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.BelowStdDev,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      AboveAverage = false;
+      StdDev = 1;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingBelowStdDev(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingBelowStdDev(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingBetween.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingBetween.cs
new file mode 100644
index 0000000..ecb6a29
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingBetween.cs
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingBetween
+/// </summary>
+public class ExcelConditionalFormattingBetween
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingBetween {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingBetween(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.Between,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      Operator = eExcelConditionalFormattingOperatorType.Between;
+      Formula = string.Empty;
+      Formula2 = string.Empty;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingBetween(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingBetween(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingBottom.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingBottom.cs
new file mode 100644
index 0000000..41156e1
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingBottom.cs
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingBottom
+/// </summary>
+public class ExcelConditionalFormattingBottom
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingTopBottomGroup {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingBottom(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.Bottom,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      Bottom = true;
+      Percent = false;
+      Rank = 10; // Last 10 values
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingBottom(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingBottom(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingBottomPercent.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingBottomPercent.cs
new file mode 100644
index 0000000..9f3fe2a
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingBottomPercent.cs
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingBottomPercent
+/// </summary>
+public class ExcelConditionalFormattingBottomPercent
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingTopBottomGroup {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingBottomPercent(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.BottomPercent,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      Bottom = true;
+      Percent = true;
+      Rank = 10; // Last 10 percent
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingBottomPercent(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingBottomPercent(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsBlanks.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsBlanks.cs
new file mode 100644
index 0000000..86c74f4
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsBlanks.cs
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingContainsBlanks
+/// </summary>
+public class ExcelConditionalFormattingContainsBlanks
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingContainsBlanks {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingContainsBlanks(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.ContainsBlanks,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      Formula = string.Format("LEN(TRIM({0}))=0", Address.Start.Address);
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingContainsBlanks(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingContainsBlanks(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsErrors.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsErrors.cs
new file mode 100644
index 0000000..a3c7287
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsErrors.cs
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingContainsErrors
+/// </summary>
+public class ExcelConditionalFormattingContainsErrors
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingContainsErrors {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingContainsErrors(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.ContainsErrors,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      Formula = string.Format("ISERROR({0})", Address.Start.Address);
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingContainsErrors(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingContainsErrors(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsText.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsText.cs
new file mode 100644
index 0000000..80f0d0a
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsText.cs
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingContainsText
+/// </summary>
+public class ExcelConditionalFormattingContainsText
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingContainsText {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingContainsText(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.ContainsText,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      Operator = eExcelConditionalFormattingOperatorType.ContainsText;
+      Text = string.Empty;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingContainsText(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingContainsText(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+
+  /// <summary>
+  /// The text to search inside the cell
+  /// </summary>
+  public string Text {
+    get => GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._textAttribute);
+    set {
+      SetXmlNodeString(ExcelConditionalFormattingConstants.Paths._textAttribute, value);
+
+      Formula = string.Format(
+          "NOT(ISERROR(SEARCH(\"{1}\",{0})))",
+          Address.Start.Address,
+          value.Replace("\"", "\"\""));
+    }
+  }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingDataBar.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingDataBar.cs
new file mode 100644
index 0000000..fc9aca6
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingDataBar.cs
@@ -0,0 +1,155 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Collections.Immutable;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Databar
+/// </summary>
+public class ExcelConditionalFormattingDataBar
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingDataBarGroup {
+  protected override ImmutableArray<string> SchemaNodeOrder { get; } = ["cfvo", "color"];
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="type"></param>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingDataBar(
+      eExcelConditionalFormattingRuleType type,
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          type,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    //Create the <dataBar> node inside the <cfRule> node
+    if (itemElementNode != null && itemElementNode.HasChildNodes) {
+      bool high = false;
+      foreach (XmlNode node in itemElementNode.SelectNodes("d:dataBar/d:cfvo", NameSpaceManager)) {
+        if (high == false) {
+          LowValue = new(type, address, worksheet, node, namespaceManager);
+          high = true;
+        } else {
+          HighValue = new(type, address, worksheet, node, namespaceManager);
+        }
+      }
+    } else {
+      var iconSetNode = CreateComplexNode(Node, ExcelConditionalFormattingConstants.Paths._dataBar);
+
+      var lowNode = iconSetNode.OwnerDocument.CreateElement(
+          ExcelConditionalFormattingConstants.Paths._cfvo,
+          ExcelPackage._schemaMain);
+      iconSetNode.AppendChild(lowNode);
+      LowValue = new(
+          eExcelConditionalFormattingValueObjectType.Min,
+          0,
+          "",
+          eExcelConditionalFormattingRuleType.DataBar,
+          address,
+          priority,
+          worksheet,
+          lowNode,
+          namespaceManager);
+
+      var highNode = iconSetNode.OwnerDocument.CreateElement(
+          ExcelConditionalFormattingConstants.Paths._cfvo,
+          ExcelPackage._schemaMain);
+      iconSetNode.AppendChild(highNode);
+      HighValue = new(
+          eExcelConditionalFormattingValueObjectType.Max,
+          0,
+          "",
+          eExcelConditionalFormattingRuleType.DataBar,
+          address,
+          priority,
+          worksheet,
+          highNode,
+          namespaceManager);
+    }
+    Type = type;
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="type"></param>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingDataBar(
+      eExcelConditionalFormattingRuleType type,
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(type, address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="type"></param>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingDataBar(
+      eExcelConditionalFormattingRuleType type,
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(type, address, priority, worksheet, null, null) {}
+
+  private const string _showValuePath = "d:dataBar/@showValue";
+
+  public bool ShowValue {
+    get => GetXmlNodeBool(_showValuePath, true);
+    set => SetXmlNodeBool(_showValuePath, value);
+  }
+
+  public ExcelConditionalFormattingIconDataBarValue LowValue { get; internal set; }
+
+  public ExcelConditionalFormattingIconDataBarValue HighValue { get; internal set; }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingDuplicateValues.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingDuplicateValues.cs
new file mode 100644
index 0000000..b73f3a7
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingDuplicateValues.cs
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingDuplicateValues
+/// </summary>
+public class ExcelConditionalFormattingDuplicateValues
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingDuplicateValues {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingDuplicateValues(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.DuplicateValues,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingDuplicateValues(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingDuplicateValues(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingEndsWith.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingEndsWith.cs
new file mode 100644
index 0000000..97ea0df
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingEndsWith.cs
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingEndsWith
+/// </summary>
+public class ExcelConditionalFormattingEndsWith
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingEndsWith {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingEndsWith(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.EndsWith,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      Operator = eExcelConditionalFormattingOperatorType.EndsWith;
+      Text = string.Empty;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingEndsWith(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingEndsWith(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+
+  /// <summary>
+  /// The text to search in the end of the cell
+  /// </summary>
+  public string Text {
+    get => GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._textAttribute);
+    set {
+      SetXmlNodeString(ExcelConditionalFormattingConstants.Paths._textAttribute, value);
+
+      Formula = string.Format(
+          "RIGHT({0},LEN(\"{1}\"))=\"{1}\"",
+          Address.Start.Address,
+          value.Replace("\"", "\"\""));
+    }
+  }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingEqual.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingEqual.cs
new file mode 100644
index 0000000..7e757da
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingEqual.cs
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingEqual
+/// </summary>
+public class ExcelConditionalFormattingEqual
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingEqual {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingEqual(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.Equal,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      Operator = eExcelConditionalFormattingOperatorType.Equal;
+      Formula = string.Empty;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingEqual(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingEqual(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingExpression.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingExpression.cs
new file mode 100644
index 0000000..7418688
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingExpression.cs
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingExpression
+/// </summary>
+public class ExcelConditionalFormattingExpression
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingExpression {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingExpression(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.Expression,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      Formula = string.Empty;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingExpression(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingExpression(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingFiveIconSet.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingFiveIconSet.cs
new file mode 100644
index 0000000..62bdb02
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingFiveIconSet.cs
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingThreeIconSet
+/// </summary>
+public class ExcelConditionalFormattingFiveIconSet
+    : ExcelConditionalFormattingIconSetBase<eExcelconditionalFormatting5IconsSetType>,
+      IExcelConditionalFormattingFiveIconSet {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingFiveIconSet(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.FiveIconSet,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode != null && itemElementNode.HasChildNodes) {
+      XmlNode iconNode4 = TopNode.SelectSingleNode(
+          "d:iconSet/d:cfvo[position()=4]",
+          NameSpaceManager);
+      Icon4 = new(
+          eExcelConditionalFormattingRuleType.FiveIconSet,
+          address,
+          worksheet,
+          iconNode4,
+          namespaceManager);
+
+      XmlNode iconNode5 = TopNode.SelectSingleNode(
+          "d:iconSet/d:cfvo[position()=5]",
+          NameSpaceManager);
+      Icon5 = new(
+          eExcelConditionalFormattingRuleType.FiveIconSet,
+          address,
+          worksheet,
+          iconNode5,
+          namespaceManager);
+    } else {
+      XmlNode iconSetNode = TopNode.SelectSingleNode("d:iconSet", NameSpaceManager);
+      var iconNode4 = iconSetNode.OwnerDocument.CreateElement(
+          ExcelConditionalFormattingConstants.Paths._cfvo,
+          ExcelPackage._schemaMain);
+      iconSetNode.AppendChild(iconNode4);
+
+      Icon4 = new(
+          eExcelConditionalFormattingValueObjectType.Percent,
+          60,
+          "",
+          eExcelConditionalFormattingRuleType.ThreeIconSet,
+          address,
+          priority,
+          worksheet,
+          iconNode4,
+          namespaceManager);
+
+      var iconNode5 = iconSetNode.OwnerDocument.CreateElement(
+          ExcelConditionalFormattingConstants.Paths._cfvo,
+          ExcelPackage._schemaMain);
+      iconSetNode.AppendChild(iconNode5);
+
+      Icon5 = new(
+          eExcelConditionalFormattingValueObjectType.Percent,
+          80,
+          "",
+          eExcelConditionalFormattingRuleType.ThreeIconSet,
+          address,
+          priority,
+          worksheet,
+          iconNode5,
+          namespaceManager);
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingFiveIconSet(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingFiveIconSet(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+
+  public ExcelConditionalFormattingIconDataBarValue Icon5 { get; internal set; }
+
+  public ExcelConditionalFormattingIconDataBarValue Icon4 { get; internal set; }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingFourIconSet.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingFourIconSet.cs
new file mode 100644
index 0000000..f65f105
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingFourIconSet.cs
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingThreeIconSet
+/// </summary>
+public class ExcelConditionalFormattingFourIconSet
+    : ExcelConditionalFormattingIconSetBase<eExcelconditionalFormatting4IconsSetType>,
+      IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting4IconsSetType> {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingFourIconSet(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.FourIconSet,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode != null && itemElementNode.HasChildNodes) {
+      XmlNode iconNode4 = TopNode.SelectSingleNode(
+          "d:iconSet/d:cfvo[position()=4]",
+          NameSpaceManager);
+      Icon4 = new(
+          eExcelConditionalFormattingRuleType.FourIconSet,
+          address,
+          worksheet,
+          iconNode4,
+          namespaceManager);
+    } else {
+      XmlNode iconSetNode = TopNode.SelectSingleNode("d:iconSet", NameSpaceManager);
+      var iconNode4 = iconSetNode.OwnerDocument.CreateElement(
+          ExcelConditionalFormattingConstants.Paths._cfvo,
+          ExcelPackage._schemaMain);
+      iconSetNode.AppendChild(iconNode4);
+
+      Icon4 = new(
+          eExcelConditionalFormattingValueObjectType.Percent,
+          75,
+          "",
+          eExcelConditionalFormattingRuleType.ThreeIconSet,
+          address,
+          priority,
+          worksheet,
+          iconNode4,
+          namespaceManager);
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingFourIconSet(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingFourIconSet(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+
+  public ExcelConditionalFormattingIconDataBarValue Icon4 { get; internal set; }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThan.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThan.cs
new file mode 100644
index 0000000..a60f7bc
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThan.cs
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingGreaterThan
+/// </summary>
+public class ExcelConditionalFormattingGreaterThan
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingGreaterThan {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingGreaterThan(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.GreaterThan,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      Operator = eExcelConditionalFormattingOperatorType.GreaterThan;
+      Formula = string.Empty;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingGreaterThan(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingGreaterThan(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThanOrEqual.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThanOrEqual.cs
new file mode 100644
index 0000000..bb47a80
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThanOrEqual.cs
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingGreaterThanOrEqual
+/// </summary>
+public class ExcelConditionalFormattingGreaterThanOrEqual
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingGreaterThanOrEqual {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingGreaterThanOrEqual(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.GreaterThanOrEqual,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      Operator = eExcelConditionalFormattingOperatorType.GreaterThanOrEqual;
+      Formula = string.Empty;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingGreaterThanOrEqual(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingGreaterThanOrEqual(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingLast7Days.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingLast7Days.cs
new file mode 100644
index 0000000..6fc14d8
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingLast7Days.cs
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingLast7Days
+/// </summary>
+public class ExcelConditionalFormattingLast7Days : ExcelConditionalFormattingTimePeriodGroup {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingLast7Days(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.Last7Days,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      TimePeriod = eExcelConditionalFormattingTimePeriodType.Last7Days;
+      Formula = string.Format(
+          "AND(TODAY()-FLOOR({0},1)<=6,FLOOR({0},1)<=TODAY())",
+          Address.Start.Address);
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingLast7Days(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingLast7Days(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingLastMonth.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingLastMonth.cs
new file mode 100644
index 0000000..f0d16db
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingLastMonth.cs
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingLastMonth
+/// </summary>
+public class ExcelConditionalFormattingLastMonth : ExcelConditionalFormattingTimePeriodGroup {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingLastMonth(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.LastMonth,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      TimePeriod = eExcelConditionalFormattingTimePeriodType.LastMonth;
+      Formula = string.Format(
+          "AND(MONTH({0})=MONTH(EDATE(TODAY(),0-1)),YEAR({0})=YEAR(EDATE(TODAY(),0-1)))",
+          Address.Start.Address);
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingLastMonth(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingLastMonth(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingLastWeek.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingLastWeek.cs
new file mode 100644
index 0000000..be82aea
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingLastWeek.cs
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingLastWeek
+/// </summary>
+public class ExcelConditionalFormattingLastWeek : ExcelConditionalFormattingTimePeriodGroup {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingLastWeek(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.LastWeek,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      TimePeriod = eExcelConditionalFormattingTimePeriodType.LastWeek;
+      Formula = string.Format(
+          "AND(TODAY()-ROUNDDOWN({0},0)>=(WEEKDAY(TODAY())),TODAY()-ROUNDDOWN({0},0)<(WEEKDAY(TODAY())+7))",
+          Address.Start.Address);
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingLastWeek(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingLastWeek(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThan.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThan.cs
new file mode 100644
index 0000000..6d4e97e
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThan.cs
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingLessThan
+/// </summary>
+public class ExcelConditionalFormattingLessThan
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingLessThan {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingLessThan(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.LessThan,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      Operator = eExcelConditionalFormattingOperatorType.LessThan;
+      Formula = string.Empty;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingLessThan(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingLessThan(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThanOrEqual.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThanOrEqual.cs
new file mode 100644
index 0000000..f4ff6d8
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThanOrEqual.cs
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingLessThanOrEqual
+/// </summary>
+public class ExcelConditionalFormattingLessThanOrEqual
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingLessThanOrEqual {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingLessThanOrEqual(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.LessThanOrEqual,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      Operator = eExcelConditionalFormattingOperatorType.LessThanOrEqual;
+      Formula = string.Empty;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingLessThanOrEqual(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingLessThanOrEqual(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingNextMonth.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingNextMonth.cs
new file mode 100644
index 0000000..0b5dec1
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingNextMonth.cs
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingNextMonth
+/// </summary>
+public class ExcelConditionalFormattingNextMonth : ExcelConditionalFormattingTimePeriodGroup {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingNextMonth(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.NextMonth,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      TimePeriod = eExcelConditionalFormattingTimePeriodType.NextMonth;
+      Formula = string.Format(
+          "AND(MONTH({0})=MONTH(EDATE(TODAY(),0+1)), YEAR({0})=YEAR(EDATE(TODAY(),0+1)))",
+          Address.Start.Address);
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingNextMonth(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingNextMonth(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingNextWeek.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingNextWeek.cs
new file mode 100644
index 0000000..a2e6ffd
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingNextWeek.cs
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingNextWeek
+/// </summary>
+public class ExcelConditionalFormattingNextWeek : ExcelConditionalFormattingTimePeriodGroup {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingNextWeek(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.NextWeek,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      TimePeriod = eExcelConditionalFormattingTimePeriodType.NextWeek;
+      Formula = string.Format(
+          "AND(ROUNDDOWN({0},0)-TODAY()>(7-WEEKDAY(TODAY())),ROUNDDOWN({0},0)-TODAY()<(15-WEEKDAY(TODAY())))",
+          Address.Start.Address);
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingNextWeek(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingNextWeek(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotBetween.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotBetween.cs
new file mode 100644
index 0000000..011c766
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotBetween.cs
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingNotBetween
+/// </summary>
+public class ExcelConditionalFormattingNotBetween
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingNotBetween {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingNotBetween(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.NotBetween,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      Operator = eExcelConditionalFormattingOperatorType.NotBetween;
+      Formula = string.Empty;
+      Formula2 = string.Empty;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingNotBetween(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingNotBetween(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsBlanks.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsBlanks.cs
new file mode 100644
index 0000000..aafe501
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsBlanks.cs
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingNotContainsBlanks
+/// </summary>
+public class ExcelConditionalFormattingNotContainsBlanks
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingNotContainsBlanks {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingNotContainsBlanks(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.NotContainsBlanks,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      Formula = string.Format("LEN(TRIM({0}))>0", Address.Start.Address);
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingNotContainsBlanks(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingNotContainsBlanks(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsErrors.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsErrors.cs
new file mode 100644
index 0000000..9058785
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsErrors.cs
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingNotContainsErrors
+/// </summary>
+public class ExcelConditionalFormattingNotContainsErrors
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingNotContainsErrors {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingNotContainsErrors(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.NotContainsErrors,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      Formula = string.Format("NOT(ISERROR({0}))", Address.Start.Address);
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingNotContainsErrors(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingNotContainsErrors(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsText.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsText.cs
new file mode 100644
index 0000000..97f0857
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsText.cs
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingNotContainsText
+/// </summary>
+public class ExcelConditionalFormattingNotContainsText
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingNotContainsText {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingNotContainsText(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.NotContainsText,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      Operator = eExcelConditionalFormattingOperatorType.NotContains;
+      Text = string.Empty;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingNotContainsText(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingNotContainsText(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+
+  /// <summary>
+  /// The text to search inside the cell
+  /// </summary>
+  public string Text {
+    get => GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._textAttribute);
+    set {
+      SetXmlNodeString(ExcelConditionalFormattingConstants.Paths._textAttribute, value);
+
+      Formula = string.Format(
+          "ISERROR(SEARCH(\"{1}\",{0}))",
+          Address.Start.Address,
+          value.Replace("\"", "\"\""));
+    }
+  }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotEqual.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotEqual.cs
new file mode 100644
index 0000000..65c1c72
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotEqual.cs
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingNotEqual
+/// </summary>
+public class ExcelConditionalFormattingNotEqual
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingNotEqual {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingNotEqual(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.NotEqual,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      Operator = eExcelConditionalFormattingOperatorType.NotEqual;
+      Formula = string.Empty;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingNotEqual(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingNotEqual(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingRule.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingRule.cs
new file mode 100644
index 0000000..078f35c
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingRule.cs
@@ -0,0 +1,489 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System;
+using System.Collections.Immutable;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+///
+/// </summary>
+public abstract class ExcelConditionalFormattingRule : XmlHelper, IExcelConditionalFormattingRule {
+  private eExcelConditionalFormattingRuleType? _type;
+  private readonly ExcelWorksheet _worksheet;
+
+  /// <summary>
+  /// Sinalize that we are in a Cnaging Priorities opeartion so that we won't enter
+  /// a recursive loop.
+  /// </summary>
+  private static bool _changingPriority;
+
+  protected override ImmutableArray<string> SchemaNodeOrder =>
+    ExcelWorksheet.WorksheetSchemaNodeOrder;
+
+  /// <summary>
+  /// Initialize the <see cref="ExcelConditionalFormattingRule"/>
+  /// </summary>
+  /// <param name="type"></param>
+  /// <param name="address"></param>
+  /// <param name="priority">Used also as the cfRule unique key</param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingRule(
+      eExcelConditionalFormattingRuleType type,
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(namespaceManager, itemElementNode) {
+    ArgumentNullException.ThrowIfNull(address);
+    ArgumentOutOfRangeException.ThrowIfLessThan(priority, 1);
+    ArgumentNullException.ThrowIfNull(worksheet);
+
+    _type = type;
+    _worksheet = worksheet;
+
+    if (itemElementNode == null) {
+      // Create/Get the <cfRule> inside <conditionalFormatting>
+      itemElementNode = CreateComplexNode(
+          _worksheet.WorksheetXml.DocumentElement,
+          string.Format(
+              "{0}[{1}='{2}']/{1}='{2}'/{3}[{4}='{5}']/{4}='{5}'",
+              //{0}
+              ExcelConditionalFormattingConstants.Paths._conditionalFormatting,
+              // {1}
+              ExcelConditionalFormattingConstants.Paths._sqrefAttribute,
+              // {2}
+              address.AddressSpaceSeparated, //CF node don't what to have comma between multi addresses, use space instead.
+              // {3}
+              ExcelConditionalFormattingConstants.Paths._cfRule,
+              //{4}
+              ExcelConditionalFormattingConstants.Paths._priorityAttribute,
+              //{5}
+              priority));
+    }
+
+    // Point to <cfRule>
+    TopNode = itemElementNode;
+
+    Address = address;
+    Priority = priority;
+    Type = type;
+    if (DxfId >= 0) {
+      worksheet.Workbook.Styles.Dxfs[DxfId].AllowChange = true; //This Id is referenced by CF, so we can use it when we save.
+      _style = worksheet.Workbook.Styles.Dxfs[DxfId].Clone(); //Clone, so it can be altered without effecting other dxf styles
+    }
+  }
+
+  /// <summary>
+  /// Initialize the <see cref="ExcelConditionalFormattingRule"/>
+  /// </summary>
+  /// <param name="type"></param>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingRule(
+      eExcelConditionalFormattingRuleType type,
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNamespaceManager namespaceManager)
+      : this(type, address, priority, worksheet, null, namespaceManager) {}
+
+  /// <summary>
+  /// Get the &lt;cfRule&gt; node
+  /// </summary>
+  public XmlNode Node => TopNode;
+
+  /// <summary>
+  /// Address of the conditional formatting rule
+  /// </summary>
+  /// <remarks>
+  /// The address is stores in a parent node called &lt;conditionalFormatting&gt; in the
+  /// @sqref attribute. Excel groups rules that have the same address inside one node.
+  /// </remarks>
+  public ExcelAddress Address {
+    get =>
+      new(Node.ParentNode.Attributes[ExcelConditionalFormattingConstants.Attributes._sqref].Value);
+    set {
+      // Check if the address is to be changed
+      if (Address.Address != value.Address) {
+        // Save the old parente node
+        XmlNode oldNode = Node;
+        XmlNode oldParentNode = Node.ParentNode;
+
+        // Create/Get the new <conditionalFormatting> parent node
+        XmlNode newParentNode = CreateComplexNode(
+            _worksheet.WorksheetXml.DocumentElement,
+            string.Format(
+                "{0}[{1}='{2}']/{1}='{2}'",
+                //{0}
+                ExcelConditionalFormattingConstants.Paths._conditionalFormatting,
+                // {1}
+                ExcelConditionalFormattingConstants.Paths._sqrefAttribute,
+                // {2}
+                value.AddressSpaceSeparated));
+
+        // Move the <cfRule> node to the new <conditionalFormatting> parent node
+        TopNode = newParentNode.AppendChild(Node);
+
+        // Check if the old <conditionalFormatting> parent node has <cfRule> node inside it
+        if (!oldParentNode.HasChildNodes) {
+          // Remove the old parent node
+          oldParentNode.ParentNode.RemoveChild(oldParentNode);
+        }
+      }
+    }
+  }
+
+  /// <summary>
+  /// Type of conditional formatting rule. ST_CfType §18.18.12.
+  /// </summary>
+  public eExcelConditionalFormattingRuleType Type {
+    get {
+      // Transform the @type attribute to EPPlus Rule Type (slighty diferente)
+      if (_type == null) {
+        _type = ExcelConditionalFormattingRuleType.GetTypeByAttrbiute(
+            GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._typeAttribute),
+            TopNode,
+            _worksheet.NameSpaceManager);
+      }
+      return (eExcelConditionalFormattingRuleType)_type;
+    }
+    internal set {
+      _type = value;
+      // Transform the EPPlus Rule Type to @type attribute (slighty diferente)
+      SetXmlNodeString(
+          ExcelConditionalFormattingConstants.Paths._typeAttribute,
+          ExcelConditionalFormattingRuleType.GetAttributeByType(value),
+          true);
+    }
+  }
+
+  /// <summary>
+  /// The priority of this conditional formatting rule. This value is used to determine
+  /// which format should be evaluated and rendered. Lower numeric values are higher
+  /// priority than higher numeric values, where 1 is the highest priority.
+  /// </summary>
+  public int Priority {
+    get => GetXmlNodeInt(ExcelConditionalFormattingConstants.Paths._priorityAttribute);
+    set {
+      // Save the current CF rule priority
+      int priority = Priority;
+
+      // Check if the @priority is to be changed
+      if (priority != value) {
+        // Check if we are not already inside a "Change Priority" operation
+        if (!_changingPriority) {
+          if (value < 1) {
+            throw new IndexOutOfRangeException(
+                ExcelConditionalFormattingConstants.Errors._invalidPriority);
+          }
+
+          // Sinalize that we are already changing cfRules priorities
+          _changingPriority = true;
+
+          // Check if we lowered the priority
+          if (priority > value) {
+            for (int i = priority - 1; i >= value; i--) {
+              var cfRule = _worksheet.ConditionalFormatting.RulesByPriority(i);
+
+              if (cfRule != null) {
+                cfRule.Priority++;
+              }
+            }
+          } else {
+            for (int i = priority + 1; i <= value; i++) {
+              var cfRule = _worksheet.ConditionalFormatting.RulesByPriority(i);
+
+              if (cfRule != null) {
+                cfRule.Priority--;
+              }
+            }
+          }
+
+          // Sinalize that we are no longer changing cfRules priorities
+          _changingPriority = false;
+        }
+
+        // Change the priority in the XML
+        SetXmlNodeString(
+            ExcelConditionalFormattingConstants.Paths._priorityAttribute,
+            value.ToString(),
+            true);
+      }
+    }
+  }
+
+  /// <summary>
+  /// If this flag is true, no rules with lower priority shall be applied over this rule,
+  /// when this rule evaluates to true.
+  /// </summary>
+  public bool StopIfTrue {
+    get => GetXmlNodeBool(ExcelConditionalFormattingConstants.Paths._stopIfTrueAttribute);
+    set =>
+      SetXmlNodeString(
+          ExcelConditionalFormattingConstants.Paths._stopIfTrueAttribute,
+          value ? "1" : string.Empty,
+          true);
+  }
+
+  /// <summary>
+  /// DxfId Style Attribute
+  /// </summary>
+  internal int DxfId {
+    get => GetXmlNodeInt(ExcelConditionalFormattingConstants.Paths._dxfIdAttribute);
+    set =>
+      SetXmlNodeString(
+          ExcelConditionalFormattingConstants.Paths._dxfIdAttribute,
+          (value == int.MinValue) ? string.Empty : value.ToString(),
+          true);
+  }
+
+  internal ExcelDxfStyleConditionalFormatting _style;
+
+  public ExcelDxfStyleConditionalFormatting Style {
+    get {
+      if (_style == null) {
+        _style = new(NameSpaceManager, null, _worksheet.Workbook.Styles);
+      }
+      return _style;
+    }
+  }
+
+  /// <summary>
+  /// StdDev (zero is not allowed and will be converted to 1)
+  /// </summary>
+  public UInt16 StdDev {
+    get =>
+      Convert.ToUInt16(GetXmlNodeInt(ExcelConditionalFormattingConstants.Paths._stdDevAttribute));
+    set =>
+      SetXmlNodeString(
+          ExcelConditionalFormattingConstants.Paths._stdDevAttribute,
+          (value == 0) ? "1" : value.ToString(),
+          true);
+  }
+
+  /// <summary>
+  /// Rank (zero is not allowed and will be converted to 1)
+  /// </summary>
+  public UInt16 Rank {
+    get =>
+      Convert.ToUInt16(GetXmlNodeInt(ExcelConditionalFormattingConstants.Paths._rankAttribute));
+    set =>
+      SetXmlNodeString(
+          ExcelConditionalFormattingConstants.Paths._rankAttribute,
+          (value == 0) ? "1" : value.ToString(),
+          true);
+  }
+
+  /// <summary>
+  /// AboveAverage
+  /// </summary>
+  internal protected bool? AboveAverage {
+    get {
+      bool? aboveAverage = GetXmlNodeBoolNullable(
+          ExcelConditionalFormattingConstants.Paths._aboveAverageAttribute);
+
+      // Above Avarege if TRUE or if attribute does not exists
+      return (aboveAverage == true) || (aboveAverage == null);
+    }
+    set {
+      string aboveAverageValue = string.Empty;
+
+      // Only the types that needs the @AboveAverage
+      if ((_type == eExcelConditionalFormattingRuleType.BelowAverage)
+          || (_type == eExcelConditionalFormattingRuleType.BelowOrEqualAverage)
+          || (_type == eExcelConditionalFormattingRuleType.BelowStdDev)) {
+        aboveAverageValue = "0";
+      }
+
+      SetXmlNodeString(
+          ExcelConditionalFormattingConstants.Paths._aboveAverageAttribute,
+          aboveAverageValue,
+          true);
+    }
+  }
+
+  /// <summary>
+  /// EqualAverage
+  /// </summary>
+  internal protected bool? EqualAverage {
+    get {
+      bool? equalAverage = GetXmlNodeBoolNullable(
+          ExcelConditionalFormattingConstants.Paths._equalAverageAttribute);
+
+      // Equal Avarege only if TRUE
+      return (equalAverage == true);
+    }
+    set {
+      string equalAverageValue = string.Empty;
+
+      // Only the types that needs the @EqualAverage
+      if ((_type == eExcelConditionalFormattingRuleType.AboveOrEqualAverage)
+          || (_type == eExcelConditionalFormattingRuleType.BelowOrEqualAverage)) {
+        equalAverageValue = "1";
+      }
+
+      SetXmlNodeString(
+          ExcelConditionalFormattingConstants.Paths._equalAverageAttribute,
+          equalAverageValue,
+          true);
+    }
+  }
+
+  /// <summary>
+  /// Bottom attribute
+  /// </summary>
+  internal protected bool? Bottom {
+    get {
+      bool? bottom = GetXmlNodeBoolNullable(
+          ExcelConditionalFormattingConstants.Paths._bottomAttribute);
+
+      // Bottom if TRUE
+      return (bottom == true);
+    }
+    set {
+      string bottomValue = string.Empty;
+
+      // Only the types that needs the @Bottom
+      if ((_type == eExcelConditionalFormattingRuleType.Bottom)
+          || (_type == eExcelConditionalFormattingRuleType.BottomPercent)) {
+        bottomValue = "1";
+      }
+
+      SetXmlNodeString(
+          ExcelConditionalFormattingConstants.Paths._bottomAttribute,
+          bottomValue,
+          true);
+    }
+  }
+
+  /// <summary>
+  /// Percent attribute
+  /// </summary>
+  internal protected bool? Percent {
+    get {
+      bool? percent = GetXmlNodeBoolNullable(
+          ExcelConditionalFormattingConstants.Paths._percentAttribute);
+
+      // Bottom if TRUE
+      return (percent == true);
+    }
+    set {
+      string percentValue = string.Empty;
+
+      // Only the types that needs the @Bottom
+      if ((_type == eExcelConditionalFormattingRuleType.BottomPercent)
+          || (_type == eExcelConditionalFormattingRuleType.TopPercent)) {
+        percentValue = "1";
+      }
+
+      SetXmlNodeString(
+          ExcelConditionalFormattingConstants.Paths._percentAttribute,
+          percentValue,
+          true);
+    }
+  }
+
+  /// <summary>
+  /// TimePeriod
+  /// </summary>
+  internal protected eExcelConditionalFormattingTimePeriodType TimePeriod {
+    get =>
+      ExcelConditionalFormattingTimePeriodType.GetTypeByAttribute(
+          GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._timePeriodAttribute));
+    set =>
+      SetXmlNodeString(
+          ExcelConditionalFormattingConstants.Paths._timePeriodAttribute,
+          ExcelConditionalFormattingTimePeriodType.GetAttributeByType(value),
+          true);
+  }
+
+  /// <summary>
+  /// Operator
+  /// </summary>
+  internal protected eExcelConditionalFormattingOperatorType Operator {
+    get =>
+      ExcelConditionalFormattingOperatorType.GetTypeByAttribute(
+          GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._operatorAttribute));
+    set =>
+      SetXmlNodeString(
+          ExcelConditionalFormattingConstants.Paths._operatorAttribute,
+          ExcelConditionalFormattingOperatorType.GetAttributeByType(value),
+          true);
+  }
+
+  /// <summary>
+  /// Formula
+  /// </summary>
+  public string Formula {
+    get => GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._formula);
+    set => SetXmlNodeString(ExcelConditionalFormattingConstants.Paths._formula, value);
+  }
+
+  /// <summary>
+  /// Formula2
+  /// </summary>
+  public string Formula2 {
+    get =>
+      GetXmlNodeString(
+          string.Format(
+              "{0}[position()=2]",
+              // {0}
+              ExcelConditionalFormattingConstants.Paths._formula));
+    set {
+      // Create/Get the first <formula> node (ensure that it exists)
+      var firstNode = CreateComplexNode(
+          TopNode,
+          string.Format(
+              "{0}[position()=1]",
+              // {0}
+              ExcelConditionalFormattingConstants.Paths._formula));
+
+      // Create/Get the seconde <formula> node (ensure that it exists)
+      var secondNode = CreateComplexNode(
+          TopNode,
+          string.Format(
+              "{0}[position()=2]",
+              // {0}
+              ExcelConditionalFormattingConstants.Paths._formula));
+
+      // Save the formula in the second <formula> node
+      secondNode.InnerText = value;
+    }
+  }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingThisMonth.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingThisMonth.cs
new file mode 100644
index 0000000..0b11938
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingThisMonth.cs
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingThisMonth
+/// </summary>
+public class ExcelConditionalFormattingThisMonth : ExcelConditionalFormattingTimePeriodGroup {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingThisMonth(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.ThisMonth,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      TimePeriod = eExcelConditionalFormattingTimePeriodType.ThisMonth;
+      Formula = string.Format(
+          "AND(MONTH({0})=MONTH(TODAY()), YEAR({0})=YEAR(TODAY()))",
+          Address.Start.Address);
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingThisMonth(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingThisMonth(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingThisWeek.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingThisWeek.cs
new file mode 100644
index 0000000..cb7833c
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingThisWeek.cs
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingThisWeek
+/// </summary>
+public class ExcelConditionalFormattingThisWeek : ExcelConditionalFormattingTimePeriodGroup {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingThisWeek(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.ThisWeek,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      TimePeriod = eExcelConditionalFormattingTimePeriodType.ThisWeek;
+      Formula = string.Format(
+          "AND(TODAY()-ROUNDDOWN({0},0)<=WEEKDAY(TODAY())-1,ROUNDDOWN({0},0)-TODAY()<=7-WEEKDAY(TODAY()))",
+          Address.Start.Address);
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingThisWeek(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingThisWeek(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeColorScale.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeColorScale.cs
new file mode 100644
index 0000000..9c0570e
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeColorScale.cs
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingThreeColorScale
+/// </summary>
+public class ExcelConditionalFormattingThreeColorScale
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingThreeColorScale {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingThreeColorScale(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.ThreeColorScale,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    // Create the <colorScale> node inside the <cfRule> node
+    var colorScaleNode = CreateComplexNode(
+        Node,
+        ExcelConditionalFormattingConstants.Paths._colorScale);
+
+    // LowValue default
+    LowValue = new(
+        eExcelConditionalFormattingValueObjectPosition.Low,
+        eExcelConditionalFormattingValueObjectType.Min,
+        eExcelConditionalFormattingRuleType.ThreeColorScale,
+        address,
+        priority,
+        worksheet,
+        NameSpaceManager);
+
+    // MiddleValue default
+    MiddleValue = new(
+        eExcelConditionalFormattingValueObjectPosition.Middle,
+        eExcelConditionalFormattingValueObjectType.Percent,
+        50,
+        string.Empty,
+        eExcelConditionalFormattingRuleType.ThreeColorScale,
+        address,
+        priority,
+        worksheet,
+        NameSpaceManager);
+
+    // HighValue default
+    HighValue = new(
+        eExcelConditionalFormattingValueObjectPosition.High,
+        eExcelConditionalFormattingValueObjectType.Max,
+        eExcelConditionalFormattingRuleType.ThreeColorScale,
+        address,
+        priority,
+        worksheet,
+        NameSpaceManager);
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingThreeColorScale(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingThreeColorScale(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+
+  /// <summary>
+  /// Low Value for Three Color Scale Object Value
+  /// </summary>
+  public ExcelConditionalFormattingColorScaleValue LowValue { get; set; }
+
+  /// <summary>
+  /// Middle Value for Three Color Scale Object Value
+  /// </summary>
+  public ExcelConditionalFormattingColorScaleValue MiddleValue { get; set; }
+
+  /// <summary>
+  /// High Value for Three Color Scale Object Value
+  /// </summary>
+  public ExcelConditionalFormattingColorScaleValue HighValue { get; set; }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeIconSet.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeIconSet.cs
new file mode 100644
index 0000000..554e428
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeIconSet.cs
@@ -0,0 +1,277 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+public class ExcelConditionalFormattingThreeIconSet
+    : ExcelConditionalFormattingIconSetBase<eExcelconditionalFormatting3IconsSetType> {
+  internal ExcelConditionalFormattingThreeIconSet(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.ThreeIconSet,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {}
+}
+
+/// <summary>
+/// ExcelConditionalFormattingThreeIconSet
+/// </summary>
+public class ExcelConditionalFormattingIconSetBase<T>
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingThreeIconSet<T> {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="type"></param>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingIconSetBase(
+      eExcelConditionalFormattingRuleType type,
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          type,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode != null && itemElementNode.HasChildNodes) {
+      int pos = 1;
+      foreach (XmlNode node in itemElementNode.SelectNodes("d:iconSet/d:cfvo", NameSpaceManager)) {
+        if (pos == 1) {
+          Icon1 = new(type, address, worksheet, node, namespaceManager);
+        } else if (pos == 2) {
+          Icon2 = new(type, address, worksheet, node, namespaceManager);
+        } else if (pos == 3) {
+          Icon3 = new(type, address, worksheet, node, namespaceManager);
+        } else {
+          break;
+        }
+        pos++;
+      }
+    } else {
+      var iconSetNode = CreateComplexNode(Node, ExcelConditionalFormattingConstants.Paths._iconSet);
+
+      //Create the <iconSet> node inside the <cfRule> node
+      double spann;
+      if (type == eExcelConditionalFormattingRuleType.ThreeIconSet) {
+        spann = 3;
+      } else if (type == eExcelConditionalFormattingRuleType.FourIconSet) {
+        spann = 4;
+      } else {
+        spann = 5;
+      }
+
+      var iconNode1 = iconSetNode.OwnerDocument.CreateElement(
+          ExcelConditionalFormattingConstants.Paths._cfvo,
+          ExcelPackage._schemaMain);
+      iconSetNode.AppendChild(iconNode1);
+      Icon1 = new(
+          eExcelConditionalFormattingValueObjectType.Percent,
+          0,
+          "",
+          eExcelConditionalFormattingRuleType.ThreeIconSet,
+          address,
+          priority,
+          worksheet,
+          iconNode1,
+          namespaceManager);
+
+      var iconNode2 = iconSetNode.OwnerDocument.CreateElement(
+          ExcelConditionalFormattingConstants.Paths._cfvo,
+          ExcelPackage._schemaMain);
+      iconSetNode.AppendChild(iconNode2);
+      Icon2 = new(
+          eExcelConditionalFormattingValueObjectType.Percent,
+          Math.Round(100D / spann, 0),
+          "",
+          eExcelConditionalFormattingRuleType.ThreeIconSet,
+          address,
+          priority,
+          worksheet,
+          iconNode2,
+          namespaceManager);
+
+      var iconNode3 = iconSetNode.OwnerDocument.CreateElement(
+          ExcelConditionalFormattingConstants.Paths._cfvo,
+          ExcelPackage._schemaMain);
+      iconSetNode.AppendChild(iconNode3);
+      Icon3 = new(
+          eExcelConditionalFormattingValueObjectType.Percent,
+          Math.Round(100D * (2D / spann), 0),
+          "",
+          eExcelConditionalFormattingRuleType.ThreeIconSet,
+          address,
+          priority,
+          worksheet,
+          iconNode3,
+          namespaceManager);
+      Type = type;
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  ///<param name="type"></param>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingIconSetBase(
+      eExcelConditionalFormattingRuleType type,
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(type, address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  ///<param name="type"></param>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingIconSetBase(
+      eExcelConditionalFormattingRuleType type,
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(type, address, priority, worksheet, null, null) {}
+
+  /// <summary>
+  /// Settings for icon 1 in the iconset
+  /// </summary>
+  public ExcelConditionalFormattingIconDataBarValue Icon1 { get; internal set; }
+
+  /// <summary>
+  /// Settings for icon 2 in the iconset
+  /// </summary>
+  public ExcelConditionalFormattingIconDataBarValue Icon2 { get; internal set; }
+
+  /// <summary>
+  /// Settings for icon 2 in the iconset
+  /// </summary>
+  public ExcelConditionalFormattingIconDataBarValue Icon3 { get; internal set; }
+
+  private const string _reversePath = "d:iconSet/@reverse";
+
+  /// <summary>
+  /// Reverse the order of the icons
+  /// </summary>
+  public bool Reverse {
+    get => GetXmlNodeBool(_reversePath, false);
+    set => SetXmlNodeBool(_reversePath, value);
+  }
+
+  private const string _showValuePath = "d:iconSet/@showValue";
+
+  /// <summary>
+  /// If the cell values are visible
+  /// </summary>
+  public bool ShowValue {
+    get => GetXmlNodeBool(_showValuePath, true);
+    set => SetXmlNodeBool(_showValuePath, value);
+  }
+
+  private const string _iconSetPath = "d:iconSet/@iconSet";
+
+  private string GetIconSetString(T value) {
+    if (Type == eExcelConditionalFormattingRuleType.FourIconSet) {
+      switch (value.ToString()) {
+        case "Arrows":
+          return "4Arrows";
+        case "ArrowsGray":
+          return "4ArrowsGray";
+        case "Rating":
+          return "4Rating";
+        case "RedToBlack":
+          return "4RedToBlack";
+        case "TrafficLights":
+          return "4TrafficLights";
+        default:
+          throw (new ArgumentException("Invalid type"));
+      }
+    }
+    if (Type == eExcelConditionalFormattingRuleType.FiveIconSet) {
+      switch (value.ToString()) {
+        case "Arrows":
+          return "5Arrows";
+        case "ArrowsGray":
+          return "5ArrowsGray";
+        case "Quarters":
+          return "5Quarters";
+        case "Rating":
+          return "5Rating";
+        default:
+          throw (new ArgumentException("Invalid type"));
+      }
+    }
+    switch (value.ToString()) {
+      case "Arrows":
+        return "3Arrows";
+      case "ArrowsGray":
+        return "3ArrowsGray";
+      case "Flags":
+        return "3Flags";
+      case "Signs":
+        return "3Signs";
+      case "Symbols":
+        return "3Symbols";
+      case "Symbols2":
+        return "3Symbols2";
+      case "TrafficLights1":
+        return "3TrafficLights1";
+      case "TrafficLights2":
+        return "3TrafficLights2";
+      default:
+        throw (new ArgumentException("Invalid type"));
+    }
+  }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingTimePeriodGroup.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingTimePeriodGroup.cs
new file mode 100644
index 0000000..2fc4a58
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingTimePeriodGroup.cs
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingTimePeriodGroup
+/// </summary>
+public class ExcelConditionalFormattingTimePeriodGroup
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingTimePeriodGroup {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="type"></param>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingTimePeriodGroup(
+      eExcelConditionalFormattingRuleType type,
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          type,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="type"></param>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingTimePeriodGroup(
+      eExcelConditionalFormattingRuleType type,
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(type, address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="type"></param>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingTimePeriodGroup(
+      eExcelConditionalFormattingRuleType type,
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(type, address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingToday.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingToday.cs
new file mode 100644
index 0000000..e6bdfd6
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingToday.cs
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingToday
+/// </summary>
+public class ExcelConditionalFormattingToday : ExcelConditionalFormattingTimePeriodGroup {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingToday(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.Today,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      TimePeriod = eExcelConditionalFormattingTimePeriodType.Today;
+      Formula = string.Format("FLOOR({0},1)=TODAY()", Address.Start.Address);
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingToday(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingToday(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingTomorrow.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingTomorrow.cs
new file mode 100644
index 0000000..4169af3
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingTomorrow.cs
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingTomorrow
+/// </summary>
+public class ExcelConditionalFormattingTomorrow : ExcelConditionalFormattingTimePeriodGroup {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingTomorrow(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.Tomorrow,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      TimePeriod = eExcelConditionalFormattingTimePeriodType.Tomorrow;
+      Formula = string.Format("FLOOR({0},1)=TODAY()+1", Address.Start.Address);
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingTomorrow(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingTomorrow(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingTop.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingTop.cs
new file mode 100644
index 0000000..47bbeca
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingTop.cs
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingTop
+/// </summary>
+public class ExcelConditionalFormattingTop
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingTopBottomGroup {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingTop(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.Top,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      Bottom = false;
+      Percent = false;
+      Rank = 10; // First 10 values
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingTop(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingTop(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingTopPercent.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingTopPercent.cs
new file mode 100644
index 0000000..0fe253e
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingTopPercent.cs
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingTopPercent
+/// </summary>
+public class ExcelConditionalFormattingTopPercent
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingTopBottomGroup {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingTopPercent(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.TopPercent,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      Bottom = false;
+      Percent = true;
+      Rank = 10; // First 10 percent
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingTopPercent(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingTopPercent(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingTwoColorScale.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingTwoColorScale.cs
new file mode 100644
index 0000000..4bc1365
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingTwoColorScale.cs
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingTwoColorScale
+/// </summary>
+public class ExcelConditionalFormattingTwoColorScale
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingTwoColorScale {
+  /// <summary>
+  /// Private Low Value
+  /// </summary>
+  private ExcelConditionalFormattingColorScaleValue _lowValue;
+
+  /// <summary>
+  /// Private High Value
+  /// </summary>
+  private ExcelConditionalFormattingColorScaleValue _highValue;
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingTwoColorScale(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.TwoColorScale,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    // Create the <colorScale> node inside the <cfRule> node
+    var colorScaleNode = CreateComplexNode(
+        Node,
+        ExcelConditionalFormattingConstants.Paths._colorScale);
+
+    // LowValue default
+    LowValue = new(
+        eExcelConditionalFormattingValueObjectPosition.Low,
+        eExcelConditionalFormattingValueObjectType.Min,
+        eExcelConditionalFormattingRuleType.TwoColorScale,
+        address,
+        priority,
+        worksheet,
+        NameSpaceManager);
+
+    // HighValue default
+    HighValue = new(
+        eExcelConditionalFormattingValueObjectPosition.High,
+        eExcelConditionalFormattingValueObjectType.Max,
+        eExcelConditionalFormattingRuleType.TwoColorScale,
+        address,
+        priority,
+        worksheet,
+        NameSpaceManager);
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingTwoColorScale(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingTwoColorScale(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+
+  /// <summary>
+  /// Low Value for Two Color Scale Object Value
+  /// </summary>
+  public ExcelConditionalFormattingColorScaleValue LowValue {
+    get => _lowValue;
+    set => _lowValue = value;
+  }
+
+  /// <summary>
+  /// High Value for Two Color Scale Object Value
+  /// </summary>
+  public ExcelConditionalFormattingColorScaleValue HighValue {
+    get => _highValue;
+    set => _highValue = value;
+  }
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingUniqueValues.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingUniqueValues.cs
new file mode 100644
index 0000000..eb2de44
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingUniqueValues.cs
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingUniqueValues
+/// </summary>
+public class ExcelConditionalFormattingUniqueValues
+    : ExcelConditionalFormattingRule,
+      IExcelConditionalFormattingUniqueValues {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="priority"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingUniqueValues(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.UniqueValues,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingUniqueValues(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingUniqueValues(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingYesterday.cs b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingYesterday.cs
new file mode 100644
index 0000000..f6302f2
--- /dev/null
+++ b/AppsheetEpplus/ConditionalFormatting/Rules/ExcelConditionalFormattingYesterday.cs
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Eyal Seagull        Added       		  2012-04-03
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// ExcelConditionalFormattingYesterday
+/// </summary>
+public class ExcelConditionalFormattingYesterday : ExcelConditionalFormattingTimePeriodGroup {
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelConditionalFormattingYesterday(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(
+          eExcelConditionalFormattingRuleType.Yesterday,
+          address,
+          priority,
+          worksheet,
+          itemElementNode,
+          namespaceManager ?? worksheet.NameSpaceManager) {
+    if (itemElementNode
+        == null) //Set default values and create attributes if needed
+    {
+      TimePeriod = eExcelConditionalFormattingTimePeriodType.Yesterday;
+      Formula = string.Format("FLOOR({0},1)=TODAY()-1", Address.Start.Address);
+    }
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelConditionalFormattingYesterday(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet,
+      XmlNode itemElementNode)
+      : this(address, priority, worksheet, itemElementNode, null) {}
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="priority"></param>
+  /// <param name="address"></param>
+  /// <param name="worksheet"></param>
+  internal ExcelConditionalFormattingYesterday(
+      ExcelAddress address,
+      int priority,
+      ExcelWorksheet worksheet)
+      : this(address, priority, worksheet, null, null) {}
+}
diff --git a/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidation.cs b/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidation.cs
new file mode 100644
index 0000000..be01429
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidation.cs
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Interface for data validation
+/// </summary>
+public interface IExcelDataValidation {
+  /// <summary>
+  /// Address of data validation
+  /// </summary>
+  ExcelAddress Address { get; }
+
+  /// <summary>
+  /// Validation type
+  /// </summary>
+  ExcelDataValidationType ValidationType { get; }
+
+  /// <summary>
+  /// Controls how Excel will handle invalid values.
+  /// </summary>
+  ExcelDataValidationWarningStyle ErrorStyle { get; }
+
+  /// <summary>
+  /// True if input message should be shown
+  /// </summary>
+  bool? AllowBlank { get; set; }
+
+  /// <summary>
+  /// True if input message should be shown
+  /// </summary>
+  bool? ShowInputMessage { get; set; }
+
+  /// <summary>
+  /// True if error message should be shown.
+  /// </summary>
+  bool? ShowErrorMessage { get; set; }
+
+  /// <summary>
+  /// Title of error message box (see property ShowErrorMessage)
+  /// </summary>
+  string ErrorTitle { get; set; }
+
+  /// <summary>
+  /// Error message box text (see property ShowErrorMessage)
+  /// </summary>
+  string Error { get; set; }
+
+  /// <summary>
+  /// Title of info box if input message should be shown (see property ShowInputMessage)
+  /// </summary>
+  string PromptTitle { get; set; }
+
+  /// <summary>
+  /// Info message text (see property ShowErrorMessage)
+  /// </summary>
+  string Prompt { get; set; }
+
+  /// <summary>
+  /// True if the current validation type allows operator.
+  /// </summary>
+  bool AllowsOperator { get; }
+
+  /// <summary>
+  /// Validates the state of the validation.
+  /// </summary>
+  void Validate();
+}
diff --git a/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationAny.cs b/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationAny.cs
new file mode 100644
index 0000000..fb6e842
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationAny.cs
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Raziq York   		            Added       		        2014-08-08
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Data validation interface for Any value validation.
+/// </summary>
+public interface IExcelDataValidationAny : IExcelDataValidation {}
diff --git a/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationCustom.cs b/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationCustom.cs
new file mode 100644
index 0000000..88055cb
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationCustom.cs
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Data validation interface for custom validation.
+/// </summary>
+public interface IExcelDataValidationCustom
+    : IExcelDataValidationWithFormula<IExcelDataValidationFormula>,
+      IExcelDataValidationWithOperator {}
diff --git a/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationDateTime.cs b/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationDateTime.cs
new file mode 100644
index 0000000..08703d0
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationDateTime.cs
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Validation interface for datetime validations
+/// </summary>
+public interface IExcelDataValidationDateTime
+    : IExcelDataValidationWithFormula2<IExcelDataValidationFormulaDateTime>,
+      IExcelDataValidationWithOperator {}
diff --git a/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationDecimal.cs b/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationDecimal.cs
new file mode 100644
index 0000000..92e19cd
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationDecimal.cs
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Data validation interface for decimal values
+/// </summary>
+public interface IExcelDataValidationDecimal
+    : IExcelDataValidationWithFormula2<IExcelDataValidationFormulaDecimal>,
+      IExcelDataValidationWithOperator {}
diff --git a/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationInt.cs b/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationInt.cs
new file mode 100644
index 0000000..4ec1398
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationInt.cs
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+public interface IExcelDataValidationInt
+    : IExcelDataValidationWithFormula2<IExcelDataValidationFormulaInt>,
+      IExcelDataValidationWithOperator {}
diff --git a/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationList.cs b/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationList.cs
new file mode 100644
index 0000000..9e8e1f4
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationList.cs
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+public interface IExcelDataValidationList
+    : IExcelDataValidationWithFormula<IExcelDataValidationFormulaList> {}
diff --git a/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationTime.cs b/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationTime.cs
new file mode 100644
index 0000000..d37d676
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationTime.cs
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Data validation interface for time validation.
+/// </summary>
+public interface IExcelDataValidationTime
+    : IExcelDataValidationWithFormula2<IExcelDataValidationFormulaTime>,
+      IExcelDataValidationWithOperator {}
diff --git a/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationWithFormula.cs b/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationWithFormula.cs
new file mode 100644
index 0000000..60899d0
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationWithFormula.cs
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+public interface IExcelDataValidationWithFormula<T> : IExcelDataValidation
+    where T : IExcelDataValidationFormula {
+  T Formula { get; }
+}
diff --git a/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationWithFormula2.cs b/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationWithFormula2.cs
new file mode 100644
index 0000000..9ba64d9
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationWithFormula2.cs
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Interface for a data validation with two formulas
+/// </summary>
+/// <typeparam name="T"></typeparam>
+public interface IExcelDataValidationWithFormula2<T> : IExcelDataValidationWithFormula<T>
+    where T : IExcelDataValidationFormula {
+  /// <summary>
+  /// Formula 2
+  /// </summary>
+  T Formula2 { get; }
+}
diff --git a/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationWithOperator.cs b/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationWithOperator.cs
new file mode 100644
index 0000000..ab5c50e
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Contracts/IExcelDataValidationWithOperator.cs
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Represents a validation with an operator
+/// </summary>
+public interface IExcelDataValidationWithOperator {
+  /// <summary>
+  /// Operator type
+  /// </summary>
+  ExcelDataValidationOperator Operator { get; }
+}
diff --git a/AppsheetEpplus/DataValidation/ExcelDataValidation.cs b/AppsheetEpplus/DataValidation/ExcelDataValidation.cs
new file mode 100644
index 0000000..4ad68e0
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/ExcelDataValidation.cs
@@ -0,0 +1,283 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-01
+ * Jan Källman		                License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+using System;
+using System.Collections.Immutable;
+using System.Globalization;
+using System.Text.RegularExpressions;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Excel datavalidation
+/// </summary>
+public abstract class ExcelDataValidation : XmlHelper, IExcelDataValidation {
+  private const string _itemElementNodeName = "d:dataValidation";
+
+  private readonly string _errorStylePath = "@errorStyle";
+  private readonly string _errorTitlePath = "@errorTitle";
+  private readonly string _errorPath = "@error";
+  private readonly string _promptTitlePath = "@promptTitle";
+  private readonly string _promptPath = "@prompt";
+  private readonly string _operatorPath = "@operator";
+  private readonly string _showErrorMessagePath = "@showErrorMessage";
+  private readonly string _showInputMessagePath = "@showInputMessage";
+  private readonly string _typeMessagePath = "@type";
+  private readonly string _sqrefPath = "@sqref";
+  private readonly string _allowBlankPath = "@allowBlank";
+  protected readonly string _formula1Path = "d:formula1";
+  protected readonly string _formula2Path = "d:formula2";
+
+  protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
+    "type",
+    "errorStyle",
+    "operator",
+    "allowBlank",
+    "showInputMessage",
+    "showErrorMessage",
+    "errorTitle",
+    "error",
+    "promptTitle",
+    "prompt",
+    "sqref",
+    "formula1",
+    "formula2",
+  ];
+
+  internal ExcelDataValidation(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType)
+      : this(worksheet, address, validationType, null) {}
+
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet">worksheet that owns the validation</param>
+  /// <param name="itemElementNode">Xml top node (dataValidations)</param>
+  /// <param name="validationType">Data validation type</param>
+  /// <param name="address">address for data validation</param>
+  internal ExcelDataValidation(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType,
+      XmlNode itemElementNode)
+      : this(worksheet, address, validationType, itemElementNode, null) {}
+
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet">worksheet that owns the validation</param>
+  /// <param name="itemElementNode">Xml top node (dataValidations) when importing xml</param>
+  /// <param name="validationType">Data validation type</param>
+  /// <param name="address">address for data validation</param>
+  /// <param name="namespaceManager">Xml Namespace manager</param>
+  internal ExcelDataValidation(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(namespaceManager ?? worksheet.NameSpaceManager) {
+    ArgumentException.ThrowIfNullOrEmpty(address);
+    address = CheckAndFixRangeAddress(address);
+    if (itemElementNode == null) {
+      //var xmlDoc = worksheet.WorksheetXml;
+      TopNode = worksheet.WorksheetXml.SelectSingleNode(
+          "//d:dataValidations",
+          worksheet.NameSpaceManager);
+      // did not succeed using the XmlHelper methods here... so I'm creating the new node using XmlDocument...
+      var nsUri = NameSpaceManager.LookupNamespace("d");
+      //itemElementNode = TopNode.OwnerDocument.CreateElement(_itemElementNodeName, nsUri);
+      itemElementNode = TopNode.OwnerDocument.CreateElement(
+          _itemElementNodeName.Split(':')[1],
+          nsUri);
+      TopNode.AppendChild(itemElementNode);
+    }
+    TopNode = itemElementNode;
+    ValidationType = validationType;
+    Address = new(address);
+  }
+
+  private string CheckAndFixRangeAddress(string address) {
+    if (address.Contains(',')) {
+      throw new FormatException("Multiple addresses may not be commaseparated, use space instead");
+    }
+    address = address.ToUpper(CultureInfo.InvariantCulture);
+    if (Regex.IsMatch(address, "[A-Z]+:[A-Z]+")) {
+      address = AddressUtility.ParseEntireColumnSelections(address);
+    }
+    return address;
+  }
+
+  private void SetNullableBoolValue(string path, bool? val) {
+    if (val.HasValue) {
+      SetXmlNodeBool(path, val.Value);
+    } else {
+      DeleteNode(path);
+    }
+  }
+
+  /// <summary>
+  /// This method will validate the state of the validation
+  /// </summary>
+  /// <exception cref="InvalidOperationException">If the state breaks the rules of the validation</exception>
+  public virtual void Validate() {
+    var address = Address.Address;
+    // validate Formula1
+    if (string.IsNullOrEmpty(Formula1Internal)) {
+      throw new InvalidOperationException(
+          "Validation of " + address + " failed: Formula1 cannot be empty");
+    }
+  }
+
+  /// <summary>
+  /// True if the validation type allows operator to be set.
+  /// </summary>
+  public bool AllowsOperator => ValidationType.AllowOperator;
+
+  /// <summary>
+  /// Address of data validation
+  /// </summary>
+  public ExcelAddress Address {
+    get => new(GetXmlNodeString(_sqrefPath));
+    private set {
+      var address = AddressUtility.ParseEntireColumnSelections(value.Address);
+      SetXmlNodeString(_sqrefPath, address);
+    }
+  }
+
+  /// <summary>
+  /// Validation type
+  /// </summary>
+  public ExcelDataValidationType ValidationType {
+    get {
+      var typeString = GetXmlNodeString(_typeMessagePath);
+      return ExcelDataValidationType.GetBySchemaName(typeString);
+    }
+    private set => SetXmlNodeString(_typeMessagePath, value.SchemaName, true);
+  }
+
+  /// <summary>
+  /// Operator for comparison between the entered value and Formula/Formulas.
+  /// </summary>
+  public ExcelDataValidationOperator Operator {
+    get {
+      var operatorString = GetXmlNodeString(_operatorPath);
+      return Enum.TryParse<ExcelDataValidationOperator>(operatorString, true, out var op)
+          ? op
+          : ExcelDataValidationOperator.Any;
+    }
+  }
+
+  /// <summary>
+  /// Warning style
+  /// </summary>
+  public ExcelDataValidationWarningStyle ErrorStyle {
+    get {
+      var errorStyleString = GetXmlNodeString(_errorStylePath);
+      return Enum.TryParse<ExcelDataValidationWarningStyle>(errorStyleString, true, out var style)
+          ? style
+          : ExcelDataValidationWarningStyle.Undefined;
+    }
+  }
+
+  /// <summary>
+  /// True if blanks should be allowed
+  /// </summary>
+  public bool? AllowBlank {
+    get => GetXmlNodeBoolNullable(_allowBlankPath);
+    set => SetNullableBoolValue(_allowBlankPath, value);
+  }
+
+  /// <summary>
+  /// True if input message should be shown
+  /// </summary>
+  public bool? ShowInputMessage {
+    get => GetXmlNodeBoolNullable(_showInputMessagePath);
+    set => SetNullableBoolValue(_showInputMessagePath, value);
+  }
+
+  /// <summary>
+  /// True if error message should be shown
+  /// </summary>
+  public bool? ShowErrorMessage {
+    get => GetXmlNodeBoolNullable(_showErrorMessagePath);
+    set => SetNullableBoolValue(_showErrorMessagePath, value);
+  }
+
+  /// <summary>
+  /// Title of error message box
+  /// </summary>
+  public string ErrorTitle {
+    get => GetXmlNodeString(_errorTitlePath);
+    set => SetXmlNodeString(_errorTitlePath, value);
+  }
+
+  /// <summary>
+  /// Error message box text
+  /// </summary>
+  public string Error {
+    get => GetXmlNodeString(_errorPath);
+    set => SetXmlNodeString(_errorPath, value);
+  }
+
+  public string PromptTitle {
+    get => GetXmlNodeString(_promptTitlePath);
+    set => SetXmlNodeString(_promptTitlePath, value);
+  }
+
+  public string Prompt {
+    get => GetXmlNodeString(_promptPath);
+    set => SetXmlNodeString(_promptPath, value);
+  }
+
+  /// <summary>
+  /// Formula 1
+  /// </summary>
+  protected string Formula1Internal => GetXmlNodeString(_formula1Path);
+
+  /// <summary>
+  /// Formula 2
+  /// </summary>
+  protected string Formula2Internal => GetXmlNodeString(_formula2Path);
+
+  protected void SetValue<T>(T? val, string path)
+      where T : struct {
+    if (!val.HasValue) {
+      DeleteNode(path);
+    }
+    var stringValue = val.Value.ToString().Replace(',', '.');
+    SetXmlNodeString(path, stringValue);
+  }
+}
diff --git a/AppsheetEpplus/DataValidation/ExcelDataValidationAny.cs b/AppsheetEpplus/DataValidation/ExcelDataValidationAny.cs
new file mode 100644
index 0000000..4e6e34f
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/ExcelDataValidationAny.cs
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Raziq York   		            Added       		        2014-08-08
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Any value validation.
+/// </summary>
+public class ExcelDataValidationAny : ExcelDataValidation, IExcelDataValidationAny {
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet"></param>
+  /// <param name="address"></param>
+  /// <param name="validationType"></param>
+  internal ExcelDataValidationAny(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType)
+      : base(worksheet, address, validationType) {}
+
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet"></param>
+  /// <param name="address"></param>
+  /// <param name="validationType"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelDataValidationAny(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType,
+      XmlNode itemElementNode)
+      : base(worksheet, address, validationType, itemElementNode) {}
+
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet"></param>
+  /// <param name="address"></param>
+  /// <param name="validationType"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelDataValidationAny(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(worksheet, address, validationType, itemElementNode, namespaceManager) {}
+
+  /// <summary>
+  /// This method will validate the state of the validation
+  /// </summary>
+  public override void Validate() {}
+}
diff --git a/AppsheetEpplus/DataValidation/ExcelDataValidationCollection.cs b/AppsheetEpplus/DataValidation/ExcelDataValidationCollection.cs
new file mode 100644
index 0000000..1548409
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/ExcelDataValidationCollection.cs
@@ -0,0 +1,359 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-01
+ * Mats Alm                         Applying patch submitted    2011-11-14
+ *                                  by Ted Heatherington
+ * Jan Källman		                License changed GPL-->LGPL  2011-12-27
+ * Raziq York		                Added support for Any type  2014-08-08
+*******************************************************************************/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// <para>
+/// Collection of <see cref="ExcelDataValidation"/>. This class is providing the API for EPPlus data validation.
+/// </para>
+/// <para>
+/// The public methods of this class (Add[...]Validation) will create a datavalidation entry in the worksheet. When this
+/// validation has been created changes to the properties will affect the workbook immediately.
+/// </para>
+/// <para>
+/// Each type of validation has either a formula or a typed value/values, except for custom validation which has a formula only.
+/// </para>
+/// <code>
+/// // Add a date time validation
+/// var validation = worksheet.DataValidation.AddDateTimeValidation("A1");
+/// // set validation properties
+/// validation.ShowErrorMessage = true;
+/// validation.ErrorTitle = "An invalid date was entered";
+/// validation.Error = "The date must be between 2011-01-31 and 2011-12-31";
+/// validation.Prompt = "Enter date here";
+/// validation.Formula.Value = DateTime.Parse("2011-01-01");
+/// validation.Formula2.Value = DateTime.Parse("2011-12-31");
+/// validation.Operator = ExcelDataValidationOperator.between;
+/// </code>
+/// </summary>
+public class ExcelDataValidationCollection : XmlHelper, IEnumerable<IExcelDataValidation> {
+  private readonly List<IExcelDataValidation> _validations = new();
+  private readonly ExcelWorksheet _worksheet;
+
+  private const string _dataValidationPath = "//d:dataValidations";
+  private readonly string DataValidationItemsPath = string.Format(
+      "{0}/d:dataValidation",
+      _dataValidationPath);
+
+  protected override ImmutableArray<string> SchemaNodeOrder =>
+    ExcelWorksheet.WorksheetSchemaNodeOrder;
+
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet"></param>
+  internal ExcelDataValidationCollection(ExcelWorksheet worksheet)
+      : base(worksheet.NameSpaceManager, worksheet.WorksheetXml.DocumentElement) {
+    ArgumentNullException.ThrowIfNull(worksheet);
+    _worksheet = worksheet;
+
+    // check existing nodes and load them
+    var dataValidationNodes = worksheet.WorksheetXml.SelectNodes(
+        DataValidationItemsPath,
+        worksheet.NameSpaceManager);
+    if (dataValidationNodes != null && dataValidationNodes.Count > 0) {
+      foreach (XmlNode node in dataValidationNodes) {
+        if (node.Attributes["sqref"] == null) {
+          continue;
+        }
+
+        var addr = node.Attributes["sqref"].Value;
+
+        var typeSchema = node.Attributes["type"] != null ? node.Attributes["type"].Value : "";
+
+        var type = ExcelDataValidationType.GetBySchemaName(typeSchema);
+        _validations.Add(ExcelDataValidationFactory.Create(type, worksheet, addr, node));
+      }
+    }
+  }
+
+  private void EnsureRootElementExists() {
+    var node = _worksheet.WorksheetXml.SelectSingleNode(
+        _dataValidationPath,
+        _worksheet.NameSpaceManager);
+    if (node == null) {
+      CreateNode(_dataValidationPath.TrimStart('/'));
+    }
+  }
+
+  /// <summary>
+  /// Validates address - not empty, collisions
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="validatingValidation"></param>
+  private void ValidateAddress(string address, IExcelDataValidation validatingValidation) {
+    ArgumentException.ThrowIfNullOrEmpty(address);
+
+    // ensure that the new address does not collide with an existing validation.
+    var newAddress = new ExcelAddress(address);
+    if (_validations.Count > 0) {
+      foreach (var validation in _validations) {
+        if (validatingValidation != null && validatingValidation == validation) {
+          continue;
+        }
+        var result = validation.Address.Collide(newAddress);
+        if (result != ExcelAddressBase.eAddressCollition.No) {
+          throw new InvalidOperationException(
+              string.Format(
+                  "The address ({0}) collides with an existing validation ({1})",
+                  address,
+                  validation.Address.Address));
+        }
+      }
+    }
+  }
+
+  private void ValidateAddress(string address) {
+    ValidateAddress(address, null);
+  }
+
+  /// <summary>
+  /// Validates all data validations.
+  /// </summary>
+  internal void ValidateAll() {
+    foreach (var validation in _validations) {
+      validation.Validate();
+
+      ValidateAddress(validation.Address.Address, validation);
+    }
+  }
+
+  /// <summary>
+  /// Adds a <see cref="ExcelDataValidationAny"/> to the worksheet.
+  /// </summary>
+  /// <param name="address">The range/address to validate</param>
+  /// <returns></returns>
+  public IExcelDataValidationAny AddAnyValidation(string address) {
+    ValidateAddress(address);
+    EnsureRootElementExists();
+    var item = new ExcelDataValidationAny(_worksheet, address, ExcelDataValidationType.Any);
+    _validations.Add(item);
+    return item;
+  }
+
+  /// <summary>
+  /// Adds an <see cref="IExcelDataValidationInt"/> to the worksheet. Whole means that the only accepted values
+  /// are integer values.
+  /// </summary>
+  /// <param name="address">the range/address to validate</param>
+  public IExcelDataValidationInt AddIntegerValidation(string address) {
+    ValidateAddress(address);
+    EnsureRootElementExists();
+    var item = new ExcelDataValidationInt(_worksheet, address, ExcelDataValidationType.Whole);
+    _validations.Add(item);
+    return item;
+  }
+
+  /// <summary>
+  /// Addes an <see cref="IExcelDataValidationDecimal"/> to the worksheet. The only accepted values are
+  /// decimal values.
+  /// </summary>
+  /// <param name="address">The range/address to validate</param>
+  /// <returns></returns>
+  public IExcelDataValidationDecimal AddDecimalValidation(string address) {
+    ValidateAddress(address);
+    EnsureRootElementExists();
+    var item = new ExcelDataValidationDecimal(_worksheet, address, ExcelDataValidationType.Decimal);
+    _validations.Add(item);
+    return item;
+  }
+
+  /// <summary>
+  /// Adds an <see cref="IExcelDataValidationList"/> to the worksheet. The accepted values are defined
+  /// in a list.
+  /// </summary>
+  /// <param name="address">The range/address to validate</param>
+  /// <returns></returns>
+  public IExcelDataValidationList AddListValidation(string address) {
+    ValidateAddress(address);
+    EnsureRootElementExists();
+    var item = new ExcelDataValidationList(_worksheet, address, ExcelDataValidationType.List);
+    _validations.Add(item);
+    return item;
+  }
+
+  /// <summary>
+  /// Adds an <see cref="IExcelDataValidationInt"/> regarding text length to the worksheet.
+  /// </summary>
+  /// <param name="address">The range/address to validate</param>
+  /// <returns></returns>
+  public IExcelDataValidationInt AddTextLengthValidation(string address) {
+    ValidateAddress(address);
+    EnsureRootElementExists();
+    var item = new ExcelDataValidationInt(_worksheet, address, ExcelDataValidationType.TextLength);
+    _validations.Add(item);
+    return item;
+  }
+
+  /// <summary>
+  /// Adds an <see cref="IExcelDataValidationDateTime"/> to the worksheet.
+  /// </summary>
+  /// <param name="address">The range/address to validate</param>
+  /// <returns></returns>
+  public IExcelDataValidationDateTime AddDateTimeValidation(string address) {
+    ValidateAddress(address);
+    EnsureRootElementExists();
+    var item = new ExcelDataValidationDateTime(
+        _worksheet,
+        address,
+        ExcelDataValidationType.DateTime);
+    _validations.Add(item);
+    return item;
+  }
+
+  public IExcelDataValidationTime AddTimeValidation(string address) {
+    ValidateAddress(address);
+    EnsureRootElementExists();
+    var item = new ExcelDataValidationTime(_worksheet, address, ExcelDataValidationType.Time);
+    _validations.Add(item);
+    return item;
+  }
+
+  /// <summary>
+  /// Adds a <see cref="ExcelDataValidationCustom"/> to the worksheet.
+  /// </summary>
+  /// <param name="address">The range/address to validate</param>
+  /// <returns></returns>
+  public IExcelDataValidationCustom AddCustomValidation(string address) {
+    ValidateAddress(address);
+    EnsureRootElementExists();
+    var item = new ExcelDataValidationCustom(_worksheet, address, ExcelDataValidationType.Custom);
+    _validations.Add(item);
+    return item;
+  }
+
+  /// <summary>
+  /// Removes an <see cref="ExcelDataValidation"/> from the collection.
+  /// </summary>
+  /// <param name="item">The item to remove</param>
+  /// <returns>True if remove succeeds, otherwise false</returns>
+  /// <exception cref="ArgumentNullException">if <paramref name="item"/> is null</exception>
+  public bool Remove(IExcelDataValidation item) {
+    if (!(item is ExcelDataValidation validation)) {
+      throw new InvalidCastException(
+          "The supplied item must inherit OfficeOpenXml.DataValidation.ExcelDataValidation");
+    }
+    ArgumentNullException.ThrowIfNull(item);
+    TopNode.RemoveChild(validation.TopNode);
+    return _validations.Remove(validation);
+  }
+
+  /// <summary>
+  /// Number of validations
+  /// </summary>
+  public int Count => _validations.Count;
+
+  /// <summary>
+  /// Index operator, returns by 0-based index
+  /// </summary>
+  /// <param name="index"></param>
+  /// <returns></returns>
+  public IExcelDataValidation this[int index] {
+    get => _validations[index];
+    set => _validations[index] = value;
+  }
+
+  /// <summary>
+  /// Index operator, returns a data validation which address partly or exactly matches the searched address.
+  /// </summary>
+  /// <param name="address">A cell address or range</param>
+  /// <returns>A <see cref="ExcelDataValidation"/> or null if no match</returns>
+  public IExcelDataValidation this[string address] {
+    get {
+      var searchedAddress = new ExcelAddress(address);
+      return _validations.Find(x =>
+          x.Address.Collide(searchedAddress) != ExcelAddressBase.eAddressCollition.No);
+    }
+  }
+
+  /// <summary>
+  /// Returns all validations that matches the supplied predicate <paramref name="match"/>.
+  /// </summary>
+  /// <param name="match">predicate to filter out matching validations</param>
+  /// <returns></returns>
+  public IEnumerable<IExcelDataValidation> FindAll(Predicate<IExcelDataValidation> match) {
+    return _validations.FindAll(match);
+  }
+
+  /// <summary>
+  /// Returns the first matching validation.
+  /// </summary>
+  /// <param name="match"></param>
+  /// <returns></returns>
+  public IExcelDataValidation Find(Predicate<IExcelDataValidation> match) {
+    return _validations.Find(match);
+  }
+
+  /// <summary>
+  /// Removes all validations from the collection.
+  /// </summary>
+  public void Clear() {
+    DeleteAllNode(DataValidationItemsPath.TrimStart('/'));
+    _validations.Clear();
+  }
+
+  /// <summary>
+  /// Removes the validations that matches the predicate
+  /// </summary>
+  /// <param name="match"></param>
+  public void RemoveAll(Predicate<IExcelDataValidation> match) {
+    var matches = _validations.FindAll(match);
+    foreach (var m in matches) {
+      if (!(m is ExcelDataValidation validation)) {
+        throw new InvalidCastException(
+            "The supplied item must inherit OfficeOpenXml.DataValidation.ExcelDataValidation");
+      }
+      TopNode
+          .SelectSingleNode(_dataValidationPath.TrimStart('/'), NameSpaceManager)
+          .RemoveChild(validation.TopNode);
+    }
+    _validations.RemoveAll(match);
+  }
+
+  IEnumerator<IExcelDataValidation> IEnumerable<IExcelDataValidation>.GetEnumerator() {
+    return _validations.GetEnumerator();
+  }
+
+  IEnumerator IEnumerable.GetEnumerator() {
+    return _validations.GetEnumerator();
+  }
+}
diff --git a/AppsheetEpplus/DataValidation/ExcelDataValidationCustom.cs b/AppsheetEpplus/DataValidation/ExcelDataValidationCustom.cs
new file mode 100644
index 0000000..381dfd4
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/ExcelDataValidationCustom.cs
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-01
+ * Jan Källman		                License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Custom validation, i.e. a formula.
+/// </summary>
+public class ExcelDataValidationCustom
+    : ExcelDataValidationWithFormula<IExcelDataValidationFormula>,
+      IExcelDataValidationCustom {
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet"></param>
+  /// <param name="address"></param>
+  /// <param name="validationType"></param>
+  internal ExcelDataValidationCustom(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType)
+      : base(worksheet, address, validationType) {
+    Formula = new ExcelDataValidationFormulaCustom(NameSpaceManager, TopNode, _formula1Path);
+  }
+
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet"></param>
+  /// <param name="address"></param>
+  /// <param name="validationType"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelDataValidationCustom(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType,
+      XmlNode itemElementNode)
+      : base(worksheet, address, validationType, itemElementNode) {
+    Formula = new ExcelDataValidationFormulaCustom(NameSpaceManager, TopNode, _formula1Path);
+  }
+
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet"></param>
+  /// <param name="address"></param>
+  /// <param name="validationType"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelDataValidationCustom(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(worksheet, address, validationType, itemElementNode, namespaceManager) {
+    Formula = new ExcelDataValidationFormulaCustom(NameSpaceManager, TopNode, _formula1Path);
+  }
+}
diff --git a/AppsheetEpplus/DataValidation/ExcelDataValidationDateTime.cs b/AppsheetEpplus/DataValidation/ExcelDataValidationDateTime.cs
new file mode 100644
index 0000000..04d5428
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/ExcelDataValidationDateTime.cs
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-01
+ * Jan Källman		                License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+using System;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Validation for <see cref="DateTime"/>.
+/// </summary>
+public class ExcelDataValidationDateTime
+    : ExcelDataValidationWithFormula2<IExcelDataValidationFormulaDateTime>,
+      IExcelDataValidationDateTime {
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet"></param>
+  /// <param name="address"></param>
+  /// <param name="validationType"></param>
+  internal ExcelDataValidationDateTime(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType)
+      : base(worksheet, address, validationType) {
+    Formula = new ExcelDataValidationFormulaDateTime(NameSpaceManager, TopNode, _formula1Path);
+    Formula2 = new ExcelDataValidationFormulaDateTime(NameSpaceManager, TopNode, _formula2Path);
+  }
+
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet"></param>
+  /// <param name="address"></param>
+  /// <param name="validationType"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelDataValidationDateTime(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType,
+      XmlNode itemElementNode)
+      : base(worksheet, address, validationType, itemElementNode) {
+    Formula = new ExcelDataValidationFormulaDateTime(NameSpaceManager, TopNode, _formula1Path);
+    Formula2 = new ExcelDataValidationFormulaDateTime(NameSpaceManager, TopNode, _formula2Path);
+  }
+
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet"></param>
+  /// <param name="address"></param>
+  /// <param name="validationType"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelDataValidationDateTime(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(worksheet, address, validationType, itemElementNode, namespaceManager) {
+    Formula = new ExcelDataValidationFormulaDateTime(NameSpaceManager, TopNode, _formula1Path);
+    Formula2 = new ExcelDataValidationFormulaDateTime(NameSpaceManager, TopNode, _formula2Path);
+  }
+}
diff --git a/AppsheetEpplus/DataValidation/ExcelDataValidationDecimal.cs b/AppsheetEpplus/DataValidation/ExcelDataValidationDecimal.cs
new file mode 100644
index 0000000..dd9afbc
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/ExcelDataValidationDecimal.cs
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-01
+ * Jan Källman		                License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Data validation for decimal values
+/// </summary>
+public class ExcelDataValidationDecimal
+    : ExcelDataValidationWithFormula2<IExcelDataValidationFormulaDecimal>,
+      IExcelDataValidationDecimal {
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet"></param>
+  /// <param name="address"></param>
+  /// <param name="validationType"></param>
+  internal ExcelDataValidationDecimal(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType)
+      : base(worksheet, address, validationType) {
+    Formula = new ExcelDataValidationFormulaDecimal(NameSpaceManager, TopNode, _formula1Path);
+    Formula2 = new ExcelDataValidationFormulaDecimal(NameSpaceManager, TopNode, _formula2Path);
+  }
+
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet"></param>
+  /// <param name="address"></param>
+  /// <param name="validationType"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelDataValidationDecimal(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType,
+      XmlNode itemElementNode)
+      : base(worksheet, address, validationType, itemElementNode) {
+    Formula = new ExcelDataValidationFormulaDecimal(NameSpaceManager, TopNode, _formula1Path);
+    Formula2 = new ExcelDataValidationFormulaDecimal(NameSpaceManager, TopNode, _formula2Path);
+  }
+
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet"></param>
+  /// <param name="address"></param>
+  /// <param name="validationType"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager">For test purposes</param>
+  internal ExcelDataValidationDecimal(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(worksheet, address, validationType, itemElementNode, namespaceManager) {
+    Formula = new ExcelDataValidationFormulaDecimal(NameSpaceManager, TopNode, _formula1Path);
+    Formula2 = new ExcelDataValidationFormulaDecimal(NameSpaceManager, TopNode, _formula2Path);
+  }
+}
diff --git a/AppsheetEpplus/DataValidation/ExcelDataValidationFactory.cs b/AppsheetEpplus/DataValidation/ExcelDataValidationFactory.cs
new file mode 100644
index 0000000..bf9faa1
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/ExcelDataValidationFactory.cs
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-01
+ * Jan Källman		                License changed GPL-->LGPL  2011-12-27
+ * Raziq York 		                Added support for Any type  2014-08-08
+ *******************************************************************************/
+
+using System;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Factory class for ExcelDataValidation.
+/// </summary>
+internal static class ExcelDataValidationFactory {
+  /// <summary>
+  /// Creates an instance of <see cref="ExcelDataValidation"/> out of the given parameters.
+  /// </summary>
+  /// <param name="type"></param>
+  /// <param name="worksheet"></param>
+  /// <param name="address"></param>
+  /// <param name="itemElementNode"></param>
+  /// <returns></returns>
+  public static ExcelDataValidation Create(
+      ExcelDataValidationType type,
+      ExcelWorksheet worksheet,
+      string address,
+      XmlNode itemElementNode) {
+    ArgumentNullException.ThrowIfNull(type);
+    switch (type.Type) {
+      case eDataValidationType.Any:
+        return new ExcelDataValidationAny(worksheet, address, type, itemElementNode);
+      case eDataValidationType.TextLength:
+      case eDataValidationType.Whole:
+        return new ExcelDataValidationInt(worksheet, address, type, itemElementNode);
+      case eDataValidationType.Decimal:
+        return new ExcelDataValidationDecimal(worksheet, address, type, itemElementNode);
+      case eDataValidationType.List:
+        return new ExcelDataValidationList(worksheet, address, type, itemElementNode);
+      case eDataValidationType.DateTime:
+        return new ExcelDataValidationDateTime(worksheet, address, type, itemElementNode);
+      case eDataValidationType.Time:
+        return new ExcelDataValidationTime(worksheet, address, type, itemElementNode);
+      case eDataValidationType.Custom:
+        return new ExcelDataValidationCustom(worksheet, address, type, itemElementNode);
+      default:
+        throw new InvalidOperationException("Non supported validationtype: " + type.Type);
+    }
+  }
+}
diff --git a/AppsheetEpplus/DataValidation/ExcelDataValidationInt.cs b/AppsheetEpplus/DataValidation/ExcelDataValidationInt.cs
new file mode 100644
index 0000000..8b0c64b
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/ExcelDataValidationInt.cs
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		                License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Data validation for integer values.
+/// </summary>
+public class ExcelDataValidationInt
+    : ExcelDataValidationWithFormula2<IExcelDataValidationFormulaInt>,
+      IExcelDataValidationInt {
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet"></param>
+  /// <param name="address"></param>
+  /// <param name="validationType"></param>
+  internal ExcelDataValidationInt(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType)
+      : base(worksheet, address, validationType) {
+    Formula = new ExcelDataValidationFormulaInt(worksheet.NameSpaceManager, TopNode, _formula1Path);
+    Formula2 = new ExcelDataValidationFormulaInt(
+        worksheet.NameSpaceManager,
+        TopNode,
+        _formula2Path);
+  }
+
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet"></param>
+  /// <param name="address"></param>
+  /// <param name="validationType"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelDataValidationInt(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType,
+      XmlNode itemElementNode)
+      : base(worksheet, address, validationType, itemElementNode) {
+    Formula = new ExcelDataValidationFormulaInt(worksheet.NameSpaceManager, TopNode, _formula1Path);
+    Formula2 = new ExcelDataValidationFormulaInt(
+        worksheet.NameSpaceManager,
+        TopNode,
+        _formula2Path);
+  }
+
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet"></param>
+  /// <param name="address"></param>
+  /// <param name="validationType"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager">For test purposes</param>
+  internal ExcelDataValidationInt(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(worksheet, address, validationType, itemElementNode, namespaceManager) {
+    Formula = new ExcelDataValidationFormulaInt(NameSpaceManager, TopNode, _formula1Path);
+    Formula2 = new ExcelDataValidationFormulaInt(NameSpaceManager, TopNode, _formula2Path);
+  }
+}
diff --git a/AppsheetEpplus/DataValidation/ExcelDataValidationList.cs b/AppsheetEpplus/DataValidation/ExcelDataValidationList.cs
new file mode 100644
index 0000000..0d56dbb
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/ExcelDataValidationList.cs
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		                License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// This class represents an List data validation.
+/// </summary>
+public class ExcelDataValidationList
+    : ExcelDataValidationWithFormula<IExcelDataValidationFormulaList>,
+      IExcelDataValidationList {
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet"></param>
+  /// <param name="address"></param>
+  /// <param name="validationType"></param>
+  internal ExcelDataValidationList(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType)
+      : base(worksheet, address, validationType) {
+    Formula = new ExcelDataValidationFormulaList(NameSpaceManager, TopNode, _formula1Path);
+  }
+
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet"></param>
+  /// <param name="address"></param>
+  /// <param name="validationType"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelDataValidationList(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType,
+      XmlNode itemElementNode)
+      : base(worksheet, address, validationType, itemElementNode) {
+    Formula = new ExcelDataValidationFormulaList(NameSpaceManager, TopNode, _formula1Path);
+  }
+
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet"></param>
+  /// <param name="address"></param>
+  /// <param name="validationType"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager">Namespace manager, for test purposes</param>
+  internal ExcelDataValidationList(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(worksheet, address, validationType, itemElementNode, namespaceManager) {
+    Formula = new ExcelDataValidationFormulaList(NameSpaceManager, TopNode, _formula1Path);
+  }
+}
diff --git a/AppsheetEpplus/DataValidation/ExcelDataValidationOperator.cs b/AppsheetEpplus/DataValidation/ExcelDataValidationOperator.cs
new file mode 100644
index 0000000..7969ca6
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/ExcelDataValidationOperator.cs
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-01
+ * Jan Källman		                License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Operator for comparison between Formula and Formula2 in a validation.
+/// </summary>
+public enum ExcelDataValidationOperator {
+  Any,
+  Equal,
+  NotEqual,
+  LessThan,
+  LessThanOrEqual,
+  GreaterThan,
+  GreaterThanOrEqual,
+  Between,
+  NotBetween,
+}
diff --git a/AppsheetEpplus/DataValidation/ExcelDataValidationTime.cs b/AppsheetEpplus/DataValidation/ExcelDataValidationTime.cs
new file mode 100644
index 0000000..c8a7081
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/ExcelDataValidationTime.cs
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		                License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Validation for times (<see cref="OfficeOpenXml.DataValidation.ExcelTime"/>).
+/// </summary>
+public class ExcelDataValidationTime
+    : ExcelDataValidationWithFormula2<IExcelDataValidationFormulaTime>,
+      IExcelDataValidationTime {
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet"></param>
+  /// <param name="address"></param>
+  /// <param name="validationType"></param>
+  internal ExcelDataValidationTime(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType)
+      : base(worksheet, address, validationType) {
+    Formula = new ExcelDataValidationFormulaTime(NameSpaceManager, TopNode, _formula1Path);
+    Formula2 = new ExcelDataValidationFormulaTime(NameSpaceManager, TopNode, _formula2Path);
+  }
+
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet"></param>
+  /// <param name="address"></param>
+  /// <param name="validationType"></param>
+  /// <param name="itemElementNode"></param>
+  internal ExcelDataValidationTime(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType,
+      XmlNode itemElementNode)
+      : base(worksheet, address, validationType, itemElementNode) {
+    Formula = new ExcelDataValidationFormulaTime(NameSpaceManager, TopNode, _formula1Path);
+    Formula2 = new ExcelDataValidationFormulaTime(NameSpaceManager, TopNode, _formula2Path);
+  }
+
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet"></param>
+  /// <param name="address"></param>
+  /// <param name="validationType"></param>
+  /// <param name="itemElementNode"></param>
+  /// <param name="namespaceManager"></param>
+  internal ExcelDataValidationTime(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(worksheet, address, validationType, itemElementNode, namespaceManager) {
+    Formula = new ExcelDataValidationFormulaTime(NameSpaceManager, TopNode, _formula1Path);
+    Formula2 = new ExcelDataValidationFormulaTime(NameSpaceManager, TopNode, _formula2Path);
+  }
+}
diff --git a/AppsheetEpplus/DataValidation/ExcelDataValidationType.cs b/AppsheetEpplus/DataValidation/ExcelDataValidationType.cs
new file mode 100644
index 0000000..bad0745
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/ExcelDataValidationType.cs
@@ -0,0 +1,261 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-01
+ * Jan Källman		                License changed GPL-->LGPL  2011-12-27
+ * Raziq York 		                Added support for Any type  2014-08-08
+ *******************************************************************************/
+
+using System;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Enum for available data validation types
+/// </summary>
+public enum eDataValidationType {
+  /// <summary>
+  /// Any value
+  /// </summary>
+  Any,
+
+  /// <summary>
+  /// Integer value
+  /// </summary>
+  Whole,
+
+  /// <summary>
+  /// Decimal values
+  /// </summary>
+  Decimal,
+
+  /// <summary>
+  /// List of values
+  /// </summary>
+  List,
+
+  /// <summary>
+  /// Text length validation
+  /// </summary>
+  TextLength,
+
+  /// <summary>
+  /// DateTime validation
+  /// </summary>
+  DateTime,
+
+  /// <summary>
+  /// Time validation
+  /// </summary>
+  Time,
+
+  /// <summary>
+  /// Custom validation
+  /// </summary>
+  Custom,
+}
+
+internal static class DataValidationSchemaNames {
+  public const string Any = "";
+  public const string Whole = "whole";
+  public const string Decimal = "decimal";
+  public const string List = "list";
+  public const string TextLength = "textLength";
+  public const string Date = "date";
+  public const string Time = "time";
+  public const string Custom = "custom";
+}
+
+/// <summary>
+/// Types of datavalidation
+/// </summary>
+public class ExcelDataValidationType {
+  private ExcelDataValidationType(
+      eDataValidationType validationType,
+      bool allowOperator,
+      string schemaName) {
+    Type = validationType;
+    AllowOperator = allowOperator;
+    SchemaName = schemaName;
+  }
+
+  /// <summary>
+  /// Validation type
+  /// </summary>
+  public eDataValidationType Type { get; private set; }
+
+  internal string SchemaName { get; private set; }
+
+  /// <summary>
+  /// This type allows operator to be set
+  /// </summary>
+  internal bool AllowOperator { get; private set; }
+
+  internal static ExcelDataValidationType GetBySchemaName(string schemaName) {
+    switch (schemaName) {
+      case DataValidationSchemaNames.Any:
+        return Any;
+      case DataValidationSchemaNames.Whole:
+        return Whole;
+      case DataValidationSchemaNames.Decimal:
+        return Decimal;
+      case DataValidationSchemaNames.List:
+        return List;
+      case DataValidationSchemaNames.TextLength:
+        return TextLength;
+      case DataValidationSchemaNames.Date:
+        return DateTime;
+      case DataValidationSchemaNames.Time:
+        return Time;
+      case DataValidationSchemaNames.Custom:
+        return Custom;
+      default:
+        throw new ArgumentException("Invalid schemaname: " + schemaName);
+    }
+  }
+
+  /// <summary>
+  /// Overridden Equals, compares on internal validation type
+  /// </summary>
+  /// <param name="obj"></param>
+  /// <returns></returns>
+  public override bool Equals(object obj) {
+    if (!(obj is ExcelDataValidationType type)) {
+      return false;
+    }
+    return type.Type == Type;
+  }
+
+  /// <summary>
+  /// Overrides GetHashCode()
+  /// </summary>
+  /// <returns></returns>
+  public override int GetHashCode() {
+    return base.GetHashCode();
+  }
+
+  /// <summary>
+  /// Integer values
+  /// </summary>
+  private static ExcelDataValidationType _any;
+
+  public static ExcelDataValidationType Any {
+    get {
+      if (_any == null) {
+        _any = new(eDataValidationType.Any, false, DataValidationSchemaNames.Any);
+      }
+      return _any;
+    }
+  }
+
+  /// <summary>
+  /// Integer values
+  /// </summary>
+  private static ExcelDataValidationType _whole;
+
+  public static ExcelDataValidationType Whole {
+    get {
+      if (_whole == null) {
+        _whole = new(eDataValidationType.Whole, true, DataValidationSchemaNames.Whole);
+      }
+      return _whole;
+    }
+  }
+
+  /// <summary>
+  /// List of allowed values
+  /// </summary>
+  private static ExcelDataValidationType _list;
+
+  public static ExcelDataValidationType List {
+    get {
+      if (_list == null) {
+        _list = new(eDataValidationType.List, false, DataValidationSchemaNames.List);
+      }
+      return _list;
+    }
+  }
+
+  private static ExcelDataValidationType _decimal;
+
+  public static ExcelDataValidationType Decimal {
+    get {
+      if (_decimal == null) {
+        _decimal = new(eDataValidationType.Decimal, true, DataValidationSchemaNames.Decimal);
+      }
+      return _decimal;
+    }
+  }
+
+  private static ExcelDataValidationType _textLength;
+
+  public static ExcelDataValidationType TextLength {
+    get {
+      if (_textLength == null) {
+        _textLength = new(
+            eDataValidationType.TextLength,
+            true,
+            DataValidationSchemaNames.TextLength);
+      }
+      return _textLength;
+    }
+  }
+
+  private static ExcelDataValidationType _dateTime;
+
+  public static ExcelDataValidationType DateTime {
+    get {
+      if (_dateTime == null) {
+        _dateTime = new(eDataValidationType.DateTime, true, DataValidationSchemaNames.Date);
+      }
+      return _dateTime;
+    }
+  }
+
+  private static ExcelDataValidationType _time;
+
+  public static ExcelDataValidationType Time {
+    get {
+      if (_time == null) {
+        _time = new(eDataValidationType.Time, true, DataValidationSchemaNames.Time);
+      }
+      return _time;
+    }
+  }
+
+  private static ExcelDataValidationType _custom;
+
+  public static ExcelDataValidationType Custom {
+    get {
+      if (_custom == null) {
+        _custom = new(eDataValidationType.Custom, true, DataValidationSchemaNames.Custom);
+      }
+      return _custom;
+    }
+  }
+}
diff --git a/AppsheetEpplus/DataValidation/ExcelDataValidationWarningStyle.cs b/AppsheetEpplus/DataValidation/ExcelDataValidationWarningStyle.cs
new file mode 100644
index 0000000..17ce8dc
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/ExcelDataValidationWarningStyle.cs
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-01
+ * Jan Källman		                License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// warning style, controls how Excel will handle invalid changes.
+/// </summary>
+public enum ExcelDataValidationWarningStyle {
+  /// <summary>
+  /// warning style will be excluded
+  /// </summary>
+  Undefined,
+
+  /// <summary>
+  /// stop warning style, invalid changes will not be accepted
+  /// </summary>
+  Stop,
+
+  /// <summary>
+  /// warning will be presented when an attempt to an invalid change is done, but the change will be accepted.
+  /// </summary>
+  Warning,
+
+  /// <summary>
+  /// information warning style.
+  /// </summary>
+  Information,
+}
diff --git a/AppsheetEpplus/DataValidation/ExcelDataValidationWithFormula.cs b/AppsheetEpplus/DataValidation/ExcelDataValidationWithFormula.cs
new file mode 100644
index 0000000..27affda
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/ExcelDataValidationWithFormula.cs
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-01
+ * Jan Källman		                License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+using System;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// A validation containing a formula
+/// </summary>
+/// <typeparam name="T"></typeparam>
+public class ExcelDataValidationWithFormula<T> : ExcelDataValidation
+    where T : IExcelDataValidationFormula {
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet"></param>
+  /// <param name="address"></param>
+  /// <param name="validationType"></param>
+  internal ExcelDataValidationWithFormula(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType)
+      : this(worksheet, address, validationType, null) {}
+
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet">Worksheet that owns the validation</param>
+  /// <param name="itemElementNode">Xml top node (dataValidations)</param>
+  /// <param name="validationType">Data validation type</param>
+  /// <param name="address">address for data validation</param>
+  internal ExcelDataValidationWithFormula(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType,
+      XmlNode itemElementNode)
+      : base(worksheet, address, validationType, itemElementNode) {}
+
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet">Worksheet that owns the validation</param>
+  /// <param name="itemElementNode">Xml top node (dataValidations)</param>
+  /// <param name="validationType">Data validation type</param>
+  /// <param name="address">address for data validation</param>
+  /// <param name="namespaceManager">for test purposes</param>
+  internal ExcelDataValidationWithFormula(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(worksheet, address, validationType, itemElementNode, namespaceManager) {}
+
+  /// <summary>
+  /// Formula - Either a {T} value (except for custom validation) or a spreadsheet formula
+  /// </summary>
+  public T Formula { get; protected set; }
+
+  public override void Validate() {
+    base.Validate();
+    if (Operator == ExcelDataValidationOperator.Between
+        || Operator == ExcelDataValidationOperator.NotBetween) {
+      if (string.IsNullOrEmpty(Formula2Internal)) {
+        throw new InvalidOperationException(
+            "Validation of "
+                + Address.Address
+                + " failed: Formula2 must be set if operator is 'between' or 'notBetween'");
+      }
+    }
+  }
+}
diff --git a/AppsheetEpplus/DataValidation/ExcelDataValidationWithFormula2.cs b/AppsheetEpplus/DataValidation/ExcelDataValidationWithFormula2.cs
new file mode 100644
index 0000000..7b18cb3
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/ExcelDataValidationWithFormula2.cs
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-01
+ * Jan Källman		                License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+public class ExcelDataValidationWithFormula2<T> : ExcelDataValidationWithFormula<T>
+    where T : IExcelDataValidationFormula {
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet"></param>
+  /// <param name="address"></param>
+  /// <param name="validationType"></param>
+  internal ExcelDataValidationWithFormula2(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType)
+      : this(worksheet, address, validationType, null) {}
+
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet">Worksheet that owns the validation</param>
+  /// <param name="itemElementNode">Xml top node (dataValidations)</param>
+  /// <param name="validationType">Data validation type</param>
+  /// <param name="address">address for data validation</param>
+  internal ExcelDataValidationWithFormula2(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType,
+      XmlNode itemElementNode)
+      : base(worksheet, address, validationType, itemElementNode) {}
+
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="worksheet">Worksheet that owns the validation</param>
+  /// <param name="itemElementNode">Xml top node (dataValidations)</param>
+  /// <param name="validationType">Data validation type</param>
+  /// <param name="address">address for data validation</param>
+  /// <param name="namespaceManager">for test purposes</param>
+  internal ExcelDataValidationWithFormula2(
+      ExcelWorksheet worksheet,
+      string address,
+      ExcelDataValidationType validationType,
+      XmlNode itemElementNode,
+      XmlNamespaceManager namespaceManager)
+      : base(worksheet, address, validationType, itemElementNode, namespaceManager) {}
+
+  /// <summary>
+  /// Formula - Either a {T} value or a spreadsheet formula
+  /// </summary>
+  public T Formula2 { get; protected set; }
+}
diff --git a/AppsheetEpplus/DataValidation/ExcelTime.cs b/AppsheetEpplus/DataValidation/ExcelTime.cs
new file mode 100644
index 0000000..7aa6a6e
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/ExcelTime.cs
@@ -0,0 +1,224 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-01
+ * Jan Källman		                License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+using System;
+using System.Globalization;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Represents a time between 00:00:00 and 23:59:59
+/// </summary>
+public class ExcelTime {
+  private event EventHandler TimeChangedEvent;
+
+  private readonly decimal SecondsPerDay = 3600 * 24;
+  private readonly decimal SecondsPerHour = 3600;
+  private readonly decimal SecondsPerMinute = 60;
+
+  /// <summary>
+  /// Max number of decimals when rounding.
+  /// </summary>
+  public const int NumberOfDecimals = 15;
+
+  /// <summary>
+  /// Default constructor
+  /// </summary>
+  public ExcelTime() {}
+
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="value">An existing time for initialization</param>
+  public ExcelTime(decimal value) {
+    if (value < 0M) {
+      throw new ArgumentException("Value cannot be less than 0");
+    }
+    if (value >= 1M) {
+      throw new ArgumentException("Value cannot be greater or equal to 1");
+    }
+    Init(value);
+  }
+
+  private void Init(decimal value) {
+    // handle hour
+    decimal totalSeconds = value * SecondsPerDay;
+    decimal hour = Math.Floor(totalSeconds / SecondsPerHour);
+    Hour = (int)hour;
+
+    // handle minute
+    decimal remainingSeconds = totalSeconds - (hour * SecondsPerHour);
+    decimal minute = Math.Floor(remainingSeconds / SecondsPerMinute);
+    Minute = (int)minute;
+
+    // handle second
+    remainingSeconds = totalSeconds - (hour * SecondsPerHour) - (minute * SecondsPerMinute);
+    decimal second = Math.Round(remainingSeconds, MidpointRounding.AwayFromZero);
+    // Second might be rounded to 60... the SetSecond method handles that.
+    SetSecond((int)second);
+  }
+
+  /// <summary>
+  /// If we are unlucky second might be rounded up to 60. This will have the minute to be raised and might affect the hour.
+  /// </summary>
+  /// <param name="value"></param>
+  private void SetSecond(int value) {
+    if (value == 60) {
+      Second = 0;
+      var minute = Minute + 1;
+      SetMinute(minute);
+    } else {
+      Second = value;
+    }
+  }
+
+  private void SetMinute(int value) {
+    if (value == 60) {
+      Minute = 0;
+      var hour = Hour + 1;
+      SetHour(hour);
+    } else {
+      Minute = value;
+    }
+  }
+
+  private void SetHour(int value) {
+    if (value == 24) {
+      Hour = 0;
+    }
+  }
+
+  internal event EventHandler TimeChanged {
+    add => TimeChangedEvent += value;
+    remove => TimeChangedEvent -= value;
+  }
+
+  private void OnTimeChanged() {
+    if (TimeChangedEvent != null) {
+      TimeChangedEvent(this, EventArgs.Empty);
+    }
+  }
+
+  private int _hour;
+
+  /// <summary>
+  /// Hour between 0 and 23
+  /// </summary>
+  public int Hour {
+    get => _hour;
+    set {
+      if (value < 0) {
+        throw new InvalidOperationException("Value for hour cannot be negative");
+      }
+      if (value > 23) {
+        throw new InvalidOperationException("Value for hour cannot be greater than 23");
+      }
+      _hour = value;
+      OnTimeChanged();
+    }
+  }
+
+  private int _minute;
+
+  /// <summary>
+  /// Minute between 0 and 59
+  /// </summary>
+  public int Minute {
+    get => _minute;
+    set {
+      if (value < 0) {
+        throw new InvalidOperationException("Value for minute cannot be negative");
+      }
+      if (value > 59) {
+        throw new InvalidOperationException("Value for minute cannot be greater than 59");
+      }
+      _minute = value;
+      OnTimeChanged();
+    }
+  }
+
+  private int? _second;
+
+  /// <summary>
+  /// Second between 0 and 59
+  /// </summary>
+  public int? Second {
+    get => _second;
+    set {
+      if (value < 0) {
+        throw new InvalidOperationException("Value for second cannot be negative");
+      }
+      if (value > 59) {
+        throw new InvalidOperationException("Value for second cannot be greater than 59");
+      }
+      _second = value;
+      OnTimeChanged();
+    }
+  }
+
+  private decimal Round(decimal value) {
+    return Math.Round(value, NumberOfDecimals);
+  }
+
+  private decimal ToSeconds() {
+    var result = Hour * SecondsPerHour;
+    result += Minute * SecondsPerMinute;
+    result += Second ?? 0;
+    return result;
+  }
+
+  /// <summary>
+  /// Returns the excel decimal representation of a time.
+  /// </summary>
+  /// <returns></returns>
+  public decimal ToExcelTime() {
+    var seconds = ToSeconds();
+    return Round(seconds / SecondsPerDay);
+  }
+
+  /// <summary>
+  /// Returns the excel decimal representation of a time as a string.
+  /// </summary>
+  /// <returns></returns>
+  public string ToExcelString() {
+    return ToExcelTime().ToString(CultureInfo.InvariantCulture);
+  }
+
+  public override string ToString() {
+    var second = Second ?? 0;
+    return string.Format(
+        "{0}:{1}:{2}",
+        Hour < 10 ? "0" + Hour : Hour.ToString(),
+        Minute < 10 ? "0" + Minute : Minute.ToString(),
+        second < 10 ? "0" + second : second.ToString());
+  }
+}
diff --git a/AppsheetEpplus/DataValidation/Formulas/Contracts/IExcelDataValidationFormula.cs b/AppsheetEpplus/DataValidation/Formulas/Contracts/IExcelDataValidationFormula.cs
new file mode 100644
index 0000000..206c5fe
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Formulas/Contracts/IExcelDataValidationFormula.cs
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Interface for a data validation formula
+/// </summary>
+public interface IExcelDataValidationFormula {
+  /// <summary>
+  /// An excel formula
+  /// </summary>
+  string ExcelFormula { get; set; }
+}
diff --git a/AppsheetEpplus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaDateTime.cs b/AppsheetEpplus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaDateTime.cs
new file mode 100644
index 0000000..c15a609
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaDateTime.cs
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+using System;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Validation formula interface for <see cref="DateTime"/>
+/// </summary>
+public interface IExcelDataValidationFormulaDateTime
+    : IExcelDataValidationFormulaWithValue<DateTime?> {}
diff --git a/AppsheetEpplus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaDecimal.cs b/AppsheetEpplus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaDecimal.cs
new file mode 100644
index 0000000..19a9cc2
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaDecimal.cs
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Interface for a data validation formula of <see cref="System.Single">float</see> value
+/// </summary>
+public interface IExcelDataValidationFormulaDecimal
+    : IExcelDataValidationFormulaWithValue<double?> {}
diff --git a/AppsheetEpplus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaInt.cs b/AppsheetEpplus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaInt.cs
new file mode 100644
index 0000000..fb13e17
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaInt.cs
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Interface for a data validation formula of <see cref="System.Int32"/> value
+/// </summary>
+public interface IExcelDataValidationFormulaInt : IExcelDataValidationFormulaWithValue<int?> {}
diff --git a/AppsheetEpplus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaList.cs b/AppsheetEpplus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaList.cs
new file mode 100644
index 0000000..d827f9e
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaList.cs
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Interface for a data validation of list type
+/// </summary>
+public interface IExcelDataValidationFormulaList : IExcelDataValidationFormula {
+  /// <summary>
+  /// A list of value strings.
+  /// </summary>
+  IList<string> Values { get; }
+}
diff --git a/AppsheetEpplus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaTime.cs b/AppsheetEpplus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaTime.cs
new file mode 100644
index 0000000..1e27a6d
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaTime.cs
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public interface IExcelDataValidationFormulaTime
+    : IExcelDataValidationFormulaWithValue<ExcelTime> {}
diff --git a/AppsheetEpplus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaWithValue.cs b/AppsheetEpplus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaWithValue.cs
new file mode 100644
index 0000000..f508bec
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaWithValue.cs
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Interface for a formula with a value
+/// </summary>
+/// <typeparam name="T"></typeparam>
+public interface IExcelDataValidationFormulaWithValue<T> : IExcelDataValidationFormula {
+  /// <summary>
+  /// The value.
+  /// </summary>
+  T Value { get; set; }
+}
diff --git a/AppsheetEpplus/DataValidation/Formulas/ExcelDataValidationFormula.cs b/AppsheetEpplus/DataValidation/Formulas/ExcelDataValidationFormula.cs
new file mode 100644
index 0000000..8554d5b
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Formulas/ExcelDataValidationFormula.cs
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+using System;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Enumeration representing the state of an <see cref="ExcelDataValidationFormulaValue{T}"/>
+/// </summary>
+internal enum FormulaState {
+  /// <summary>
+  /// Value is set
+  /// </summary>
+  Value,
+
+  /// <summary>
+  /// Formula is set
+  /// </summary>
+  Formula,
+}
+
+/// <summary>
+/// Base class for a formula
+/// </summary>
+internal abstract class ExcelDataValidationFormula : XmlHelper {
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="namespaceManager">Namespacemanger of the worksheet</param>
+  /// <param name="topNode">validation top node</param>
+  /// <param name="formulaPath">xml path of the current formula</param>
+  public ExcelDataValidationFormula(
+      XmlNamespaceManager namespaceManager,
+      XmlNode topNode,
+      string formulaPath)
+      : base(namespaceManager, topNode) {
+    ArgumentException.ThrowIfNullOrEmpty(formulaPath);
+    FormulaPath = formulaPath;
+  }
+
+  private string _formula;
+
+  protected string FormulaPath { get; private set; }
+
+  /// <summary>
+  /// State of the validationformula, i.e. tells if value or formula is set
+  /// </summary>
+  protected FormulaState State { get; set; }
+
+  /// <summary>
+  /// A formula which output must match the current validation type
+  /// </summary>
+  public string ExcelFormula {
+    get => _formula;
+    set {
+      if (!string.IsNullOrEmpty(value)) {
+        ResetValue();
+        State = FormulaState.Formula;
+      }
+      if (value != null && value.Length > 255) {
+        throw new InvalidOperationException(
+            "The length of a DataValidation formula cannot exceed 255 characters");
+      }
+      //var val = SqRefUtility.ToSqRefAddress(value);
+      _formula = value;
+      SetXmlNodeString(FormulaPath, value);
+    }
+  }
+
+  internal abstract void ResetValue();
+
+  /// <summary>
+  /// This value will be stored in the xml. Can be overridden by subclasses
+  /// </summary>
+  internal virtual string GetXmlValue() {
+    if (State == FormulaState.Formula) {
+      return ExcelFormula;
+    }
+    return GetValueAsString();
+  }
+
+  /// <summary>
+  /// Returns the value as a string. Must be implemented by subclasses
+  /// </summary>
+  /// <returns></returns>
+  protected abstract string GetValueAsString();
+}
diff --git a/AppsheetEpplus/DataValidation/Formulas/ExcelDataValidationFormulaCustom.cs b/AppsheetEpplus/DataValidation/Formulas/ExcelDataValidationFormulaCustom.cs
new file mode 100644
index 0000000..7f01bd9
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Formulas/ExcelDataValidationFormulaCustom.cs
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+///
+/// </summary>
+internal class ExcelDataValidationFormulaCustom
+    : ExcelDataValidationFormula,
+      IExcelDataValidationFormula {
+  public ExcelDataValidationFormulaCustom(
+      XmlNamespaceManager namespaceManager,
+      XmlNode topNode,
+      string formulaPath)
+      : base(namespaceManager, topNode, formulaPath) {
+    var value = GetXmlNodeString(formulaPath);
+    if (!string.IsNullOrEmpty(value)) {
+      ExcelFormula = value;
+    }
+    State = FormulaState.Formula;
+  }
+
+  internal override string GetXmlValue() {
+    return ExcelFormula;
+  }
+
+  protected override string GetValueAsString() {
+    return ExcelFormula;
+  }
+
+  internal override void ResetValue() {
+    ExcelFormula = null;
+  }
+}
diff --git a/AppsheetEpplus/DataValidation/Formulas/ExcelDataValidationFormulaDateTime.cs b/AppsheetEpplus/DataValidation/Formulas/ExcelDataValidationFormulaDateTime.cs
new file mode 100644
index 0000000..3c6e6a1
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Formulas/ExcelDataValidationFormulaDateTime.cs
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+using System;
+using System.Globalization;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+internal class ExcelDataValidationFormulaDateTime
+    : ExcelDataValidationFormulaValue<DateTime?>,
+      IExcelDataValidationFormulaDateTime {
+  public ExcelDataValidationFormulaDateTime(
+      XmlNamespaceManager namespaceManager,
+      XmlNode topNode,
+      string formulaPath)
+      : base(namespaceManager, topNode, formulaPath) {
+    var value = GetXmlNodeString(formulaPath);
+    if (!string.IsNullOrEmpty(value)) {
+      if (double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var oADate)) {
+        Value = DateTime.FromOADate(oADate);
+      } else {
+        ExcelFormula = value;
+      }
+    }
+  }
+
+  protected override string GetValueAsString() {
+    return Value.HasValue
+        ? Value.Value.ToOADate().ToString(CultureInfo.InvariantCulture)
+        : string.Empty;
+  }
+}
diff --git a/AppsheetEpplus/DataValidation/Formulas/ExcelDataValidationFormulaDecimal.cs b/AppsheetEpplus/DataValidation/Formulas/ExcelDataValidationFormulaDecimal.cs
new file mode 100644
index 0000000..cfdc5fe
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Formulas/ExcelDataValidationFormulaDecimal.cs
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+using System.Globalization;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+///
+/// </summary>
+internal class ExcelDataValidationFormulaDecimal
+    : ExcelDataValidationFormulaValue<double?>,
+      IExcelDataValidationFormulaDecimal {
+  public ExcelDataValidationFormulaDecimal(
+      XmlNamespaceManager namespaceManager,
+      XmlNode topNode,
+      string formulaPath)
+      : base(namespaceManager, topNode, formulaPath) {
+    var value = GetXmlNodeString(formulaPath);
+    if (!string.IsNullOrEmpty(value)) {
+      if (double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var dValue)) {
+        Value = dValue;
+      } else {
+        ExcelFormula = value;
+      }
+    }
+  }
+
+  protected override string GetValueAsString() {
+    return Value.HasValue
+        ? Value.Value.ToString("R15", CultureInfo.InvariantCulture)
+        : string.Empty;
+  }
+}
diff --git a/AppsheetEpplus/DataValidation/Formulas/ExcelDataValidationFormulaInt.cs b/AppsheetEpplus/DataValidation/Formulas/ExcelDataValidationFormulaInt.cs
new file mode 100644
index 0000000..0d6f916
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Formulas/ExcelDataValidationFormulaInt.cs
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+internal class ExcelDataValidationFormulaInt
+    : ExcelDataValidationFormulaValue<int?>,
+      IExcelDataValidationFormulaInt {
+  public ExcelDataValidationFormulaInt(
+      XmlNamespaceManager namespaceManager,
+      XmlNode topNode,
+      string formulaPath)
+      : base(namespaceManager, topNode, formulaPath) {
+    var value = GetXmlNodeString(formulaPath);
+    if (!string.IsNullOrEmpty(value)) {
+      if (int.TryParse(value, out var intValue)) {
+        Value = intValue;
+      } else {
+        ExcelFormula = value;
+      }
+    }
+  }
+
+  protected override string GetValueAsString() {
+    return Value.HasValue ? Value.Value.ToString() : string.Empty;
+  }
+}
diff --git a/AppsheetEpplus/DataValidation/Formulas/ExcelDataValidationFormulaList.cs b/AppsheetEpplus/DataValidation/Formulas/ExcelDataValidationFormulaList.cs
new file mode 100644
index 0000000..8bff939
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Formulas/ExcelDataValidationFormulaList.cs
@@ -0,0 +1,190 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+internal class ExcelDataValidationFormulaList
+    : ExcelDataValidationFormula,
+      IExcelDataValidationFormulaList {
+  private class DataValidationList : IList<string>, ICollection {
+    private readonly IList<string> _items = new List<string>();
+    private EventHandler<EventArgs> _listChanged;
+
+    public event EventHandler<EventArgs> ListChanged {
+      add => _listChanged += value;
+      remove => _listChanged -= value;
+    }
+
+    private void OnListChanged() {
+      if (_listChanged != null) {
+        _listChanged(this, EventArgs.Empty);
+      }
+    }
+
+    int IList<string>.IndexOf(string item) {
+      return _items.IndexOf(item);
+    }
+
+    void IList<string>.Insert(int index, string item) {
+      _items.Insert(index, item);
+      OnListChanged();
+    }
+
+    void IList<string>.RemoveAt(int index) {
+      _items.RemoveAt(index);
+      OnListChanged();
+    }
+
+    string IList<string>.this[int index] {
+      get => _items[index];
+      set {
+        _items[index] = value;
+        OnListChanged();
+      }
+    }
+
+    void ICollection<string>.Add(string item) {
+      _items.Add(item);
+      OnListChanged();
+    }
+
+    void ICollection<string>.Clear() {
+      _items.Clear();
+      OnListChanged();
+    }
+
+    bool ICollection<string>.Contains(string item) {
+      return _items.Contains(item);
+    }
+
+    void ICollection<string>.CopyTo(string[] array, int arrayIndex) {
+      _items.CopyTo(array, arrayIndex);
+    }
+
+    int ICollection<string>.Count => _items.Count;
+
+    bool ICollection<string>.IsReadOnly => false;
+
+    bool ICollection<string>.Remove(string item) {
+      var retVal = _items.Remove(item);
+      OnListChanged();
+      return retVal;
+    }
+
+    IEnumerator<string> IEnumerable<string>.GetEnumerator() {
+      return _items.GetEnumerator();
+    }
+
+    IEnumerator IEnumerable.GetEnumerator() {
+      return _items.GetEnumerator();
+    }
+
+    public void CopyTo(Array array, int index) {
+      _items.CopyTo((string[])array, index);
+    }
+
+    int ICollection.Count => _items.Count;
+
+    public bool IsSynchronized => ((ICollection)_items).IsSynchronized;
+
+    public object SyncRoot => ((ICollection)_items).SyncRoot;
+  }
+
+  public ExcelDataValidationFormulaList(
+      XmlNamespaceManager namespaceManager,
+      XmlNode itemNode,
+      string formulaPath)
+      : base(namespaceManager, itemNode, formulaPath) {
+    ArgumentException.ThrowIfNullOrEmpty(formulaPath);
+    _formulaPath = formulaPath;
+    var values = new DataValidationList();
+    values.ListChanged += values_ListChanged;
+    Values = values;
+    SetInitialValues();
+  }
+
+  private readonly string _formulaPath;
+
+  private void SetInitialValues() {
+    var value = GetXmlNodeString(_formulaPath);
+    if (!string.IsNullOrEmpty(value)) {
+      if (value.StartsWith("\"") && value.EndsWith("\"")) {
+        value = value.TrimStart('"').TrimEnd('"');
+        var items = value.Split([','], StringSplitOptions.RemoveEmptyEntries);
+        foreach (var item in items) {
+          Values.Add(item);
+        }
+      } else {
+        ExcelFormula = value;
+      }
+    }
+  }
+
+  private void values_ListChanged(object sender, EventArgs e) {
+    if (Values.Count > 0) {
+      State = FormulaState.Value;
+    }
+    var valuesAsString = GetValueAsString();
+    // Excel supports max 255 characters in this field.
+    if (valuesAsString.Length > 255) {
+      throw new InvalidOperationException(
+          "The total length of a DataValidation list cannot exceed 255 characters");
+    }
+    SetXmlNodeString(_formulaPath, valuesAsString);
+  }
+
+  public IList<string> Values { get; private set; }
+
+  protected override string GetValueAsString() {
+    var sb = new StringBuilder();
+    foreach (var val in Values) {
+      if (sb.Length == 0) {
+        sb.Append("\"");
+        sb.Append(val);
+      } else {
+        sb.AppendFormat(",{0}", val);
+      }
+    }
+    sb.Append("\"");
+    return sb.ToString();
+  }
+
+  internal override void ResetValue() {
+    Values.Clear();
+  }
+}
diff --git a/AppsheetEpplus/DataValidation/Formulas/ExcelDataValidationFormulaTime.cs b/AppsheetEpplus/DataValidation/Formulas/ExcelDataValidationFormulaTime.cs
new file mode 100644
index 0000000..eb864e9
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Formulas/ExcelDataValidationFormulaTime.cs
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		                License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+using System;
+using System.Globalization;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+internal class ExcelDataValidationFormulaTime
+    : ExcelDataValidationFormulaValue<ExcelTime>,
+      IExcelDataValidationFormulaTime {
+  public ExcelDataValidationFormulaTime(
+      XmlNamespaceManager namespaceManager,
+      XmlNode topNode,
+      string formulaPath)
+      : base(namespaceManager, topNode, formulaPath) {
+    var value = GetXmlNodeString(formulaPath);
+    if (!string.IsNullOrEmpty(value)) {
+      if (decimal.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var time)) {
+        Value = new(time);
+      } else {
+        Value = new();
+        ExcelFormula = value;
+      }
+    } else {
+      Value = new();
+    }
+    Value.TimeChanged += Value_TimeChanged;
+  }
+
+  private void Value_TimeChanged(object sender, EventArgs e) {
+    SetXmlNodeString(FormulaPath, Value.ToExcelString());
+  }
+
+  protected override string GetValueAsString() {
+    if (State == FormulaState.Value) {
+      return Value.ToExcelString();
+    }
+    return string.Empty;
+  }
+
+  internal override void ResetValue() {
+    Value = new();
+  }
+}
diff --git a/AppsheetEpplus/DataValidation/Formulas/ExcelDataValidationFormulaValue.cs b/AppsheetEpplus/DataValidation/Formulas/ExcelDataValidationFormulaValue.cs
new file mode 100644
index 0000000..c7194d8
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/Formulas/ExcelDataValidationFormulaValue.cs
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-08
+ * Jan Källman		                License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// This class represents a validation formula. Its value can be specified as a value of the specified datatype or as a formula.
+/// </summary>
+/// <typeparam name="T"></typeparam>
+internal abstract class ExcelDataValidationFormulaValue<T> : ExcelDataValidationFormula {
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="namespaceManager">Namespacemanger of the worksheet</param>
+  /// <param name="topNode">validation top node</param>
+  /// <param name="formulaPath">xml path of the current formula</param>
+  public ExcelDataValidationFormulaValue(
+      XmlNamespaceManager namespaceManager,
+      XmlNode topNode,
+      string formulaPath)
+      : base(namespaceManager, topNode, formulaPath) {}
+
+  private T _value;
+
+  /// <summary>
+  /// Typed value
+  /// </summary>
+  public T Value {
+    get => _value;
+    set {
+      State = FormulaState.Value;
+      _value = value;
+      SetXmlNodeString(FormulaPath, GetValueAsString());
+    }
+  }
+
+  internal override void ResetValue() {
+    Value = default(T);
+  }
+}
diff --git a/AppsheetEpplus/DataValidation/IRangeDataValidation.cs b/AppsheetEpplus/DataValidation/IRangeDataValidation.cs
new file mode 100644
index 0000000..b34d626
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/IRangeDataValidation.cs
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-03-23
+ * Jan Källman		                License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Provides functionality for adding datavalidation to a range (<see cref="ExcelRangeBase"/>). Each method will
+/// return a configurable validation.
+/// </summary>
+public interface IRangeDataValidation {
+  /// <summary>
+  /// Adds a <see cref="IExcelDataValidationAny"/> to the range.
+  /// </summary>
+  /// <returns>A <see cref="ExcelDataValidationAny"/> that can be configured for any validation</returns>
+  IExcelDataValidationAny AddAnyDataValidation();
+
+  /// <summary>
+  /// Adds a <see cref="IExcelDataValidationInt"/> to the range
+  /// </summary>
+  /// <returns>A <see cref="ExcelDataValidationInt"/> that can be configured for integer data validation</returns>
+  IExcelDataValidationInt AddIntegerDataValidation();
+
+  /// <summary>
+  /// Adds a <see cref="ExcelDataValidationDecimal"/> to the range
+  /// </summary>
+  /// <returns>A <see cref="ExcelDataValidationDecimal"/> that can be configured for decimal data validation</returns>
+  IExcelDataValidationDecimal AddDecimalDataValidation();
+
+  /// <summary>
+  /// Adds a <see cref="ExcelDataValidationDateTime"/> to the range
+  /// </summary>
+  /// <returns>A <see cref="ExcelDataValidationDecimal"/> that can be configured for datetime data validation</returns>
+  IExcelDataValidationDateTime AddDateTimeDataValidation();
+
+  /// <summary>
+  /// Adds a <see cref="IExcelDataValidationList"/> to the range
+  /// </summary>
+  /// <returns>A <see cref="ExcelDataValidationList"/> that can be configured for datetime data validation</returns>
+  IExcelDataValidationList AddListDataValidation();
+
+  /// <summary>
+  /// Adds a <see cref="IExcelDataValidationInt"/> regarding text length validation to the range.
+  /// </summary>
+  /// <returns></returns>
+  IExcelDataValidationInt AddTextLengthDataValidation();
+
+  /// <summary>
+  /// Adds a <see cref="IExcelDataValidationTime"/> to the range.
+  /// </summary>
+  /// <returns>A <see cref="IExcelDataValidationTime"/> that can be configured for time data validation</returns>
+  IExcelDataValidationTime AddTimeDataValidation();
+
+  /// <summary>
+  /// Adds a <see cref="IExcelDataValidationCustom"/> to the range.
+  /// </summary>
+  /// <returns>A <see cref="IExcelDataValidationCustom"/> that can be configured for custom validation</returns>
+  IExcelDataValidationCustom AddCustomDataValidation();
+}
diff --git a/AppsheetEpplus/DataValidation/RangeDataValidation.cs b/AppsheetEpplus/DataValidation/RangeDataValidation.cs
new file mode 100644
index 0000000..48f6f21
--- /dev/null
+++ b/AppsheetEpplus/DataValidation/RangeDataValidation.cs
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-03-23
+ * Jan Källman		                License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+using System;
+
+namespace AppsheetEpplus;
+
+internal class RangeDataValidation : IRangeDataValidation {
+  public RangeDataValidation(ExcelWorksheet worksheet, string address) {
+    ArgumentNullException.ThrowIfNull(worksheet);
+    ArgumentException.ThrowIfNullOrEmpty(address);
+    _worksheet = worksheet;
+    _address = address;
+  }
+
+  private readonly ExcelWorksheet _worksheet;
+  private readonly string _address;
+
+  public IExcelDataValidationAny AddAnyDataValidation() {
+    return _worksheet.DataValidations.AddAnyValidation(_address);
+  }
+
+  public IExcelDataValidationInt AddIntegerDataValidation() {
+    return _worksheet.DataValidations.AddIntegerValidation(_address);
+  }
+
+  public IExcelDataValidationDecimal AddDecimalDataValidation() {
+    return _worksheet.DataValidations.AddDecimalValidation(_address);
+  }
+
+  public IExcelDataValidationDateTime AddDateTimeDataValidation() {
+    return _worksheet.DataValidations.AddDateTimeValidation(_address);
+  }
+
+  public IExcelDataValidationList AddListDataValidation() {
+    return _worksheet.DataValidations.AddListValidation(_address);
+  }
+
+  public IExcelDataValidationInt AddTextLengthDataValidation() {
+    return _worksheet.DataValidations.AddTextLengthValidation(_address);
+  }
+
+  public IExcelDataValidationTime AddTimeDataValidation() {
+    return _worksheet.DataValidations.AddTimeValidation(_address);
+  }
+
+  public IExcelDataValidationCustom AddCustomDataValidation() {
+    return _worksheet.DataValidations.AddCustomValidation(_address);
+  }
+}
diff --git a/AppsheetEpplus/Drawing/Vml/ExcelVmlDrawingBase.cs b/AppsheetEpplus/Drawing/Vml/ExcelVmlDrawingBase.cs
new file mode 100644
index 0000000..0ab4392
--- /dev/null
+++ b/AppsheetEpplus/Drawing/Vml/ExcelVmlDrawingBase.cs
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		Initial Release		        2010-06-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System.Collections.Immutable;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Horizontal Alingment
+/// </summary>
+public enum eTextAlignHorizontalVml {
+  Left,
+  Center,
+  Right,
+}
+
+/// <summary>
+/// Vertical Alingment
+/// </summary>
+public enum eTextAlignVerticalVml {
+  Top,
+  Center,
+  Bottom,
+}
+
+/// <summary>
+/// Linestyle
+/// </summary>
+public enum eLineStyleVml {
+  Solid,
+  Round,
+  Square,
+  Dash,
+  DashDot,
+  LongDash,
+  LongDashDot,
+  LongDashDotDot,
+}
+
+/// <summary>
+/// Drawing object used for comments
+/// </summary>
+public class ExcelVmlDrawingBase : XmlHelper {
+  protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
+    "fill",
+    "stroke",
+    "shadow",
+    "path",
+    "textbox",
+    "ClientData",
+    "MoveWithCells",
+    "SizeWithCells",
+    "Anchor",
+    "Locked",
+    "AutoFill",
+    "LockText",
+    "TextHAlign",
+    "TextVAlign",
+    "Row",
+    "Column",
+    "Visible",
+  ];
+
+  internal ExcelVmlDrawingBase(XmlNode topNode, XmlNamespaceManager ns)
+      : base(ns, topNode) {}
+
+  public string Id {
+    get => GetXmlNodeString("@id");
+    set => SetXmlNodeString("@id", value);
+  }
+
+  /// <summary>
+  /// Alternative text to be displayed instead of a graphic.
+  /// </summary>
+  public string AlternativeText {
+    get => GetXmlNodeString("@alt");
+    set => SetXmlNodeString("@alt", value);
+  }
+
+  protected bool GetStyle(string style, string key, out string value) {
+    string[] styles = style.Split(';');
+    foreach (string s in styles) {
+      if (s.IndexOf(':') > 0) {
+        string[] split = s.Split(':');
+        if (split[0] == key) {
+          value = split[1];
+          return true;
+        }
+      } else if (s == key) {
+        value = "";
+        return true;
+      }
+    }
+    value = "";
+    return false;
+  }
+
+  protected string SetStyle(string style, string key, string value) {
+    string[] styles = style.Split(';');
+    string newStyle = "";
+    bool changed = false;
+    foreach (string s in styles) {
+      string[] split = s.Split(':');
+      if (split[0].Trim() == key) {
+        if (value.Trim()
+            != "") //If blank remove the item
+        {
+          newStyle += key + ':' + value;
+        }
+        changed = true;
+      } else {
+        newStyle += s;
+      }
+      newStyle += ';';
+    }
+    if (!changed) {
+      newStyle += key + ':' + value;
+    } else {
+      newStyle = style.Substring(0, style.Length - 1);
+    }
+    return newStyle;
+  }
+}
diff --git a/AppsheetEpplus/Drawing/Vml/ExcelVmlDrawingBaseCollection.cs b/AppsheetEpplus/Drawing/Vml/ExcelVmlDrawingBaseCollection.cs
new file mode 100644
index 0000000..03d0e22
--- /dev/null
+++ b/AppsheetEpplus/Drawing/Vml/ExcelVmlDrawingBaseCollection.cs
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		Initial Release		        2010-06-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+public class ExcelVmlDrawingBaseCollection {
+  internal ExcelVmlDrawingBaseCollection(ExcelPackage pck, ExcelWorksheet ws, Uri uri) {
+    VmlDrawingXml.PreserveWhitespace = false;
+
+    NameTable nt = new NameTable();
+    NameSpaceManager = new(nt);
+    NameSpaceManager.AddNamespace("v", ExcelPackage._schemaMicrosoftVml);
+    NameSpaceManager.AddNamespace("o", ExcelPackage._schemaMicrosoftOffice);
+    NameSpaceManager.AddNamespace("x", ExcelPackage._schemaMicrosoftExcel);
+    Uri = uri;
+    if (uri == null) {
+      Part = null;
+    } else {
+      Part = pck.Package.GetPart(uri);
+      XmlHelper.LoadXmlSafe(VmlDrawingXml, Part.GetStream());
+    }
+  }
+
+  internal XmlDocument VmlDrawingXml { get; set; } = new();
+
+  internal Uri Uri { get; set; }
+  internal string RelId { get; set; }
+  internal ZipPackagePart Part { get; set; }
+  internal XmlNamespaceManager NameSpaceManager { get; set; }
+}
diff --git a/AppsheetEpplus/Drawing/Vml/ExcelVmlDrawingComment.cs b/AppsheetEpplus/Drawing/Vml/ExcelVmlDrawingComment.cs
new file mode 100644
index 0000000..51c1b2c
--- /dev/null
+++ b/AppsheetEpplus/Drawing/Vml/ExcelVmlDrawingComment.cs
@@ -0,0 +1,232 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		Initial Release		        2010-06-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System.Collections.Immutable;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Drawing object used for comments
+/// </summary>
+public class ExcelVmlDrawingComment : ExcelVmlDrawingBase, IRangeId {
+  protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
+    "fill",
+    "stroke",
+    "shadow",
+    "path",
+    "textbox",
+    "ClientData",
+    "MoveWithCells",
+    "SizeWithCells",
+    "Anchor",
+    "Locked",
+    "AutoFill",
+    "LockText",
+    "TextHAlign",
+    "TextVAlign",
+    "Row",
+    "Column",
+    "Visible",
+  ];
+
+  internal ExcelVmlDrawingComment(XmlNode topNode, ExcelRangeBase range, XmlNamespaceManager ns)
+      : base(topNode, ns) {
+    Range = range;
+  }
+
+  internal ExcelRangeBase Range { get; set; }
+
+  /// <summary>
+  /// Address in the worksheet
+  /// </summary>
+  public string Address => Range.Address;
+
+  private const string _verticalAlignmentPath = "x:ClientData/x:TextVAlign";
+
+  /// <summary>
+  /// Vertical alignment for text
+  /// </summary>
+  public eTextAlignVerticalVml VerticalAlignment {
+    get {
+      switch (GetXmlNodeString(_verticalAlignmentPath)) {
+        case "Center":
+          return eTextAlignVerticalVml.Center;
+        case "Bottom":
+          return eTextAlignVerticalVml.Bottom;
+        default:
+          return eTextAlignVerticalVml.Top;
+      }
+    }
+    set {
+      switch (value) {
+        case eTextAlignVerticalVml.Center:
+          SetXmlNodeString(_verticalAlignmentPath, "Center");
+          break;
+        case eTextAlignVerticalVml.Bottom:
+          SetXmlNodeString(_verticalAlignmentPath, "Bottom");
+          break;
+        default:
+          DeleteNode(_verticalAlignmentPath);
+          break;
+      }
+    }
+  }
+
+  private const string _horizontalAlignmentPath = "x:ClientData/x:TextHAlign";
+
+  /// <summary>
+  /// Horizontal alignment for text
+  /// </summary>
+  public eTextAlignHorizontalVml HorizontalAlignment {
+    get {
+      switch (GetXmlNodeString(_horizontalAlignmentPath)) {
+        case "Center":
+          return eTextAlignHorizontalVml.Center;
+        case "Right":
+          return eTextAlignHorizontalVml.Right;
+        default:
+          return eTextAlignHorizontalVml.Left;
+      }
+    }
+    set {
+      switch (value) {
+        case eTextAlignHorizontalVml.Center:
+          SetXmlNodeString(_horizontalAlignmentPath, "Center");
+          break;
+        case eTextAlignHorizontalVml.Right:
+          SetXmlNodeString(_horizontalAlignmentPath, "Right");
+          break;
+        default:
+          DeleteNode(_horizontalAlignmentPath);
+          break;
+      }
+    }
+  }
+
+  private const string _visiblePath = "x:ClientData/x:Visible";
+
+  /// <summary>
+  /// If the drawing object is visible.
+  /// </summary>
+  public bool Visible {
+    get => (TopNode.SelectSingleNode(_visiblePath, NameSpaceManager) != null);
+    set {
+      if (value) {
+        CreateNode(_visiblePath);
+        Style = SetStyle(Style, "visibility", "visible");
+      } else {
+        DeleteNode(_visiblePath);
+        Style = SetStyle(Style, "visibility", "hidden");
+      }
+    }
+  }
+
+  private const string _textboxStylePath = "v:textbox/@style";
+
+  /// <summary>
+  /// Autofits the drawingobject
+  /// </summary>
+  public bool AutoFit {
+    get {
+      GetStyle(GetXmlNodeString(_textboxStylePath), "mso-fit-shape-to-text", out var value);
+      return value == "t";
+    }
+    set =>
+      SetXmlNodeString(
+          _textboxStylePath,
+          SetStyle(GetXmlNodeString(_textboxStylePath), "mso-fit-shape-to-text", value ? "t" : ""));
+  }
+
+  private const string _lockedPath = "x:ClientData/x:Locked";
+
+  /// <summary>
+  /// If the object is locked when the sheet is protected
+  /// </summary>
+  public bool Locked {
+    get => GetXmlNodeBool(_lockedPath, false);
+    set => SetXmlNodeBool(_lockedPath, value, false);
+  }
+
+  private const string _lockTextPath = "x:ClientData/x:LockText";
+
+  /// <summary>
+  /// Specifies that the object's text is locked
+  /// </summary>
+  public bool LockText {
+    get => GetXmlNodeBool(_lockTextPath, false);
+    set => SetXmlNodeBool(_lockTextPath, value, false);
+  }
+
+  private ExcelVmlDrawingPosition _from;
+
+  /// <summary>
+  /// From position. For comments only when Visible=true.
+  /// </summary>
+  public ExcelVmlDrawingPosition From {
+    get {
+      if (_from == null) {
+        _from = new(
+            NameSpaceManager,
+            TopNode.SelectSingleNode("x:ClientData", NameSpaceManager),
+            0);
+      }
+      return _from;
+    }
+  }
+
+  private ExcelVmlDrawingPosition _to;
+
+  /// <summary>
+  /// To position. For comments only when Visible=true.
+  /// </summary>
+  public ExcelVmlDrawingPosition To {
+    get {
+      if (_to == null) {
+        _to = new(NameSpaceManager, TopNode.SelectSingleNode("x:ClientData", NameSpaceManager), 4);
+      }
+      return _to;
+    }
+  }
+
+  private const string _stylePath = "@style";
+
+  internal string Style {
+    get => GetXmlNodeString(_stylePath);
+    set => SetXmlNodeString(_stylePath, value);
+  }
+
+  ulong IRangeId.RangeID {
+    get => ExcelCellBase.GetCellId(Range.Worksheet.SheetID, Range.Start.Row, Range.Start.Column);
+    set {}
+  }
+}
diff --git a/AppsheetEpplus/Drawing/Vml/ExcelVmlDrawingCommentCollection.cs b/AppsheetEpplus/Drawing/Vml/ExcelVmlDrawingCommentCollection.cs
new file mode 100644
index 0000000..193505c
--- /dev/null
+++ b/AppsheetEpplus/Drawing/Vml/ExcelVmlDrawingCommentCollection.cs
@@ -0,0 +1,188 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		Initial Release		        2010-06-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+internal class ExcelVmlDrawingCommentCollection : ExcelVmlDrawingBaseCollection, IEnumerable {
+  internal RangeCollection _drawings;
+
+  internal ExcelVmlDrawingCommentCollection(ExcelPackage pck, ExcelWorksheet ws, Uri uri)
+      : base(pck, ws, uri) {
+    if (uri == null) {
+      VmlDrawingXml.LoadXml(CreateVmlDrawings());
+      _drawings = new([]);
+    } else {
+      AddDrawingsFromXml(ws);
+    }
+  }
+
+  protected void AddDrawingsFromXml(ExcelWorksheet ws) {
+    var nodes = VmlDrawingXml.SelectNodes("//v:shape", NameSpaceManager);
+    var list = new List<IRangeId>();
+    foreach (XmlNode node in nodes) {
+      var rowNode = node.SelectSingleNode("x:ClientData/x:Row", NameSpaceManager);
+      var colNode = node.SelectSingleNode("x:ClientData/x:Column", NameSpaceManager);
+      if (rowNode != null && colNode != null) {
+        var row = int.Parse(rowNode.InnerText) + 1;
+        var col = int.Parse(colNode.InnerText) + 1;
+        list.Add(new ExcelVmlDrawingComment(node, ws.Cells[row, col], NameSpaceManager));
+      } else {
+        list.Add(new ExcelVmlDrawingComment(node, ws.Cells[1, 1], NameSpaceManager));
+      }
+    }
+    list.Sort((r1, r2) =>
+        (r1.RangeID < r2.RangeID
+                ? -1
+                : r1.RangeID > r2.RangeID
+                    ? 1
+                    : 0)); //Vml drawings are not sorted. Sort to avoid missmatches.
+    _drawings = new(list);
+  }
+
+  private string CreateVmlDrawings() {
+    string vml = string.Format(
+        "<xml xmlns:v=\"{0}\" xmlns:o=\"{1}\" xmlns:x=\"{2}\">",
+        ExcelPackage._schemaMicrosoftVml,
+        ExcelPackage._schemaMicrosoftOffice,
+        ExcelPackage._schemaMicrosoftExcel);
+
+    vml += "<o:shapelayout v:ext=\"edit\">";
+    vml += "<o:idmap v:ext=\"edit\" data=\"1\"/>";
+    vml += "</o:shapelayout>";
+
+    vml +=
+        "<v:shapetype id=\"_x0000_t202\" coordsize=\"21600,21600\" o:spt=\"202\" path=\"m,l,21600r21600,l21600,xe\">";
+    vml += "<v:stroke joinstyle=\"miter\" />";
+    vml += "<v:path gradientshapeok=\"t\" o:connecttype=\"rect\" />";
+    vml += "</v:shapetype>";
+    vml += "</xml>";
+
+    return vml;
+  }
+
+  internal ExcelVmlDrawingComment Add(ExcelRangeBase cell) {
+    XmlNode node = AddDrawing(cell);
+    var draw = new ExcelVmlDrawingComment(node, cell, NameSpaceManager);
+    _drawings.Add(draw);
+    return draw;
+  }
+
+  private XmlNode AddDrawing(ExcelRangeBase cell) {
+    int row = cell.Start.Row,
+        col = cell.Start.Column;
+    var node = VmlDrawingXml.CreateElement("v", "shape", ExcelPackage._schemaMicrosoftVml);
+
+    var id = ExcelCellBase.GetCellId(cell.Worksheet.SheetID, cell._fromRow, cell._fromCol);
+    var ix = _drawings.IndexOf(id);
+    if (ix < 0 && (~ix < _drawings.Count)) {
+      ix = ~ix;
+      var prevDraw = _drawings[ix] as ExcelVmlDrawingBase;
+      prevDraw.TopNode.ParentNode.InsertBefore(node, prevDraw.TopNode);
+    } else {
+      VmlDrawingXml.DocumentElement.AppendChild(node);
+    }
+
+    node.SetAttribute("id", GetNewId());
+    node.SetAttribute("type", "#_x0000_t202");
+    node.SetAttribute("style", "position:absolute;z-index:1; visibility:hidden");
+    //node.SetAttribute("style", "position:absolute; margin-left:59.25pt;margin-top:1.5pt;width:108pt;height:59.25pt;z-index:1; visibility:hidden");
+    node.SetAttribute("fillcolor", "#ffffe1");
+    node.SetAttribute("insetmode", ExcelPackage._schemaMicrosoftOffice, "auto");
+
+    string vml = "<v:fill color2=\"#ffffe1\" />";
+    vml += "<v:shadow on=\"t\" color=\"black\" obscured=\"t\" />";
+    vml += "<v:path o:connecttype=\"none\" />";
+    vml += "<v:textbox style=\"mso-direction-alt:auto\">";
+    vml += "<div style=\"text-align:left\" />";
+    vml += "</v:textbox>";
+    vml += "<x:ClientData ObjectType=\"Note\">";
+    vml += "<x:MoveWithCells />";
+    vml += "<x:SizeWithCells />";
+    vml += string.Format(
+        "<x:Anchor>{0}, 15, {1}, 2, {2}, 31, {3}, 1</x:Anchor>",
+        col,
+        row - 1,
+        col + 2,
+        row + 3);
+    vml += "<x:AutoFill>False</x:AutoFill>";
+    vml += string.Format("<x:Row>{0}</x:Row>", row - 1);
+    ;
+    vml += string.Format("<x:Column>{0}</x:Column>", col - 1);
+    vml += "</x:ClientData>";
+
+    node.InnerXml = vml;
+    return node;
+  }
+
+  private int _nextID;
+
+  /// <summary>
+  /// returns the next drawing id.
+  /// </summary>
+  /// <returns></returns>
+  internal string GetNewId() {
+    if (_nextID == 0) {
+      foreach (ExcelVmlDrawingComment draw in this) {
+        if (draw.Id.Length > 3 && draw.Id.StartsWith("vml")) {
+          if (int.TryParse(draw.Id.Substring(3, draw.Id.Length - 3), out var id)) {
+            if (id > _nextID) {
+              _nextID = id;
+            }
+          }
+        }
+      }
+    }
+    _nextID++;
+    return "vml" + _nextID;
+  }
+
+  internal ExcelVmlDrawingBase this[ulong rangeId] => _drawings[rangeId] as ExcelVmlDrawingComment;
+
+  internal bool ContainsKey(ulong rangeId) {
+    return _drawings.ContainsKey(rangeId);
+  }
+
+  internal int Count => _drawings.Count;
+
+  public IEnumerator GetEnumerator() {
+    return _drawings;
+  }
+
+  IEnumerator IEnumerable.GetEnumerator() {
+    return _drawings;
+  }
+}
diff --git a/AppsheetEpplus/Drawing/Vml/ExcelVmlDrawingPosition.cs b/AppsheetEpplus/Drawing/Vml/ExcelVmlDrawingPosition.cs
new file mode 100644
index 0000000..4d17416
--- /dev/null
+++ b/AppsheetEpplus/Drawing/Vml/ExcelVmlDrawingPosition.cs
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		Initial Release		        2010-06-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// The position of a VML drawing. Used for comments
+/// </summary>
+public class ExcelVmlDrawingPosition : XmlHelper {
+  private readonly int _startPos;
+
+  internal ExcelVmlDrawingPosition(XmlNamespaceManager ns, XmlNode topNode, int startPos)
+      : base(ns, topNode) {
+    _startPos = startPos;
+  }
+
+  /// <summary>
+  /// Row. Zero based
+  /// </summary>
+  public int Row {
+    get => GetNumber(2);
+    set => SetNumber(2, value);
+  }
+
+  /// <summary>
+  /// Row offset in pixels. Zero based
+  /// </summary>
+  public int RowOffset {
+    get => GetNumber(3);
+    set => SetNumber(3, value);
+  }
+
+  /// <summary>
+  /// Column. Zero based
+  /// </summary>
+  public int Column {
+    get => GetNumber(0);
+    set => SetNumber(0, value);
+  }
+
+  /// <summary>
+  /// Column offset. Zero based
+  /// </summary>
+  public int ColumnOffset {
+    get => GetNumber(1);
+    set => SetNumber(1, value);
+  }
+
+  private void SetNumber(int pos, int value) {
+    string anchor = GetXmlNodeString("x:Anchor");
+    string[] numbers = anchor.Split(',');
+    if (numbers.Length == 8) {
+      numbers[_startPos + pos] = value.ToString();
+    } else {
+      throw (new("Anchor element is invalid in vmlDrawing"));
+    }
+    SetXmlNodeString("x:Anchor", string.Join(",", numbers));
+  }
+
+  private int GetNumber(int pos) {
+    string anchor = GetXmlNodeString("x:Anchor");
+    string[] numbers = anchor.Split(',');
+    if (numbers.Length == 8) {
+      if (int.TryParse(numbers[_startPos + pos], out var ret)) {
+        return ret;
+      }
+    }
+    throw (new("Anchor element is invalid in vmlDrawing"));
+  }
+}
diff --git a/AppsheetEpplus/ExcelAddress.cs b/AppsheetEpplus/ExcelAddress.cs
new file mode 100644
index 0000000..494fd34
--- /dev/null
+++ b/AppsheetEpplus/ExcelAddress.cs
@@ -0,0 +1,1215 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Jan Källman		Added		18-MAR-2010
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+
+namespace AppsheetEpplus;
+
+public class ExcelTableAddress {
+  public string Name { get; set; }
+
+  public string ColumnSpan { get; set; }
+
+  public bool IsAll { get; set; }
+
+  public bool IsHeader { get; set; }
+
+  public bool IsData { get; set; }
+
+  public bool IsTotals { get; set; }
+
+  public bool IsThisRow { get; set; }
+}
+
+/// <summary>
+/// A range address
+/// </summary>
+/// <remarks>Examples of addresses are "A1" "B1:C2" "A:A" "1:1" "A1:E2,G3:G5" </remarks>
+public class ExcelAddressBase : ExcelCellBase {
+  protected internal int _fromRow = -1,
+      _toRow,
+      _fromCol,
+      _toCol;
+  protected internal bool _fromRowFixed,
+      _fromColFixed,
+      _toRowFixed,
+      _toColFixed;
+  protected internal string _wb;
+  protected internal string _ws;
+  protected internal string _address;
+
+  protected internal event EventHandler AddressChange;
+
+  internal enum eAddressCollition {
+    No,
+    Partly,
+    Inside,
+    Equal,
+  }
+
+  internal enum eShiftType {
+    Right,
+    Down,
+    EntireRow,
+    EntireColumn,
+  }
+
+  internal ExcelAddressBase() {}
+
+  /// <summary>
+  /// Creates an Address object
+  /// </summary>
+  /// <param name="fromRow">start row</param>
+  /// <param name="fromCol">start column</param>
+  /// <param name="toRow">End row</param>
+  /// <param name="toColumn">End column</param>
+  public ExcelAddressBase(int fromRow, int fromCol, int toRow, int toColumn) {
+    _fromRow = fromRow;
+    _toRow = toRow;
+    _fromCol = fromCol;
+    _toCol = toColumn;
+    Validate();
+
+    _address = GetAddress(_fromRow, _fromCol, _toRow, _toCol);
+  }
+
+  /// <summary>
+  /// Creates an Address object
+  /// </summary>
+  /// <param name="fromRow">start row</param>
+  /// <param name="fromCol">start column</param>
+  /// <param name="toRow">End row</param>
+  /// <param name="toColumn">End column</param>
+  /// <param name="fromRowFixed">start row fixed</param>
+  /// <param name="fromColFixed">start column fixed</param>
+  /// <param name="toRowFixed">End row fixed</param>
+  /// <param name="toColFixed">End column fixed</param>
+  public ExcelAddressBase(
+      int fromRow,
+      int fromCol,
+      int toRow,
+      int toColumn,
+      bool fromRowFixed,
+      bool fromColFixed,
+      bool toRowFixed,
+      bool toColFixed) {
+    _fromRow = fromRow;
+    _toRow = toRow;
+    _fromCol = fromCol;
+    _toCol = toColumn;
+    _fromRowFixed = fromRowFixed;
+    _fromColFixed = fromColFixed;
+    _toRowFixed = toRowFixed;
+    _toColFixed = toColFixed;
+    Validate();
+
+    _address = GetAddress(
+        _fromRow,
+        _fromCol,
+        _toRow,
+        _toCol,
+        _fromRowFixed,
+        fromColFixed,
+        _toRowFixed,
+        _toColFixed);
+  }
+
+  /// <summary>
+  /// Creates an Address object
+  /// </summary>
+  /// <remarks>Examples of addresses are "A1" "B1:C2" "A:A" "1:1" "A1:E2,G3:G5" </remarks>
+  /// <param name="address">The Excel Address</param>
+  public ExcelAddressBase(string address) {
+    SetAddress(address);
+  }
+
+  /// <summary>
+  /// Creates an Address object
+  /// </summary>
+  /// <remarks>Examples of addresses are "A1" "B1:C2" "A:A" "1:1" "A1:E2,G3:G5" </remarks>
+  /// <param name="address">The Excel Address</param>
+  /// <param name="pck">Reference to the package to find information about tables and names</param>
+  /// <param name="referenceAddress">The address</param>
+  protected ExcelAddressBase(
+      string address,
+      ExcelWorkbook workbook,
+      ExcelAddressBase referenceAddress) {
+    SetAddress(address);
+    SetRcFromTable(workbook, referenceAddress);
+  }
+
+  internal void SetRcFromTable(ExcelWorkbook workbook, ExcelAddressBase referenceAddress) {
+    if (string.IsNullOrEmpty(_wb) && Table != null) {
+      foreach (var ws in workbook.Worksheets) {
+        foreach (var t in ws.Tables) {
+          if (t.Name.Equals(Table.Name, StringComparison.InvariantCultureIgnoreCase)) {
+            _ws = ws.Name;
+            if (Table.IsAll) {
+              _fromRow = t.Address._fromRow;
+              _toRow = t.Address._toRow;
+            } else {
+              if (Table.IsThisRow) {
+                if (referenceAddress == null) {
+                  _fromRow = -1;
+                  _toRow = -1;
+                } else {
+                  _fromRow = referenceAddress._fromRow;
+                  _toRow = _fromRow;
+                }
+              } else if (Table.IsHeader && Table.IsData) {
+                _fromRow = t.Address._fromRow;
+                _toRow = t.ShowTotal ? t.Address._toRow - 1 : t.Address._toRow;
+              } else if (Table.IsData && Table.IsTotals) {
+                _fromRow = t.ShowHeader ? t.Address._fromRow + 1 : t.Address._fromRow;
+                _toRow = t.Address._toRow;
+              } else if (Table.IsHeader) {
+                _fromRow = t.ShowHeader ? t.Address._fromRow : -1;
+                _toRow = t.ShowHeader ? t.Address._fromRow : -1;
+              } else if (Table.IsTotals) {
+                _fromRow = t.ShowTotal ? t.Address._toRow : -1;
+                _toRow = t.ShowTotal ? t.Address._toRow : -1;
+              } else {
+                _fromRow = t.ShowHeader ? t.Address._fromRow + 1 : t.Address._fromRow;
+                _toRow = t.ShowTotal ? t.Address._toRow - 1 : t.Address._toRow;
+              }
+            }
+
+            if (string.IsNullOrEmpty(Table.ColumnSpan)) {
+              _fromCol = t.Address._fromCol;
+              _toCol = t.Address._toCol;
+              return;
+            }
+            var col = t.Address._fromCol;
+            var cols = Table.ColumnSpan.Split(':');
+            foreach (var c in t.Columns) {
+              if (_fromCol <= 0
+                  && cols[0]
+                      .Equals(
+                          c.Name,
+                          StringComparison.InvariantCultureIgnoreCase)) //Issue15063 Add invariant igore case
+              {
+                _fromCol = col;
+                if (cols.Length == 1) {
+                  _toCol = _fromCol;
+                  return;
+                }
+              } else if (cols.Length > 1
+                  && _fromCol > 0
+                  && cols[1]
+                      .Equals(
+                          c.Name,
+                          StringComparison.InvariantCultureIgnoreCase)) //Issue15063 Add invariant igore case
+              {
+                _toCol = col;
+                return;
+              }
+
+              col++;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  /// <summary>
+  /// Address is an defined name
+  /// </summary>
+  /// <param name="address">the name</param>
+  /// <param name="isName">Should always be true</param>
+  internal ExcelAddressBase(string address, bool isName) {
+    if (isName) {
+      _address = address;
+      _fromRow = -1;
+      _fromCol = -1;
+      _toRow = -1;
+      _toCol = -1;
+      _start = null;
+      _end = null;
+    } else {
+      SetAddress(address);
+    }
+  }
+
+  protected internal void SetAddress(string address) {
+    address = address.Trim();
+    if (address.StartsWith("'")) {
+      SetWbWs(address);
+    } else if (address.StartsWith(
+        "[")) //Remove any external reference
+    {
+      SetWbWs(address);
+    } else {
+      _address = address;
+    }
+    if (_address.IndexOfAny([',', '!', '[']) > -1) {
+      //Advanced address. Including Sheet or multi or table.
+      ExtractAddress(_address);
+    } else {
+      //Simple address
+      GetRowColFromAddress(
+          _address,
+          out _fromRow,
+          out _fromCol,
+          out _toRow,
+          out _toCol,
+          out _fromRowFixed,
+          out _fromColFixed,
+          out _toRowFixed,
+          out _toColFixed);
+      _addresses = null;
+      _start = null;
+      _end = null;
+    }
+    _address = address;
+    Validate();
+  }
+
+  internal void ChangeAddress() {
+    if (AddressChange != null) {
+      AddressChange(this, new());
+    }
+  }
+
+  private void SetWbWs(string address) {
+    int pos = 0;
+
+    // Get Workbook, if any
+    if (address[pos] == '[') {
+      pos = address.IndexOf("]");
+      _wb = address.Substring(1, pos - 1);
+      pos++;
+    } else {
+      _wb = "";
+    }
+
+    // Get Worksheet
+    if (address[pos] == '\'') {
+      int startPos = pos;
+      pos = address.IndexOf("'", pos + 1);
+      while (pos < address.Length && address[pos + 1] == '\'') {
+        pos = address.IndexOf("'", pos + 2);
+      }
+      _ws = address.Substring(startPos + 1, pos - startPos - 1).Replace("''", "'");
+      pos++;
+    } else {
+      int startPos = pos;
+      pos = address.IndexOf("!", pos);
+      if (pos > -1) {
+        _ws = address.Substring(startPos, pos - startPos);
+      }
+    }
+
+    // Get Address
+    pos = address.IndexOf("!", pos);
+    if (pos > -1) {
+      _address = address.Substring(pos + 1);
+    } else {
+      _address = "";
+    }
+  }
+
+  internal void ChangeWorksheet(string wsName, string newWs) {
+    if (_ws == wsName) {
+      _ws = newWs;
+    }
+    var fullAddress = GetAddress();
+
+    if (Addresses != null) {
+      foreach (var a in Addresses) {
+        if (a._ws == wsName) {
+          a._ws = newWs;
+          fullAddress += "," + a.GetAddress();
+        } else {
+          fullAddress += "," + a._address;
+        }
+      }
+    }
+    _address = fullAddress;
+  }
+
+  private string GetAddress() {
+    var adr = "";
+    if (string.IsNullOrEmpty(_wb)) {
+      adr = "[" + _wb + "]";
+    }
+
+    if (string.IsNullOrEmpty(_ws)) {
+      adr += string.Format("'{0}'!", _ws);
+    }
+    adr += GetAddress(_fromRow, _fromCol, _toRow, _toCol);
+    return adr;
+  }
+
+  private ExcelCellAddress _start;
+
+  /// <summary>
+  /// Gets the row and column of the top left cell.
+  /// </summary>
+  /// <value>The start row column.</value>
+  public ExcelCellAddress Start {
+    get {
+      if (_start == null) {
+        _start = new(_fromRow, _fromCol);
+      }
+      return _start;
+    }
+  }
+
+  private ExcelCellAddress _end;
+
+  /// <summary>
+  /// Gets the row and column of the bottom right cell.
+  /// </summary>
+  /// <value>The end row column.</value>
+  public ExcelCellAddress End {
+    get {
+      if (_end == null) {
+        _end = new(_toRow, _toCol);
+      }
+      return _end;
+    }
+  }
+
+  private ExcelTableAddress _table;
+
+  public ExcelTableAddress Table => _table;
+
+  /// <summary>
+  /// The address for the range
+  /// </summary>
+  public virtual string Address => _address;
+
+  /// <summary>
+  /// If the address is a defined name
+  /// </summary>
+  public bool IsName => _fromRow < 0;
+
+  /// <summary>
+  /// Returns the address text
+  /// </summary>
+  /// <returns></returns>
+  public override string ToString() {
+    return _address;
+  }
+
+  private string _firstAddress;
+
+  /// <summary>
+  /// returns the first address if the address is a multi address.
+  /// A1:A2,B1:B2 returns A1:A2
+  /// </summary>
+  internal string FirstAddress {
+    get {
+      if (string.IsNullOrEmpty(_firstAddress)) {
+        return _address;
+      }
+      return _firstAddress;
+    }
+  }
+
+  internal string AddressSpaceSeparated => _address.Replace(',', ' '); //Conditional formatting and a few other places use space as separator for mulit addresses.
+
+  /// <summary>
+  /// Validate the address
+  /// </summary>
+  protected void Validate() {
+    if (_fromRow > _toRow || _fromCol > _toCol) {
+      throw new ArgumentOutOfRangeException(
+          "Start cell Address must be less or equal to End cell address");
+    }
+  }
+
+  internal string WorkSheet => _ws;
+
+  protected internal List<ExcelAddress> _addresses;
+
+  internal virtual List<ExcelAddress> Addresses => _addresses;
+
+  private bool ExtractAddress(string fullAddress) {
+    var brackPos = new Stack<int>();
+    var bracketParts = new List<string>();
+    string first = "",
+        second = "";
+    bool isText = false,
+        hasSheet = false;
+    try {
+      if (fullAddress == "#REF!") {
+        SetAddress(ref fullAddress, ref second, ref hasSheet);
+        return true;
+      }
+      if (fullAddress.StartsWith("!")) {
+        // invalid address!
+        return false;
+      }
+      for (int i = 0; i < fullAddress.Length; i++) {
+        var c = fullAddress[i];
+        if (c == '\'') {
+          if (isText && i + 1 < fullAddress.Length && fullAddress[i] == '\'') {
+            if (hasSheet) {
+              second += c;
+            } else {
+              first += c;
+            }
+          }
+          isText = !isText;
+        } else {
+          if (brackPos.Count > 0) {
+            if (c == '[' && !isText) {
+              brackPos.Push(i);
+            } else if (c == ']' && !isText) {
+              if (brackPos.Count > 0) {
+                var from = brackPos.Pop();
+                bracketParts.Add(fullAddress.Substring(from + 1, i - from - 1));
+
+                if (brackPos.Count == 0) {
+                  HandleBrackets(first, second, bracketParts);
+                }
+              } else {
+                //Invalid address!
+                return false;
+              }
+            }
+          } else if (c == '[' && !isText) {
+            brackPos.Push(i);
+          } else if (c == '!' && !isText && !first.EndsWith("#REF") && !second.EndsWith("#REF")) {
+            hasSheet = true;
+          } else if (c == ',' && !isText) {
+            SetAddress(ref first, ref second, ref hasSheet);
+          } else {
+            if (hasSheet) {
+              second += c;
+            } else {
+              first += c;
+            }
+          }
+        }
+      }
+      if (Table == null) {
+        SetAddress(ref first, ref second, ref hasSheet);
+      }
+      return true;
+    } catch {
+      return false;
+    }
+  }
+
+  private void HandleBrackets(string first, string second, List<string> bracketParts) {
+    if (!string.IsNullOrEmpty(first)) {
+      _table = new();
+      Table.Name = first;
+      foreach (var s in bracketParts) {
+        if (s.IndexOf("[") < 0) {
+          switch (s.ToLower(CultureInfo.InvariantCulture)) {
+            case "#all":
+              _table.IsAll = true;
+              break;
+            case "#headers":
+              _table.IsHeader = true;
+              break;
+            case "#data":
+              _table.IsData = true;
+              break;
+            case "#totals":
+              _table.IsTotals = true;
+              break;
+            case "#this row":
+              _table.IsThisRow = true;
+              break;
+            default:
+              if (string.IsNullOrEmpty(_table.ColumnSpan)) {
+                _table.ColumnSpan = s;
+              } else {
+                _table.ColumnSpan += ":" + s;
+              }
+              break;
+          }
+        }
+      }
+    }
+  }
+
+  internal eAddressCollition Collide(ExcelAddressBase address) {
+    if (address.WorkSheet != WorkSheet && address.WorkSheet != null) {
+      return eAddressCollition.No;
+    }
+
+    if (address._fromRow > _toRow
+        || address._fromCol > _toCol
+        || _fromRow > address._toRow
+        || _fromCol > address._toCol) {
+      return eAddressCollition.No;
+    }
+    if (address._fromRow == _fromRow
+        && address._fromCol == _fromCol
+        && address._toRow == _toRow
+        && address._toCol == _toCol) {
+      return eAddressCollition.Equal;
+    }
+    if (address._fromRow >= _fromRow
+        && address._toRow <= _toRow
+        && address._fromCol >= _fromCol
+        && address._toCol <= _toCol) {
+      return eAddressCollition.Inside;
+    }
+    return eAddressCollition.Partly;
+  }
+
+  internal ExcelAddressBase AddRow(int row, int rows, bool setFixed = false) {
+    if (row > _toRow) {
+      return this;
+    }
+    if (row <= _fromRow) {
+      return new(
+          (setFixed && _fromRowFixed ? _fromRow : _fromRow + rows),
+          _fromCol,
+          (setFixed && _toRowFixed ? _toRow : _toRow + rows),
+          _toCol,
+          _fromRowFixed,
+          _fromColFixed,
+          _toRowFixed,
+          _toColFixed);
+    }
+    return new(
+        _fromRow,
+        _fromCol,
+        (setFixed && _toRowFixed ? _toRow : _toRow + rows),
+        _toCol,
+        _fromRowFixed,
+        _fromColFixed,
+        _toRowFixed,
+        _toColFixed);
+  }
+
+  internal ExcelAddressBase DeleteRow(int row, int rows, bool setFixed = false) {
+    if (row
+        > _toRow) //After
+    {
+      return this;
+    }
+    if (row + rows
+        <= _fromRow) //Before
+    {
+      return new(
+          (setFixed && _fromRowFixed ? _fromRow : _fromRow - rows),
+          _fromCol,
+          (setFixed && _toRowFixed ? _toRow : _toRow - rows),
+          _toCol,
+          _fromRowFixed,
+          _fromColFixed,
+          _toRowFixed,
+          _toColFixed);
+    }
+    if (row <= _fromRow
+        && row + rows
+            > _toRow) //Inside
+    {
+      return null;
+    } //Partly
+    if (row <= _fromRow) {
+      return new(
+          row,
+          _fromCol,
+          (setFixed && _toRowFixed ? _toRow : _toRow - rows),
+          _toCol,
+          _fromRowFixed,
+          _fromColFixed,
+          _toRowFixed,
+          _toColFixed);
+    }
+    return new(
+        _fromRow,
+        _fromCol,
+        (setFixed && _toRowFixed
+                ? _toRow
+                : _toRow - rows < row
+                    ? row - 1
+                    : _toRow - rows),
+        _toCol,
+        _fromRowFixed,
+        _fromColFixed,
+        _toRowFixed,
+        _toColFixed);
+  }
+
+  internal ExcelAddressBase AddColumn(int col, int cols, bool setFixed = false) {
+    if (col > _toCol) {
+      return this;
+    }
+    if (col <= _fromCol) {
+      return new(
+          _fromRow,
+          (setFixed && _fromColFixed ? _fromCol : _fromCol + cols),
+          _toRow,
+          (setFixed && _toColFixed ? _toCol : _toCol + cols),
+          _fromRowFixed,
+          _fromColFixed,
+          _toRowFixed,
+          _toColFixed);
+    }
+    return new(
+        _fromRow,
+        _fromCol,
+        _toRow,
+        (setFixed && _toColFixed ? _toCol : _toCol + cols),
+        _fromRowFixed,
+        _fromColFixed,
+        _toRowFixed,
+        _toColFixed);
+  }
+
+  internal ExcelAddressBase DeleteColumn(int col, int cols, bool setFixed = false) {
+    if (col
+        > _toCol) //After
+    {
+      return this;
+    }
+    if (col + cols
+        <= _fromCol) //Before
+    {
+      return new(
+          _fromRow,
+          (setFixed && _fromColFixed ? _fromCol : _fromCol - cols),
+          _toRow,
+          (setFixed && _toColFixed ? _toCol : _toCol - cols),
+          _fromRowFixed,
+          _fromColFixed,
+          _toRowFixed,
+          _toColFixed);
+    }
+    if (col <= _fromCol
+        && col + cols
+            > _toCol) //Inside
+    {
+      return null;
+    } //Partly
+    if (col <= _fromCol) {
+      return new(
+          _fromRow,
+          col,
+          _toRow,
+          (setFixed && _toColFixed ? _toCol : _toCol - cols),
+          _fromRowFixed,
+          _fromColFixed,
+          _toRowFixed,
+          _toColFixed);
+    }
+    return new(
+        _fromRow,
+        _fromCol,
+        _toRow,
+        (setFixed && _toColFixed
+                ? _toCol
+                : _toCol - cols < col
+                    ? col - 1
+                    : _toCol - cols),
+        _fromRowFixed,
+        _fromColFixed,
+        _toRowFixed,
+        _toColFixed);
+  }
+
+  internal ExcelAddressBase Insert(
+      ExcelAddressBase address,
+      eShiftType shift /*, out ExcelAddressBase topAddress, out ExcelAddressBase leftAddress, out ExcelAddressBase rightAddress, out ExcelAddressBase bottomAddress*/) {
+    //Before or after, no change
+    //if ((_toRow > address._fromRow && _toCol > address.column) ||
+    //    (_fromRow > address._toRow && column > address._toCol))
+    if (_toRow < address._fromRow
+        || _toCol < address._fromCol
+        || (_fromRow > address._toRow && _fromCol > address._toCol)) {
+      //topAddress = null;
+      //leftAddress = null;
+      //rightAddress = null;
+      //bottomAddress = null;
+      return this;
+    }
+
+    int rows = address.Rows;
+    int cols = address.Columns;
+    string retAddress = "";
+    if (shift == eShiftType.Right) {
+      if (address._fromRow > _fromRow) {
+        retAddress = GetAddress(
+            _fromRow,
+            _fromCol,
+            address._fromRow,
+            _toCol,
+            _fromRowFixed,
+            _fromColFixed,
+            _toRowFixed,
+            _toColFixed);
+      }
+      if (address._fromCol > _fromCol) {
+        retAddress = GetAddress(
+            _fromRow < address._fromRow ? _fromRow : address._fromRow,
+            _fromCol,
+            address._fromRow,
+            _toCol,
+            _fromRowFixed,
+            _fromColFixed,
+            _toRowFixed,
+            _toColFixed);
+      }
+    }
+    if (_toRow < address._fromRow) {
+      if (_fromRow < address._fromRow) {}
+    }
+    return null;
+  }
+
+  private void SetAddress(ref string first, ref string second, ref bool hasSheet) {
+    string ws,
+        address;
+    if (hasSheet) {
+      ws = first;
+      address = second;
+      first = "";
+      second = "";
+    } else {
+      address = first;
+      ws = "";
+      first = "";
+    }
+    hasSheet = false;
+    if (string.IsNullOrEmpty(_firstAddress)) {
+      if (string.IsNullOrEmpty(_ws) || !string.IsNullOrEmpty(ws)) {
+        _ws = ws;
+      }
+      _firstAddress = address;
+      GetRowColFromAddress(
+          address,
+          out _fromRow,
+          out _fromCol,
+          out _toRow,
+          out _toCol,
+          out _fromRowFixed,
+          out _fromColFixed,
+          out _toRowFixed,
+          out _toColFixed);
+    } else {
+      if (_addresses == null) {
+        _addresses = [];
+      }
+      _addresses.Add(new(_ws, address));
+    }
+  }
+
+  internal enum AddressType {
+    Invalid,
+    InternalAddress,
+    ExternalAddress,
+    InternalName,
+    ExternalName,
+    Formula,
+  }
+
+  internal static AddressType IsValid(string address) {
+    if (address == "#REF!") {
+      return AddressType.Invalid;
+    }
+    if (double.TryParse(
+        address,
+        NumberStyles.Any,
+        CultureInfo.InvariantCulture,
+        out _)) //A double, no valid address
+    {
+      return AddressType.Invalid;
+    }
+    if (IsFormula(address)) {
+      return AddressType.Formula;
+    }
+    if (SplitAddress(address, out var wb, out _, out var intAddress)) {
+      if (intAddress.Contains(
+          "[")) //Table reference
+      {
+        return string.IsNullOrEmpty(wb) ? AddressType.InternalAddress : AddressType.ExternalAddress;
+      }
+      if (intAddress.Contains(",")) {
+        intAddress = intAddress.Substring(0, intAddress.IndexOf(','));
+      }
+      if (IsAddress(intAddress)) {
+        return string.IsNullOrEmpty(wb) ? AddressType.InternalAddress : AddressType.ExternalAddress;
+      }
+      return string.IsNullOrEmpty(wb) ? AddressType.InternalName : AddressType.ExternalName;
+    }
+    return AddressType.Invalid;
+  }
+
+  private static bool IsAddress(string intAddress) {
+    if (string.IsNullOrEmpty(intAddress)) {
+      return false;
+    }
+    var cells = intAddress.Split(':');
+    int toRow,
+        toCol;
+
+    if (!GetRowCol(cells[0], out var fromRow, out var fromCol, false)) {
+      return false;
+    }
+    if (cells.Length > 1) {
+      if (!GetRowCol(cells[1], out toRow, out toCol, false)) {
+        return false;
+      }
+    } else {
+      toRow = fromRow;
+      toCol = fromCol;
+    }
+    if (fromRow <= toRow
+        && fromCol <= toCol
+        && fromCol > -1
+        && toCol <= ExcelPackage.MaxColumns
+        && fromRow > -1
+        && toRow <= ExcelPackage.MaxRows) {
+      return true;
+    }
+    return false;
+  }
+
+  private static bool SplitAddress(
+      string address,
+      out string wb,
+      out string ws,
+      out string intAddress) {
+    wb = "";
+    ws = "";
+    intAddress = "";
+    var text = "";
+    bool isText = false;
+    var brackPos = -1;
+    for (int i = 0; i < address.Length; i++) {
+      if (address[i] == '\'') {
+        isText = !isText;
+        if (i > 0 && address[i - 1] == '\'') {
+          text += "'";
+        }
+      } else {
+        if (address[i] == '!' && !isText) {
+          if (text.Length > 0 && text[0] == '[') {
+            wb = text.Substring(1, text.IndexOf("]") - 1);
+            ws = text.Substring(text.IndexOf("]") + 1);
+          } else {
+            ws = text;
+          }
+          intAddress = address.Substring(i + 1);
+          return true;
+        }
+        if (address[i] == '[' && !isText) {
+          if (i
+              > 0) //Table reference return full address;
+          {
+            intAddress = address;
+            return true;
+          }
+          brackPos = i;
+        } else if (address[i] == ']' && !isText) {
+          if (brackPos > -1) {
+            wb = text;
+            text = "";
+          } else {
+            return false;
+          }
+        } else {
+          text += address[i];
+        }
+      }
+    }
+    intAddress = text;
+    return true;
+  }
+
+  private static bool IsFormula(string address) {
+    var isText = false;
+    for (int i = 0; i < address.Length; i++) {
+      if (address[i] == '\'') {
+        isText = !isText;
+      } else {
+        if (isText == false
+            && address
+                .Substring(i, 1)
+                .IndexOfAny(['(', ')', '+', '-', '*', '/', '.', '=', '^', '&', '%', '\"']) > -1) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  public int Rows => _toRow - _fromRow + 1;
+
+  public int Columns => _toCol - _fromCol + 1;
+
+  internal static String GetWorkbookPart(string address) {
+    int ix;
+    if (address[0] == '[') {
+      ix = address.IndexOf(']') + 1;
+      if (ix > 0) {
+        return address.Substring(1, ix - 2);
+      }
+    }
+    return "";
+  }
+
+  internal static string GetWorksheetPart(string address, string defaultWorkSheet, ref int endIx) {
+    if (address == "") {
+      return defaultWorkSheet;
+    }
+    var ix = 0;
+    if (address[0] == '[') {
+      ix = address.IndexOf(']') + 1;
+    }
+    if (ix > 0 && ix < address.Length) {
+      if (address[ix] == '\'') {
+        return GetString(address, ix, out endIx);
+      }
+      var ixEnd = address.IndexOf('!', ix);
+      if (ixEnd > ix) {
+        return address.Substring(ix, ixEnd - ix);
+      }
+      return defaultWorkSheet;
+    }
+    return defaultWorkSheet;
+  }
+
+  internal static void SplitAddress(
+      string fullAddress,
+      out string wb,
+      out string ws,
+      out string address,
+      string defaultWorksheet = "") {
+    wb = GetWorkbookPart(fullAddress);
+    int ix = 0;
+    ws = GetWorksheetPart(fullAddress, defaultWorksheet, ref ix);
+    if (ix < fullAddress.Length) {
+      if (fullAddress[ix] == '!') {
+        address = fullAddress.Substring(ix + 1);
+      } else {
+        address = fullAddress.Substring(ix);
+      }
+    } else {
+      address = "";
+    }
+  }
+
+  private static string GetString(string address, int ix, out int endIx) {
+    var strIx = address.IndexOf("''");
+    while (strIx > -1) {
+      strIx = address.IndexOf("''");
+    }
+    endIx = address.IndexOf("'");
+    return address.Substring(ix, endIx - ix).Replace("''", "'");
+  }
+
+  internal bool IsValidRowCol() {
+    return !(_fromRow > _toRow
+            || _fromCol > _toCol
+            || _fromRow < 1
+            || _fromCol < 1
+            || _toRow > ExcelPackage.MaxRows
+            || _toCol > ExcelPackage.MaxColumns);
+  }
+}
+
+/// <summary>
+/// Range address with the address property readonly
+/// </summary>
+public class ExcelAddress : ExcelAddressBase {
+  internal ExcelAddress() {}
+
+  public ExcelAddress(int fromRow, int fromCol, int toRow, int toColumn)
+      : base(fromRow, fromCol, toRow, toColumn) {
+    _ws = "";
+  }
+
+  public ExcelAddress(string address)
+      : base(address) {}
+
+  internal ExcelAddress(string ws, string address)
+      : base(address) {
+    if (string.IsNullOrEmpty(_ws)) {
+      _ws = ws;
+    }
+  }
+
+  internal ExcelAddress(string ws, string address, bool isName)
+      : base(address, isName) {
+    if (string.IsNullOrEmpty(_ws)) {
+      _ws = ws;
+    }
+  }
+
+  public ExcelAddress(string address, ExcelWorkbook workbook, ExcelAddressBase referenceAddress)
+      : base(address, workbook, referenceAddress) {}
+
+  /// <summary>
+  /// The address for the range
+  /// </summary>
+  /// <remarks>Examples of addresses are "A1" "B1:C2" "A:A" "1:1" "A1:E2,G3:G5" </remarks>
+  public new string Address {
+    get {
+      if (string.IsNullOrEmpty(_address) && _fromRow > 0) {
+        _address = GetAddress(_fromRow, _fromCol, _toRow, _toCol);
+      }
+      return _address;
+    }
+    set {
+      SetAddress(value);
+      ChangeAddress();
+    }
+  }
+}
+
+public class ExcelFormulaAddress : ExcelAddressBase {
+  private bool _fromRowFixed,
+      _toRowFixed,
+      _fromColFixed,
+      _toColFixed;
+
+  public ExcelFormulaAddress(int fromRow, int fromCol, int toRow, int toColumn)
+      : base(fromRow, fromCol, toRow, toColumn) {
+    _ws = "";
+  }
+
+  public ExcelFormulaAddress(string address)
+      : base(address) {
+    SetFixed();
+  }
+
+  private void SetFixed() {
+    if (Address.IndexOf("[") >= 0) {
+      return;
+    }
+    var address = FirstAddress;
+    if (_fromRow == _toRow && _fromCol == _toCol) {
+      GetFixed(address, out _fromRowFixed, out _fromColFixed);
+    } else {
+      var cells = address.Split(':');
+      GetFixed(cells[0], out _fromRowFixed, out _fromColFixed);
+      GetFixed(cells[1], out _toRowFixed, out _toColFixed);
+    }
+  }
+
+  private void GetFixed(string address, out bool rowFixed, out bool colFixed) {
+    rowFixed = colFixed = false;
+    var ix = address.IndexOf('$');
+    while (ix > -1) {
+      ix++;
+      if (ix < address.Length) {
+        if (address[ix] >= '0' && address[ix] <= '9') {
+          rowFixed = true;
+          break;
+        }
+        colFixed = true;
+      }
+      ix = address.IndexOf('$', ix);
+    }
+  }
+
+  /// <summary>
+  /// The address for the range
+  /// </summary>
+  /// <remarks>Examples of addresses are "A1" "B1:C2" "A:A" "1:1" "A1:E2,G3:G5" </remarks>
+  public new string Address {
+    get {
+      if (string.IsNullOrEmpty(_address) && _fromRow > 0) {
+        _address = GetAddress(
+            _fromRow,
+            _fromCol,
+            _toRow,
+            _toCol,
+            _fromRowFixed,
+            _toRowFixed,
+            _fromColFixed,
+            _toColFixed);
+      }
+      return _address;
+    }
+    set {
+      SetAddress(value);
+      ChangeAddress();
+      SetFixed();
+    }
+  }
+
+  internal new List<ExcelFormulaAddress> _addresses;
+
+  public new List<ExcelFormulaAddress> Addresses {
+    get {
+      if (_addresses == null) {
+        _addresses = [];
+      }
+      return _addresses;
+    }
+  }
+
+  internal string GetOffset(int row, int column) {
+    int fromRow = _fromRow,
+        fromCol = _fromCol,
+        toRow = _toRow,
+        tocol = _toCol;
+    var isMulti = (fromRow != toRow || fromCol != tocol);
+    if (!_fromRowFixed) {
+      fromRow += row;
+    }
+    if (!_fromColFixed) {
+      fromCol += column;
+    }
+    if (isMulti) {
+      if (!_toRowFixed) {
+        toRow += row;
+      }
+      if (!_toColFixed) {
+        tocol += column;
+      }
+    } else {
+      toRow = fromRow;
+      tocol = fromCol;
+    }
+    string a = GetAddress(
+        fromRow,
+        fromCol,
+        toRow,
+        tocol,
+        _fromRowFixed,
+        _fromColFixed,
+        _toRowFixed,
+        _toColFixed);
+    if (Addresses != null) {
+      foreach (var sa in Addresses) {
+        a += "," + sa.GetOffset(row, column);
+      }
+    }
+    return a;
+  }
+}
diff --git a/AppsheetEpplus/ExcelCellAddress.cs b/AppsheetEpplus/ExcelCellAddress.cs
new file mode 100644
index 0000000..7261766
--- /dev/null
+++ b/AppsheetEpplus/ExcelCellAddress.cs
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ *  Starnuto Di Topo & Jan Källman  Initial Release		        2010-03-14
+ * Jan Källman		License changed GPL-->LGPL 2011-12-27
+ *******************************************************************************/
+
+using System;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// A single cell address
+/// </summary>
+public class ExcelCellAddress {
+  public ExcelCellAddress()
+      : this(1, 1) {}
+
+  private int _row;
+  private int _column;
+  private string _address;
+
+  /// <summary>
+  /// Initializes a new instance of the ExcelCellAddress class.
+  /// </summary>
+  /// <param name="row">The row.</param>
+  /// <param name="column">The column.</param>
+  public ExcelCellAddress(int row, int column) {
+    Row = row;
+    Column = column;
+  }
+
+  /// <summary>
+  /// Initializes a new instance of the ExcelCellAddress class.
+  /// </summary>
+  ///<param name="address">The address</param>
+  public ExcelCellAddress(string address) {
+    Address = address;
+  }
+
+  /// <summary>
+  /// Row
+  /// </summary>
+  public int Row {
+    get => _row;
+    private set {
+      if (value <= 0) {
+        throw new ArgumentOutOfRangeException("value", "Row cannot be less than 1.");
+      }
+      _row = value;
+      if (_column > 0) {
+        _address = ExcelCellBase.GetAddress(_row, _column);
+      } else {
+        _address = "#REF!";
+      }
+    }
+  }
+
+  /// <summary>
+  /// Column
+  /// </summary>
+  public int Column {
+    get => _column;
+    private set {
+      if (value <= 0) {
+        throw new ArgumentOutOfRangeException("value", "Column cannot be less than 1.");
+      }
+      _column = value;
+      if (_row > 0) {
+        _address = ExcelCellBase.GetAddress(_row, _column);
+      } else {
+        _address = "#REF!";
+      }
+    }
+  }
+
+  /// <summary>
+  /// Celladdress
+  /// </summary>
+  public string Address {
+    get => _address;
+    internal set {
+      _address = value;
+      ExcelCellBase.GetRowColFromAddress(_address, out _row, out _column);
+    }
+  }
+
+  /// <summary>
+  /// If the address is an invalid reference (#REF!)
+  /// </summary>
+  public bool IsRef => _row <= 0;
+
+  /// <summary>
+  /// Returns the letter corresponding to the supplied 1-based column index.
+  /// </summary>
+  /// <param name="column">Index of the column (1-based)</param>
+  /// <returns>The corresponding letter, like A for 1.</returns>
+  public static string GetColumnLetter(int column) {
+    if (column > ExcelPackage.MaxColumns || column < 1) {
+      throw new InvalidOperationException(
+          "Invalid 1-based column index: "
+              + column
+              + ". Valid range is 1 to "
+              + ExcelPackage.MaxColumns);
+    }
+    return ExcelCellBase.GetColumnLetter(column);
+  }
+}
diff --git a/AppsheetEpplus/ExcelCellBase.cs b/AppsheetEpplus/ExcelCellBase.cs
new file mode 100644
index 0000000..1327a21
--- /dev/null
+++ b/AppsheetEpplus/ExcelCellBase.cs
@@ -0,0 +1,1252 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Jan Källman		Initial Release		        2009-10-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-27
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Base class containing cell address manipulating methods.
+/// </summary>
+public abstract class ExcelCellBase {
+  /// <summary>
+  /// Get the sheet, row and column from the CellID
+  /// </summary>
+  /// <param name="cellId"></param>
+  /// <param name="sheet"></param>
+  /// <param name="row"></param>
+  /// <param name="col"></param>
+  static internal void SplitCellId(ulong cellId, out int sheet, out int row, out int col) {
+    sheet = (int)(cellId % 0x8000);
+    col = ((int)(cellId >> 15) & 0x3FF);
+    row = ((int)(cellId >> 29));
+  }
+
+  /// <summary>
+  /// Get the cellID for the cell.
+  /// </summary>
+  /// <param name="sheetId"></param>
+  /// <param name="row"></param>
+  /// <param name="col"></param>
+  /// <returns></returns>
+  internal static ulong GetCellId(int sheetId, int row, int col) {
+    return ((ulong)sheetId) + (((ulong)col) << 15) + (((ulong)row) << 29);
+  }
+
+  private delegate string AddressTranslator(
+    string part,
+    int row,
+    int col,
+    int rowIncr,
+    int colIncr);
+
+  /// <summary>
+  /// Translates a R1C1 to an absolut address/Formula
+  /// </summary>
+  /// <param name="value">Address</param>
+  /// <param name="row">Current row</param>
+  /// <param name="col">Current column</param>
+  /// <returns>The RC address</returns>
+  public static string TranslateFromR1C1(string value, int row, int col) {
+    return Translate(value, ToAbs, row, col, -1, -1);
+  }
+
+  /// <summary>
+  /// Translates a R1C1 to an absolut address/Formula: Version 1
+  /// </summary>
+  /// <param name="value">Address</param>
+  /// <param name="row">Current row</param>
+  /// <param name="col">Current column</param>
+  /// <returns>The RC address</returns>
+  public static string TranslateFromR1C1_V1(string value, int row, int col) {
+    return Translate_V1(value, ToAbs_V1, row, col, -1, -1);
+  }
+
+  /// <summary>
+  /// Translates a absolut address to R1C1 Format
+  /// </summary>
+  /// <param name="value">R1C1 Address</param>
+  /// <param name="row">Current row</param>
+  /// <param name="col">Current column</param>
+  /// <returns>The absolut address/Formula</returns>
+  public static string TranslateToR1C1(string value, int row, int col) {
+    return Translate(value, ToR1C1, row, col, -1, -1);
+  }
+
+  /// <summary>
+  /// Translates a absolute address to R1C1 Format : Version 1
+  /// </summary>
+  /// <param name="value">R1C1 Address</param>
+  /// <param name="row">Current row</param>
+  /// <param name="col">Current column</param>
+  /// <returns>The absolut address/Formula</returns>
+  public static string TranslateToR1C1_V1(string value, int row, int col) {
+    return Translate_V1(value, ToR1C1_V1, row, col, -1, -1);
+  }
+
+  /// <summary>
+  /// Translates betweein R1C1 or absolute addresses : Version 1
+  /// </summary>
+  /// <param name="value">The addresss/function</param>
+  /// <param name="addressTranslator">The translating function</param>
+  /// <param name="row"></param>
+  /// <param name="col"></param>
+  /// <param name="rowIncr"></param>
+  /// <param name="colIncr"></param>
+  /// <returns></returns>
+  private static string Translate(
+      string value,
+      AddressTranslator addressTranslator,
+      int row,
+      int col,
+      int rowIncr,
+      int colIncr) {
+    if (value == "") {
+      return "";
+    }
+    bool isText = false;
+    string ret = "";
+    string part = "";
+    char prevTq = (char)0;
+    for (int pos = 0; pos < value.Length; pos++) {
+      char c = value[pos];
+      if (c == '"' || c == '\'') {
+        if (isText && prevTq != c) {
+          ret += c;
+          continue;
+        }
+
+        if (isText == false && part != "" && prevTq == c) {
+          ret += addressTranslator(part, row, col, rowIncr, colIncr);
+          part = "";
+        }
+        prevTq = c;
+        isText = !isText;
+        ret += c;
+      } else if (isText) {
+        ret += c;
+      } else {
+        if ((c == '-'
+                    || c == '+'
+                    || c == '*'
+                    || c == '/'
+                    || c == '='
+                    || c == '^'
+                    || c == ','
+                    || c == ':'
+                    || c == '<'
+                    || c == '>'
+                    || c == '('
+                    || c == ')'
+                    || c == '!'
+                    || c == ' '
+                    || c == '&'
+                    || c == '%')
+            && (pos == 0
+                    || value[pos - 1]
+                        != '[')) //Last part to allow for R1C1 style [-x]
+        {
+          ret += addressTranslator(part, row, col, rowIncr, colIncr) + c;
+          part = "";
+        } else {
+          part += c;
+        }
+      }
+    }
+    if (part != "") {
+      ret += addressTranslator(part, row, col, rowIncr, colIncr);
+    }
+    return ret;
+  }
+
+  private static string Translate_V1(
+      string value,
+      AddressTranslator addressTranslator,
+      int row,
+      int col,
+      int rowIncr,
+      int colIncr) {
+    if (value == "") {
+      return "";
+    }
+    bool isText = false;
+    string ret = "";
+    string part = "";
+    char prevTq = (char)0;
+    value = value.Replace("\n", ""); // Eliminate new line characters in the formula
+    for (int pos = 0; pos < value.Length; pos++) {
+      char c = value[pos];
+      if (c == '"' || c == '\'') {
+        if (isText && prevTq != c) {
+          ret += c;
+          continue;
+        }
+
+        if (isText == false && part != "" && prevTq == c) {
+          ret += addressTranslator(part, row, col, rowIncr, colIncr);
+          part = "";
+        }
+        prevTq = c;
+        isText = !isText;
+        ret += c;
+      } else if (isText) {
+        ret += c;
+      } else if (c
+          == ':') // Keep Range expressions together
+      {
+        part += c;
+      } else {
+        if ((c == '-'
+                    || c == '+'
+                    || c == '*'
+                    || c == '/'
+                    || c == '='
+                    || c == '^'
+                    || c == ','
+                    || c == '<'
+                    || c == '>'
+                    || c == '('
+                    || c == ')'
+                    || c == '!'
+                    || c == ' '
+                    || c == '&'
+                    || c == '%')
+            && (pos == 0
+                    || value[pos - 1]
+                        != '[')) //Last part to allow for R1C1 style [-x]
+        {
+          ret += addressTranslator(part, row, col, rowIncr, colIncr) + c;
+          part = "";
+        } else {
+          part += c;
+        }
+      }
+    }
+    if (part != "") {
+      ret += addressTranslator(part, row, col, rowIncr, colIncr);
+    }
+    return ret;
+  }
+
+  /// <summary>
+  /// Translate to R1C1
+  /// </summary>
+  /// <param name="part">the value to be translated</param>
+  /// <param name="row"></param>
+  /// <param name="col"></param>
+  /// <param name="rowIncr"></param>
+  /// <param name="colIncr"></param>
+  /// <returns></returns>
+  private static string ToR1C1(string part, int row, int col, int rowIncr, int colIncr) {
+    string ret = "R";
+    if (GetRowCol(part, out var addrRow, out var addrCol, false)) {
+      if (addrRow == 0 || addrCol == 0) {
+        return part;
+      }
+      if (part.IndexOf('$', 1) > 0) {
+        ret += addrRow.ToString();
+      } else if (addrRow - row != 0) {
+        ret += string.Format("[{0}]", addrRow - row);
+      }
+
+      if (part.StartsWith("$")) {
+        return ret + "C" + addrCol;
+      }
+      if (addrCol - col != 0) {
+        return ret + "C" + string.Format("[{0}]", addrCol - col);
+      }
+      return ret + "C";
+    }
+    return part;
+  }
+
+  private static string ToR1C1_V1(string part, int row, int col, int rowIncr, int colIncr) {
+    // Handle range expressions
+    if ((part.Length > 1) && (part.IndexOf(':', 1) > 0)) {
+      return RangeToR1C1_V1(part, row, col, rowIncr, colIncr);
+    }
+
+    string ret = "R";
+    if (GetRowCol(part, out var addrRow, out var addrCol, false)) {
+      if (addrRow == 0 || addrCol == 0) {
+        return part;
+      }
+      if (part.IndexOf('$', 1) > 0) {
+        ret += addrRow.ToString();
+      } else if (addrRow - row != 0) {
+        ret += string.Format("[{0}]", addrRow - row);
+      }
+
+      if (part.StartsWith("$")) {
+        return ret + "C" + addrCol;
+      }
+      if (addrCol - col != 0) {
+        return ret + "C" + string.Format("[{0}]", addrCol - col);
+      }
+      return ret + "C";
+    }
+    return part;
+  }
+
+  private static string RangeToR1C1_V1(string part, int row, int col, int rowIncr, int colIncr) {
+    // Split range expression
+    string[] cellValues = part.Split([':'], StringSplitOptions.RemoveEmptyEntries);
+
+    // Convert range expressions
+    string result = "";
+    result += RangeCellToR1C1_V1(cellValues[0], row, col, rowIncr, colIncr);
+    result += ":";
+    result +=
+        (cellValues.Length > 1)
+            ? RangeCellToR1C1_V1(cellValues[1], row, col, rowIncr, colIncr)
+            : "";
+
+    // Return converted range expression
+    return result;
+  }
+
+  private static string RangeCellToR1C1_V1(
+      string part,
+      int row,
+      int col,
+      int rowIncr,
+      int colIncr) {
+    string result = "";
+    if (GetRowCol_V1(
+        part,
+        out var addrRow,
+        out var addrCol,
+        false,
+        out var fixedRow,
+        out var fixedCol)) {
+      if (addrRow > 0) {
+        result += "R";
+        if (fixedRow) {
+          // Absolute row
+          result += addrRow.ToString();
+        } else if (addrRow - row != 0) {
+          // Relative row
+          result += string.Format("[{0}]", addrRow - row);
+        }
+      }
+
+      if (addrCol > 0) {
+        result += "C";
+        if (fixedCol) {
+          // Absolute column
+          result += addrCol;
+        } else if (addrCol - col != 0) {
+          // Relative column
+          result += string.Format("[{0}]", addrCol - col);
+        }
+      }
+      return result;
+    }
+    return part;
+  }
+
+  /// <summary>
+  /// Translates to absolute address
+  /// </summary>
+  /// <param name="part"></param>
+  /// <param name="row"></param>
+  /// <param name="col"></param>
+  /// <param name="rowIncr"></param>
+  /// <param name="colIncr"></param>
+  /// <returns></returns>
+  ///
+  private static string ToAbs(string part, int row, int col, int rowIncr, int colIncr) {
+    string check = part.ToUpper(CultureInfo.InvariantCulture);
+
+    int rStart = check.IndexOf("R");
+    if (rStart != 0) {
+      return part;
+    }
+    if (part.Length
+        == 1) //R
+    {
+      return GetAddress(row, col);
+    }
+
+    int cStart = check.IndexOf("C");
+    bool absoluteRow;
+    if (cStart == -1) {
+      int rNum = GetRc(part, row, out absoluteRow);
+      if (rNum > int.MinValue) {
+        return GetAddress(rNum, absoluteRow, col, false);
+      }
+      return part;
+    } else {
+      int rNum = GetRc(part.Substring(1, cStart - 1), row, out absoluteRow);
+      int cNum = GetRc(
+          part.Substring(cStart + 1, part.Length - cStart - 1),
+          col,
+          out var absoluteCol);
+      if (rNum > int.MinValue && cNum > int.MinValue) {
+        return GetAddress(rNum, absoluteRow, cNum, absoluteCol);
+      }
+      return part;
+    }
+  }
+
+  private static string ToAbs_V1(string part, int row, int col, int rowIncr, int colIncr) {
+    bool absoluteCol = false;
+    bool absoluteRow = false;
+    int colNum = -1;
+    int rowNum = -1;
+    int num;
+    int numLength;
+    int pos = 0;
+
+    // Handle range expressions
+    if ((part.Length > 1) && (part.IndexOf(':', 1) > 0)) {
+      return RangeToA1_V1(part, row, col, rowIncr, colIncr);
+    }
+
+    // Ensure part is present
+    if (string.IsNullOrWhiteSpace(part)) {
+      return "";
+    }
+
+    // Convert to upper case
+    string check = part.ToUpper(CultureInfo.InvariantCulture);
+
+    // Parse "R", if any
+    if (pos < part.Length && check[pos] == 'R') {
+      pos += 1;
+
+      if (pos >= part.Length) {
+        // Only "R" present
+        absoluteRow = false;
+        rowNum = row;
+      } else if (pos < part.Length && check[pos] == 'C') {
+        // "R" followed by "C"
+        absoluteRow = false;
+        rowNum = row;
+      } else if (pos < part.Length && check[pos] == '[') {
+        // "R" followed by relative row number
+        pos += 1;
+        num = GetNumber_V1(check.Substring(pos, part.Length - pos), out numLength);
+        if (num == Int32.MinValue) {
+          return part;
+        }
+        pos += numLength;
+
+        if (pos < part.Length && check[pos] == ']') {
+          pos += 1;
+        } else {
+          return part;
+        }
+
+        absoluteRow = false;
+        rowNum = row + num;
+      } else if (pos < part.Length) {
+        // "R" followed by absolute row number
+        num = GetNumber_V1(check.Substring(pos, part.Length - pos), out numLength);
+        if (rowNum == Int32.MinValue) {
+          return part;
+        }
+        pos += numLength;
+
+        absoluteRow = true;
+        rowNum = num;
+      }
+    }
+
+    // Parse "C", if any
+    if (pos < part.Length && check[pos] == 'C') {
+      pos += 1;
+
+      if (pos >= part.Length) {
+        // Only "C" present
+        absoluteCol = false;
+        colNum = col;
+      } else if (pos < part.Length && check[pos] == '[') {
+        // "C" followed by relative column number
+        pos += 1;
+        num = GetNumber_V1(check.Substring(pos, part.Length - pos), out numLength);
+        if (num == Int32.MinValue) {
+          return part;
+        }
+        pos += numLength;
+
+        if (pos < part.Length && check[pos] == ']') {
+          pos += 1;
+        } else {
+          return part;
+        }
+
+        absoluteCol = false;
+        colNum = col + num;
+      } else if (pos < part.Length) {
+        // "C" followed by absolute column number
+        num = GetNumber_V1(check.Substring(pos, part.Length - pos), out numLength);
+        if (num == Int32.MinValue) {
+          return part;
+        }
+        pos += numLength;
+
+        absoluteCol = true;
+        colNum = num;
+      }
+    }
+
+    // Ensure nothing remains unparsed
+    if (pos < part.Length) {
+      return part;
+    }
+
+    // Exit if neither row nor column is present
+    if ((rowNum == Int32.MinValue) && (colNum == Int32.MinValue)) {
+      return part;
+    }
+
+    // Append column
+    string result = "";
+    if (colNum >= 0) {
+      if (absoluteCol) {
+        result += "$";
+      }
+      result += GetColumnLetter(colNum);
+    }
+
+    // Append row
+    if (rowNum >= 0) {
+      if (absoluteRow) {
+        result += "$";
+      }
+      result += rowNum.ToString();
+    }
+
+    // Return result
+    return result;
+  }
+
+  private static int GetNumber_V1(string value, out int length) {
+    // Get number length
+    length = 0;
+
+    // Ensure value is present
+    if (string.IsNullOrWhiteSpace(value)) {
+      return Int32.MinValue;
+    }
+
+    // Check for sign
+    if ((length < value.Length) && ((value[length] == '-') || (value[length] == '+'))) {
+      length += 1;
+    }
+
+    // Get number length
+    while (length < value.Length && value[length] >= '0' && value[length] <= '9') {
+      length += 1;
+    }
+
+    // No number found
+    if (length == 0) {
+      return Int32.MinValue;
+    }
+
+    // Return number value
+    return (int.TryParse(value.Substring(0, length), out var result)) ? result : Int32.MinValue;
+  }
+
+  private static string RangeToA1_V1(string part, int row, int col, int rowIncr, int colIncr) {
+    // Split range expression
+    string[] cellValues = part.Split([':'], StringSplitOptions.RemoveEmptyEntries);
+
+    // Convert range expressions
+    string result = "";
+    result += ToAbs_V1(cellValues[0], row, col, rowIncr, colIncr);
+    result += ":";
+    result += ToAbs_V1(cellValues[1], row, col, rowIncr, colIncr);
+
+    // Return converted range expression
+    return result;
+  }
+
+  /// <summary>
+  /// Get the offset value for RC format
+  /// </summary>
+  /// <param name="value"></param>
+  /// <param name="offsetValue"></param>
+  /// <param name="fixedAddr"></param>
+  /// <returns></returns>
+  ///
+  private static int GetRc(string value, int offsetValue, out bool fixedAddr) {
+    if (value == "") {
+      fixedAddr = false;
+      return offsetValue;
+    }
+    int num;
+    if (value[0] == '['
+        && value[value.Length - 1]
+            == ']') //Offset?
+    {
+      fixedAddr = false;
+      if (int.TryParse(value.Substring(1, value.Length - 2), out num)) {
+        return (offsetValue + num);
+      }
+      return int.MinValue;
+    }
+    // Absolute address
+    fixedAddr = true;
+    if (int.TryParse(value, out num)) {
+      return num;
+    }
+    return int.MinValue;
+  }
+
+  /// <summary>
+  /// Returns the character representation of the numbered column
+  /// </summary>
+  /// <param name="iColumnNumber">The number of the column</param>
+  /// <returns>The letter representing the column</returns>
+  protected internal static string GetColumnLetter(int iColumnNumber) {
+    return GetColumnLetter(iColumnNumber, false);
+  }
+
+  protected internal static string GetColumnLetter(int iColumnNumber, bool fixedCol) {
+    if (iColumnNumber < 1) {
+      //throw new Exception("Column number is out of range");
+      return "#REF!";
+    }
+
+    string sCol = "";
+    do {
+      sCol = ((char)('A' + ((iColumnNumber - 1) % 26))) + sCol;
+      iColumnNumber = (iColumnNumber - ((iColumnNumber - 1) % 26)) / 26;
+    } while (iColumnNumber > 0);
+    return fixedCol ? "$" + sCol : sCol;
+  }
+
+  internal static bool GetRowColFromAddress(
+      string cellAddress,
+      out int fromRow,
+      out int fromColumn,
+      out int toRow,
+      out int toColumn) {
+    bool fixedFromRow,
+        fixedFromColumn,
+        fixedToRow,
+        fixedToColumn;
+    return GetRowColFromAddress(
+        cellAddress,
+        out fromRow,
+        out fromColumn,
+        out toRow,
+        out toColumn,
+        out fixedFromRow,
+        out fixedFromColumn,
+        out fixedToRow,
+        out fixedToColumn);
+  }
+
+  /// <summary>
+  /// Get the row/columns for a Cell-address
+  /// </summary>
+  /// <param name="cellAddress">The address</param>
+  /// <param name="fromRow">Returns the to column</param>
+  /// <param name="fromColumn">Returns the from column</param>
+  /// <param name="toRow">Returns the to row</param>
+  /// <param name="toColumn">Returns the from row</param>
+  /// <param name="fixedFromRow">Is the from row fixed?</param>
+  /// <param name="fixedFromColumn">Is the from column fixed?</param>
+  /// <param name="fixedToRow">Is the to row fixed?</param>
+  /// <param name="fixedToColumn">Is the to column fixed?</param>
+  /// <returns></returns>
+  internal static bool GetRowColFromAddress(
+      string cellAddress,
+      out int fromRow,
+      out int fromColumn,
+      out int toRow,
+      out int toColumn,
+      out bool fixedFromRow,
+      out bool fixedFromColumn,
+      out bool fixedToRow,
+      out bool fixedToColumn) {
+    bool ret;
+    if (cellAddress.IndexOf('[')
+        > 0) //External reference or reference to Table or Pivottable.
+    {
+      fromRow = -1;
+      fromColumn = -1;
+      toRow = -1;
+      toColumn = -1;
+      fixedFromRow = false;
+      fixedFromColumn = false;
+      fixedToRow = false;
+      fixedToColumn = false;
+      return false;
+    }
+
+    cellAddress = cellAddress.ToUpper(CultureInfo.InvariantCulture);
+    //This one can be removed when the worksheet Select format is fixed
+    if (cellAddress.IndexOf(' ') > 0) {
+      cellAddress = cellAddress.Substring(0, cellAddress.IndexOf(' '));
+    }
+
+    if (cellAddress.IndexOf(':') < 0) {
+      ret = GetRowColFromAddress(
+          cellAddress,
+          out fromRow,
+          out fromColumn,
+          out fixedFromRow,
+          out fixedFromColumn);
+      toColumn = fromColumn;
+      toRow = fromRow;
+      fixedToRow = fixedFromRow;
+      fixedToColumn = fixedFromColumn;
+    } else {
+      string[] cells = cellAddress.Split(':');
+      ret = GetRowColFromAddress(
+          cells[0],
+          out fromRow,
+          out fromColumn,
+          out fixedFromRow,
+          out fixedFromColumn);
+      if (ret) {
+        ret = GetRowColFromAddress(
+            cells[1],
+            out toRow,
+            out toColumn,
+            out fixedToRow,
+            out fixedToColumn);
+      } else {
+        GetRowColFromAddress(cells[1], out toRow, out toColumn, out fixedToRow, out fixedToColumn);
+      }
+
+      if (fromColumn <= 0) {
+        fromColumn = 1;
+      }
+      if (fromRow <= 0) {
+        fromRow = 1;
+      }
+      if (toColumn <= 0) {
+        toColumn = ExcelPackage.MaxColumns;
+      }
+      if (toRow <= 0) {
+        toRow = ExcelPackage.MaxRows;
+      }
+    }
+    return ret;
+  }
+
+  /// <summary>
+  /// Get the row/column for n Cell-address
+  /// </summary>
+  /// <param name="cellAddress">The address</param>
+  /// <param name="row">Returns Tthe row</param>
+  /// <param name="column">Returns the column</param>
+  /// <returns>true if valid</returns>
+  internal static bool GetRowColFromAddress(string cellAddress, out int row, out int column) {
+    return GetRowCol(cellAddress, out row, out column, true);
+  }
+
+  internal static bool GetRowColFromAddress(
+      string cellAddress,
+      out int row,
+      out int col,
+      out bool fixedRow,
+      out bool fixedCol) {
+    return GetRowCol(cellAddress, out row, out col, true, out fixedRow, out fixedCol);
+  }
+
+  /// <summary>
+  /// Get the row/column for a Cell-address
+  /// </summary>
+  /// <param name="address">the address</param>
+  /// <param name="row">returns the row</param>
+  /// <param name="col">returns the column</param>
+  /// <param name="throwException">throw exception if invalid, otherwise returns false</param>
+  /// <returns></returns>
+  internal static bool GetRowCol(string address, out int row, out int col, bool throwException) {
+    bool fixedRow,
+        fixedCol;
+    return GetRowCol(address, out row, out col, throwException, out fixedRow, out fixedCol);
+  }
+
+  internal static bool GetRowCol(
+      string address,
+      out int row,
+      out int col,
+      bool throwException,
+      out bool fixedRow,
+      out bool fixedCol) {
+    bool colPart = true;
+    int colStartIx = 0;
+    int colLength = 0;
+    col = 0;
+    row = 0;
+    fixedRow = false;
+    fixedCol = false;
+
+    if (address.EndsWith("#REF!")) {
+      row = 0;
+      col = 0;
+      return true;
+    }
+
+    int sheetMarkerIndex = address.IndexOf('!');
+    if (sheetMarkerIndex >= 0) {
+      colStartIx = sheetMarkerIndex + 1;
+    }
+    address = address.ToUpper(CultureInfo.InvariantCulture);
+    for (int i = colStartIx; i < address.Length; i++) {
+      char c = address[i];
+      if (colPart && (c >= 'A' && c <= 'Z') && colLength <= 3) {
+        col *= 26;
+        col += c - 64;
+        colLength++;
+      } else if (c >= '0' && c <= '9') {
+        row *= 10;
+        row += c - 48;
+        colPart = false;
+      } else if (c == '$') {
+        if (i == colStartIx) {
+          colStartIx++;
+          fixedCol = true;
+        } else {
+          colPart = false;
+          fixedRow = true;
+        }
+      } else {
+        row = 0;
+        col = 0;
+        if (throwException) {
+          throw (new(string.Format("Invalid Address format {0}", address)));
+        }
+        return false;
+      }
+    }
+    return row != 0 || col != 0;
+  }
+
+  internal static bool GetRowCol_V1(
+      string address,
+      out int row,
+      out int col,
+      bool throwException,
+      out bool fixedRow,
+      out bool fixedCol) {
+    bool colPart = true;
+    bool isFixed = false;
+    int colStartIx = 0;
+    int colLength = 0;
+    col = 0;
+    row = 0;
+    fixedRow = false;
+    fixedCol = false;
+
+    if (address.EndsWith("#REF!")) {
+      row = 0;
+      col = 0;
+      return true;
+    }
+
+    int sheetMarkerIndex = address.IndexOf('!');
+    if (sheetMarkerIndex >= 0) {
+      colStartIx = sheetMarkerIndex + 1;
+    }
+    address = address.ToUpper(CultureInfo.InvariantCulture);
+    for (int i = colStartIx; i < address.Length; i++) {
+      char c = address[i];
+      if (c == '$') {
+        // Absolute address
+        isFixed = true;
+      } else if (colPart && (c >= 'A' && c <= 'Z') && colLength <= 3) {
+        // Column portion of address
+        if (isFixed) {
+          fixedCol = true;
+          isFixed = false;
+        }
+
+        col *= 26;
+        col += c - 64;
+        colLength++;
+      } else if (c >= '0' && c <= '9') {
+        // Row portion of address
+        if (isFixed) {
+          fixedRow = true;
+          isFixed = false;
+        }
+
+        row *= 10;
+        row += c - 48;
+        colPart = false;
+      } else {
+        row = 0;
+        col = 0;
+        if (throwException) {
+          throw (new(string.Format("Invalid Address format {0}", address)));
+        }
+        return false;
+      }
+    }
+    return row != 0 || col != 0;
+  }
+
+  private static int GetColumn(string sCol) {
+    int col = 0;
+    int len = sCol.Length - 1;
+    for (int i = len; i >= 0; i--) {
+      col += (sCol[i] - 64) * (int)(Math.Pow(26, len - i));
+    }
+    return col;
+  }
+
+  /// <summary>
+  /// Returns the AlphaNumeric representation that Excel expects for a Cell Address
+  /// </summary>
+  /// <param name="row">The number of the row</param>
+  /// <param name="column">The number of the column in the worksheet</param>
+  /// <returns>The cell address in the format A1</returns>
+  public static string GetAddress(int row, int column) {
+    return GetAddress(row, column, false);
+  }
+
+  /// <summary>
+  /// Returns the AlphaNumeric representation that Excel expects for a Cell Address
+  /// </summary>
+  /// <param name="row">The number of the row</param>
+  /// <param name="column">The number of the column in the worksheet</param>
+  /// <param name="absoluteRow">Absolute row</param>
+  /// <param name="absoluteCol">Absolute column</param>
+  /// <returns>The cell address in the format A1</returns>
+  public static string GetAddress(int row, bool absoluteRow, int column, bool absoluteCol) {
+    return (absoluteCol ? "$" : "") + GetColumnLetter(column) + (absoluteRow ? "$" : "") + row;
+  }
+
+  /// <summary>
+  /// Returns the AlphaNumeric representation that Excel expects for a Cell Address
+  /// </summary>
+  /// <param name="row">The number of the row</param>
+  /// <param name="column">The number of the column in the worksheet</param>
+  /// <param name="absolute">Get an absolute address ($A$1)</param>
+  /// <returns>The cell address in the format A1</returns>
+  public static string GetAddress(int row, int column, bool absolute) {
+    if (row == 0 || column == 0) {
+      return "#REF!";
+    }
+    if (absolute) {
+      return ("$" + GetColumnLetter(column) + "$" + row);
+    }
+    return (GetColumnLetter(column) + row);
+  }
+
+  /// <summary>
+  /// Returns the AlphaNumeric representation that Excel expects for a Cell Address
+  /// </summary>
+  /// <param name="fromRow">From row number</param>
+  /// <param name="fromColumn">From column number</param>
+  /// <param name="toRow">To row number</param>
+  /// <param name="toColumn">From column number</param>
+  /// <returns>The cell address in the format A1</returns>
+  public static string GetAddress(int fromRow, int fromColumn, int toRow, int toColumn) {
+    return GetAddress(fromRow, fromColumn, toRow, toColumn, false);
+  }
+
+  /// <summary>
+  /// Returns the AlphaNumeric representation that Excel expects for a Cell Address
+  /// </summary>
+  /// <param name="fromRow">From row number</param>
+  /// <param name="fromColumn">From column number</param>
+  /// <param name="toRow">To row number</param>
+  /// <param name="toColumn">From column number</param>
+  /// <param name="absolute">if true address is absolute (like $A$1)</param>
+  /// <returns>The cell address in the format A1</returns>
+  public static string GetAddress(
+      int fromRow,
+      int fromColumn,
+      int toRow,
+      int toColumn,
+      bool absolute) {
+    if (fromRow == toRow && fromColumn == toColumn) {
+      return GetAddress(fromRow, fromColumn, absolute);
+    }
+    if (fromRow == 1 && toRow == ExcelPackage.MaxRows) {
+      var absChar = absolute ? "$" : "";
+      return absChar + GetColumnLetter(fromColumn) + ":" + absChar + GetColumnLetter(toColumn);
+    }
+    if (fromColumn == 1 && toColumn == ExcelPackage.MaxColumns) {
+      var absChar = absolute ? "$" : "";
+      return absChar + fromRow + ":" + absChar + toRow;
+    }
+    return GetAddress(fromRow, fromColumn, absolute) + ":" + GetAddress(toRow, toColumn, absolute);
+  }
+
+  /// <summary>
+  /// Returns the AlphaNumeric representation that Excel expects for a Cell Address
+  /// </summary>
+  /// <param name="fromRow">From row number</param>
+  /// <param name="fromColumn">From column number</param>
+  /// <param name="toRow">To row number</param>
+  /// <param name="toColumn">From column number</param>
+  /// <param name="fixedFromColumn"></param>
+  /// <param name="fixedFromRow"></param>
+  /// <param name="fixedToColumn"></param>
+  /// <param name="fixedToRow"></param>
+  /// <returns>The cell address in the format A1</returns>
+  public static string GetAddress(
+      int fromRow,
+      int fromColumn,
+      int toRow,
+      int toColumn,
+      bool fixedFromRow,
+      bool fixedFromColumn,
+      bool fixedToRow,
+      bool fixedToColumn) {
+    if (fromRow == toRow && fromColumn == toColumn) {
+      return GetAddress(fromRow, fixedFromRow, fromColumn, fixedFromColumn);
+    }
+    if (fromRow == 1 && toRow == ExcelPackage.MaxRows) {
+      return GetColumnLetter(fromColumn, fixedFromColumn)
+          + ":"
+          + GetColumnLetter(toColumn, fixedToColumn);
+    }
+    if (fromColumn == 1 && toColumn == ExcelPackage.MaxColumns) {
+      return (fixedFromRow ? "$" : "") + fromRow + ":" + (fixedToRow ? "$" : "") + toRow;
+    }
+    return GetAddress(fromRow, fixedFromRow, fromColumn, fixedFromColumn)
+        + ":"
+        + GetAddress(toRow, fixedToRow, toColumn, fixedToColumn);
+  }
+
+  /// <summary>
+  /// Get the full address including the worksheet name
+  /// </summary>
+  /// <param name="worksheetName">The name of the worksheet</param>
+  /// <param name="address">The address</param>
+  /// <returns>The full address</returns>
+  public static string GetFullAddress(string worksheetName, string address) {
+    return GetFullAddress(worksheetName, address, true);
+  }
+
+  internal static string GetFullAddress(string worksheetName, string address, bool fullRowCol) {
+    if (address.IndexOf("!") == -1 || address == "#REF!") {
+      if (fullRowCol) {
+        string[] cells = address.Split(':');
+        if (cells.Length > 0) {
+          address = string.Format("'{0}'!{1}", worksheetName, cells[0]);
+          if (cells.Length > 1) {
+            address += string.Format(":{0}", cells[1]);
+          }
+        }
+      } else {
+        var a = new ExcelAddressBase(address);
+        if ((a._fromRow == 1 && a._toRow == ExcelPackage.MaxRows)
+            || (a._fromCol == 1 && a._toCol == ExcelPackage.MaxColumns)) {
+          address = string.Format(
+              "'{0}'!{1}{2}:{3}{4}",
+              worksheetName,
+              GetColumnLetter(a._fromCol),
+              a._fromRow,
+              GetColumnLetter(a._toCol),
+              a._toRow);
+        } else {
+          address = GetFullAddress(worksheetName, address, true);
+        }
+      }
+    }
+    return address;
+  }
+
+  public static bool IsValidAddress(string address) {
+    address = address.ToUpper(CultureInfo.InvariantCulture);
+    string r1 = "",
+        c1 = "",
+        r2 = "",
+        c2 = "";
+    bool isSecond = false;
+    for (int i = 0; i < address.Length; i++) {
+      if (address[i] >= 'A' && address[i] <= 'Z') {
+        if (isSecond == false) {
+          if (r1 != "") {
+            return false;
+          }
+          c1 += address[i];
+          if (c1.Length > 3) {
+            return false;
+          }
+        } else {
+          if (r2 != "") {
+            return false;
+          }
+          c2 += address[i];
+          if (c2.Length > 3) {
+            return false;
+          }
+        }
+      } else if (address[i] >= '0' && address[i] <= '9') {
+        if (isSecond == false) {
+          r1 += address[i];
+          if (r1.Length > 7) {
+            return false;
+          }
+        } else {
+          r2 += address[i];
+          if (r2.Length > 7) {
+            return false;
+          }
+        }
+      } else if (address[i] == ':') {
+        isSecond = true;
+      } else if (address[i] == '$') {
+        if (i == address.Length - 1 || address[i + 1] == ':') {
+          return false;
+        }
+      } else {
+        return false;
+      }
+    }
+
+    if (r1 != ""
+        && c1 != ""
+        && r2 == ""
+        && c2
+            == "") //Single Cell
+    {
+      return (GetColumn(c1) <= ExcelPackage.MaxColumns && int.Parse(r1) <= ExcelPackage.MaxRows);
+    }
+    if (r1 != ""
+        && r2 != ""
+        && c1 != ""
+        && c2
+            != "") //Range
+    {
+      var iR2 = int.Parse(r2);
+      var iC2 = GetColumn(c2);
+
+      return GetColumn(c1) <= iC2
+          && int.Parse(r1) <= iR2
+          && iC2 <= ExcelPackage.MaxColumns
+          && iR2 <= ExcelPackage.MaxRows;
+    }
+    if (r1 == ""
+        && r2 == ""
+        && c1 != ""
+        && c2
+            != "") //Full Column
+    {
+      var c2N = GetColumn(c2);
+      return (GetColumn(c1) <= c2N && c2N <= ExcelPackage.MaxColumns);
+    }
+    if (r1 != "" && r2 != "" && c1 == "" && c2 == "") {
+      var iR2 = int.Parse(r2);
+
+      return int.Parse(r1) <= iR2 && iR2 <= ExcelPackage.MaxRows;
+    }
+    return false;
+  }
+
+  /// <summary>
+  /// Checks that a cell address (e.g. A5) is valid.
+  /// </summary>
+  /// <param name="cellAddress">The alphanumeric cell address</param>
+  /// <returns>True if the cell address is valid</returns>
+  public static bool IsValidCellAddress(string cellAddress) {
+    bool result = false;
+    try {
+      if (GetRowColFromAddress(cellAddress, out var row, out var col)) {
+        if (row > 0 && col > 0 && row <= ExcelPackage.MaxRows && col <= ExcelPackage.MaxColumns) {
+          result = true;
+        } else {
+          result = false;
+        }
+      }
+    } catch {}
+    return result;
+  }
+
+  /// <summary>
+  /// Updates the Excel formula so that all the cellAddresses are incremented by the row and column increments
+  /// if they fall after the afterRow and afterColumn.
+  /// Supports inserting rows and columns into existing templates.
+  /// </summary>
+  /// <param name="formula">The Excel formula</param>
+  /// <param name="rowIncrement">The amount to increment the cell reference by</param>
+  /// <param name="colIncrement">The amount to increment the cell reference by</param>
+  /// <param name="afterRow">Only change rows after this row</param>
+  /// <param name="afterColumn">Only change columns after this column</param>
+  /// <returns></returns>
+  internal static string UpdateFormulaReferences(
+      string formula,
+      int rowIncrement,
+      int colIncrement,
+      int afterRow,
+      int afterColumn,
+      bool setFixed = false) {
+    //return Translate(Formula, AddToRowColumnTranslator, afterRow, afterColumn, rowIncrement, colIncrement);
+    var d = new Dictionary<string, object>();
+    try {
+      var sct = new SourceCodeTokenizer(FunctionNameProvider.Empty, NameValueProvider.Empty);
+      var tokens = sct.Tokenize(formula);
+      String f = "";
+      foreach (var t in tokens) {
+        if (t.TokenType == TokenType.ExcelAddress) {
+          var a = new ExcelAddressBase(t.Value);
+
+          if (!String.IsNullOrEmpty(
+              a._ws)) // Bug 15339
+          {
+            // This is from a different worksheet, thus no update is required
+            f += a.Address;
+            continue;
+          }
+
+          if (rowIncrement > 0) {
+            a = a.AddRow(afterRow, rowIncrement, setFixed);
+          } else if (rowIncrement < 0) {
+            a = a.DeleteRow(afterRow, -rowIncrement, setFixed);
+          }
+          if (colIncrement > 0) {
+            a = a.AddColumn(afterColumn, colIncrement, setFixed);
+          } else if (colIncrement < 0) {
+            a = a.DeleteColumn(afterColumn, -colIncrement, setFixed);
+          }
+          if (a == null || !a.IsValidRowCol()) {
+            f += "#REF!";
+          } else {
+            f += a.Address;
+          }
+        } else {
+          f += t.Value;
+        }
+      }
+      return f;
+    } catch //Invalid formula, skip updateing addresses
+    {
+      return formula;
+    }
+  }
+}
diff --git a/AppsheetEpplus/ExcelColumn.cs b/AppsheetEpplus/ExcelColumn.cs
new file mode 100644
index 0000000..f6f5ef8
--- /dev/null
+++ b/AppsheetEpplus/ExcelColumn.cs
@@ -0,0 +1,252 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan K�llman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Jan K�llman		Initial Release		        2009-10-01
+ * Jan K�llman		License changed GPL-->LGPL 2011-12-27
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Represents one or more columns within the worksheet
+/// </summary>
+public class ExcelColumn : IRangeId {
+  private readonly ExcelWorksheet _worksheet;
+  private readonly XmlElement _colElement = null;
+
+  /// <summary>
+  /// Creates a new instance of the ExcelColumn class.
+  /// For internal use only!
+  /// </summary>
+  /// <param name="worksheet"></param>
+  /// <param name="col"></param>
+  protected internal ExcelColumn(ExcelWorksheet worksheet, int col) {
+    _worksheet = worksheet;
+    _columnMin = col;
+    _columnMax = col;
+    _width = _worksheet.DefaultColWidth;
+  }
+
+  internal int _columnMin;
+
+  /// <summary>
+  /// Sets the first column the definition refers to.
+  /// </summary>
+  public int ColumnMin => _columnMin;
+
+  //set { _columnMin=value; }
+  internal int _columnMax;
+
+  /// <summary>
+  /// Sets the last column the definition refers to.
+  /// </summary>
+  public int ColumnMax {
+    get => _columnMax;
+    set {
+      if (value < _columnMin && value > ExcelPackage.MaxColumns) {
+        throw new("ColumnMax out of range");
+      }
+
+      var cse = new CellsStoreEnumerator<object>(
+          _worksheet._values,
+          0,
+          0,
+          0,
+          ExcelPackage.MaxColumns);
+      while (cse.Next()) {
+        var c = cse.Value as ExcelColumn;
+        if (cse.Column > _columnMin && c.ColumnMax <= value && cse.Column != _columnMin) {
+          throw new(string.Format("ColumnMax can not span over existing column {0}.", c.ColumnMin));
+        }
+      }
+      _columnMax = value;
+    }
+  }
+
+  /// <summary>
+  /// Internal range id for the column
+  /// </summary>
+  internal ulong ColumnID => GetColumnId(_worksheet.SheetID, ColumnMin);
+
+  /// <summary>
+  /// Allows the column to be hidden in the worksheet
+  /// </summary>
+  internal bool _hidden;
+  public bool Hidden {
+    get => _hidden;
+    set => _hidden = value;
+  }
+
+  internal double VisualWidth {
+    get {
+      if (_hidden || (Collapsed && OutlineLevel > 0)) {
+        return 0;
+      }
+      return _width;
+    }
+  }
+  internal double _width;
+
+  /// <summary>
+  /// Sets the width of the column in the worksheet
+  /// </summary>
+  public double Width {
+    get => _width;
+    set {
+      _width = value;
+
+      if (_hidden && value != 0) {
+        _hidden = false;
+      }
+    }
+  }
+
+  /// <summary>
+  /// If set to true a column automaticlly resize(grow wider) when a user inputs numbers in a cell.
+  /// </summary>
+  public bool BestFit { get; set; }
+
+  /// <summary>
+  /// If the column is collapsed in outline mode
+  /// </summary>
+  public bool Collapsed { get; set; }
+
+  /// <summary>
+  /// Outline level. Zero if no outline
+  /// </summary>
+  public int OutlineLevel { get; set; }
+
+  /// <summary>
+  /// Phonetic
+  /// </summary>
+  public bool Phonetic { get; set; }
+
+  /// <summary>
+  /// The Style applied to the whole column. Only effects cells with no individual style set.
+  /// Use Range object if you want to set specific styles.
+  /// </summary>
+  public ExcelStyle Style {
+    get {
+      string letter = ExcelCellBase.GetColumnLetter(ColumnMin);
+      string endLetter = ExcelCellBase.GetColumnLetter(ColumnMax);
+      return _worksheet.Workbook.Styles.GetStyleObject(
+          StyleID,
+          _worksheet.PositionID,
+          letter + ":" + endLetter);
+    }
+  }
+  internal string _styleName = "";
+
+  /// <summary>
+  /// Sets the style for the entire column using a style name.
+  /// </summary>
+  public string StyleName {
+    get => _styleName;
+    set {
+      StyleID = _worksheet.Workbook.Styles.GetStyleIdFromName(value);
+      _styleName = value;
+    }
+  }
+
+  //internal int _styleID = 0;
+  /// <summary>
+  /// Sets the style for the entire column using the style ID.
+  /// </summary>
+  public int StyleID {
+    get => _worksheet._styles.GetValue(0, ColumnMin);
+    set => _worksheet._styles.SetValue(0, ColumnMin, value);
+  }
+
+  /// <summary>
+  /// Adds a manual page break after the column.
+  /// </summary>
+  public bool PageBreak { get; set; }
+  public bool Merged {
+    get => _worksheet.MergedCells[ColumnMin, 0] != null;
+    set => _worksheet.MergedCells.Add(new(1, ColumnMin, ExcelPackage.MaxRows, ColumnMax), true);
+  }
+
+  /// <summary>
+  /// Returns the range of columns covered by the column definition.
+  /// </summary>
+  /// <returns>A string describing the range of columns covered by the column definition.</returns>
+  public override string ToString() {
+    return string.Format(
+        "Column Range: {0} to {1}",
+        _colElement.GetAttribute("min"),
+        _colElement.GetAttribute("min"));
+  }
+
+  /// <summary>
+  /// Get the internal RangeID
+  /// </summary>
+  /// <param name="sheetId">Sheet no</param>
+  /// <param name="column">Column</param>
+  /// <returns></returns>
+  internal static ulong GetColumnId(int sheetId, int column) {
+    return ((ulong)sheetId) + (((ulong)column) << 15);
+  }
+
+  ulong IRangeId.RangeID {
+    get => ColumnID;
+    set {
+      int prevColMin = _columnMin;
+      _columnMin = ((int)(value >> 15) & 0x3FF);
+      _columnMax += prevColMin - ColumnMin;
+      //Todo:More Validation
+      if (_columnMax > ExcelPackage.MaxColumns) {
+        _columnMax = ExcelPackage.MaxColumns;
+      }
+    }
+  }
+
+  /// <summary>
+  /// Copies the current column to a new worksheet
+  /// </summary>
+  /// <param name="added">The worksheet where the copy will be created</param>
+  internal ExcelColumn Clone(ExcelWorksheet added) {
+    return Clone(added, ColumnMin);
+  }
+
+  internal ExcelColumn Clone(ExcelWorksheet added, int col) {
+    ExcelColumn newCol = added.Column(col);
+    newCol.ColumnMax = ColumnMax;
+    newCol.BestFit = BestFit;
+    newCol.Collapsed = Collapsed;
+    newCol.OutlineLevel = OutlineLevel;
+    newCol.PageBreak = PageBreak;
+    newCol.Phonetic = Phonetic;
+    newCol._styleName = _styleName;
+    newCol.StyleID = StyleID;
+    newCol.Width = Width;
+    newCol.Hidden = Hidden;
+    return newCol;
+  }
+}
diff --git a/AppsheetEpplus/ExcelComment.cs b/AppsheetEpplus/ExcelComment.cs
new file mode 100644
index 0000000..402f9a6
--- /dev/null
+++ b/AppsheetEpplus/ExcelComment.cs
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Jan Källman		Initial Release
+ * Jan Källman		License changed GPL-->LGPL 2011-12-27
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// An Excel Cell Comment
+/// </summary>
+public class ExcelComment : ExcelVmlDrawingComment {
+  private readonly XmlHelper _commentHelper;
+  private readonly string _text;
+
+  internal ExcelComment(XmlNamespaceManager ns, XmlNode commentTopNode, ExcelRangeBase cell)
+      : base(null, cell, cell.Worksheet.VmlDrawingsComments.NameSpaceManager) {
+    //_commentHelper = new XmlHelper(ns, commentTopNode);
+    _commentHelper = XmlHelperFactory.Create(ns, commentTopNode);
+    var textElem = commentTopNode.SelectSingleNode("d:text", ns);
+    if (textElem == null) {
+      textElem = commentTopNode.OwnerDocument.CreateElement("text", ExcelPackage._schemaMain);
+      commentTopNode.AppendChild(textElem);
+    }
+    if (!cell.Worksheet._vmlDrawings.ContainsKey(
+        ExcelCellBase.GetCellId(cell.Worksheet.SheetID, cell.Start.Row, cell.Start.Column))) {
+      cell.Worksheet._vmlDrawings.Add(cell);
+    }
+
+    TopNode = cell.Worksheet.VmlDrawingsComments[ExcelCellBase.GetCellId(
+          cell.Worksheet.SheetID,
+          cell.Start.Row,
+          cell.Start.Column)].TopNode;
+    RichText = new(ns, textElem);
+    var tNode = textElem.SelectSingleNode("d:t", ns);
+    if (tNode != null) {
+      _text = tNode.InnerText;
+    }
+  }
+
+  private const string _authorsPath = "d:comments/d:authors";
+  private const string _authorPath = "d:comments/d:authors/d:author";
+
+  /// <summary>
+  /// Author
+  /// </summary>
+  public string Author {
+    get {
+      int authorRef = _commentHelper.GetXmlNodeInt("@authorId");
+      return _commentHelper.TopNode.OwnerDocument
+          .SelectSingleNode(
+              string.Format("{0}[{1}]", _authorPath, authorRef + 1),
+              _commentHelper.NameSpaceManager)
+          .InnerText;
+    }
+  }
+
+  private int GetAuthor(string value) {
+    int authorRef = 0;
+    bool found = false;
+    foreach (XmlElement node in _commentHelper.TopNode.OwnerDocument.SelectNodes(
+        _authorPath,
+        _commentHelper.NameSpaceManager)) {
+      if (node.InnerText == value) {
+        found = true;
+        break;
+      }
+      authorRef++;
+    }
+    if (!found) {
+      var elem = _commentHelper.TopNode.OwnerDocument.CreateElement(
+          "d",
+          "author",
+          ExcelPackage._schemaMain);
+      _commentHelper.TopNode.OwnerDocument
+          .SelectSingleNode(_authorsPath, _commentHelper.NameSpaceManager)
+          .AppendChild(elem);
+      elem.InnerText = value;
+    }
+    return authorRef;
+  }
+
+  /// <summary>
+  /// The comment text
+  /// </summary>
+  public string Text {
+    get {
+      if (!string.IsNullOrEmpty(RichText.Text)) {
+        return RichText.Text;
+      }
+      return _text;
+    }
+  }
+
+  /// <summary>
+  /// Sets the font of the first richtext item.
+  /// </summary>
+  public ExcelRichText Font {
+    get {
+      if (RichText.Count > 0) {
+        return RichText[0];
+      }
+      return null;
+    }
+  }
+
+  /// <summary>
+  /// Richtext collection
+  /// </summary>
+  internal ExcelRichTextCollection RichText { get; set; }
+}
diff --git a/AppsheetEpplus/ExcelCommentCollection.cs b/AppsheetEpplus/ExcelCommentCollection.cs
new file mode 100644
index 0000000..c12fbbc
--- /dev/null
+++ b/AppsheetEpplus/ExcelCommentCollection.cs
@@ -0,0 +1,143 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Jan Källman		License changed GPL-->LGPL 2011-12-27
+ *******************************************************************************/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Collection of Excelcomment objects
+/// </summary>
+public class ExcelCommentCollection : IEnumerable, IDisposable {
+  internal RangeCollection _comments;
+
+  internal ExcelCommentCollection(ExcelPackage pck, ExcelWorksheet ws, XmlNamespaceManager ns) {
+    CommentXml.PreserveWhitespace = false;
+    NameSpaceManager = ns;
+    Worksheet = ws;
+    CreateXml(pck);
+    AddCommentsFromXml();
+  }
+
+  private void CreateXml(ExcelPackage pck) {
+    var commentParts = Worksheet.Part.GetRelationshipsByType(ExcelPackage._schemaComment);
+    bool isLoaded = false;
+    CommentXml = new();
+    foreach (var commentPart in commentParts) {
+      Uri = UriHelper.ResolvePartUri(commentPart.SourceUri, commentPart.TargetUri);
+      Part = pck.Package.GetPart(Uri);
+      XmlHelper.LoadXmlSafe(CommentXml, Part.GetStream());
+      RelId = commentPart.Id;
+      isLoaded = true;
+    }
+    //Create a new document
+    if (!isLoaded) {
+      CommentXml.LoadXml(
+          "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><comments xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\"><authors /><commentList /></comments>");
+      Uri = null;
+    }
+  }
+
+  private void AddCommentsFromXml() {
+    var lst = new List<IRangeId>();
+    foreach (XmlElement node in CommentXml.SelectNodes(
+        "//d:commentList/d:comment",
+        NameSpaceManager)) {
+      var comment = new ExcelComment(
+          NameSpaceManager,
+          node,
+          new(Worksheet, node.GetAttribute("ref")));
+      lst.Add(comment);
+    }
+    _comments = new(lst);
+  }
+
+  /// <summary>
+  /// Access to the comment xml document
+  /// </summary>
+  public XmlDocument CommentXml { get; set; } = new();
+
+  internal Uri Uri { get; set; }
+
+  internal string RelId { get; set; }
+
+  internal XmlNamespaceManager NameSpaceManager { get; set; }
+
+  internal ZipPackagePart Part { get; set; }
+
+  /// <summary>
+  /// A reference to the worksheet object
+  /// </summary>
+  public ExcelWorksheet Worksheet { get; set; }
+
+  /// <summary>
+  /// Number of comments in the collection
+  /// </summary>
+  public int Count => _comments.Count;
+
+  /// <summary>
+  /// Indexer for the comments collection
+  /// </summary>
+  /// <param name="index">The index</param>
+  /// <returns>The comment</returns>
+  public ExcelComment this[int index] {
+    get {
+      if (index < 0 || index >= _comments.Count) {
+        throw (new ArgumentOutOfRangeException("Comment index out of range"));
+      }
+      return _comments[index] as ExcelComment;
+    }
+  }
+
+  /// <summary>
+  /// Indexer for the comments collection
+  /// </summary>
+  /// <param name="cell">The cell</param>
+  /// <returns>The comment</returns>
+  public ExcelComment this[ExcelCellAddress cell] {
+    get {
+      ulong cellId = ExcelCellBase.GetCellId(Worksheet.SheetID, cell.Row, cell.Column);
+      if (_comments.IndexOf(cellId) >= 0) {
+        return _comments[cellId] as ExcelComment;
+      }
+      return null;
+    }
+  }
+
+  void IDisposable.Dispose() {}
+
+  IEnumerator IEnumerable.GetEnumerator() {
+    return _comments;
+  }
+}
diff --git a/AppsheetEpplus/ExcelHyperLink.cs b/AppsheetEpplus/ExcelHyperLink.cs
new file mode 100644
index 0000000..34709a6
--- /dev/null
+++ b/AppsheetEpplus/ExcelHyperLink.cs
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		Added this class		        2010-01-24
+ * Jan Källman		License changed GPL-->LGPL 2011-12-27
+ *******************************************************************************/
+
+using System;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// HyperlinkClass
+/// </summary>
+public class ExcelHyperLink : Uri {
+  /// <summary>
+  /// A new hyperlink with the specified URI
+  /// </summary>
+  /// <param name="uriString">The URI</param>
+  public ExcelHyperLink(string uriString)
+      : base(uriString) {
+    OriginalUri = this;
+  }
+
+  /// <summary>
+  /// A new hyperlink with the specified URI. This syntax is obsolete
+  /// </summary>
+  /// <param name="uriString">The URI</param>
+  /// <param name="dontEscape"></param>
+  [Obsolete(
+      "base constructor 'System.Uri.Uri(string, bool)' is obsolete: 'The constructor has been deprecated. Please use new ExcelHyperLink(string). The dontEscape parameter is deprecated and is always false.")]
+  public ExcelHyperLink(string uriString, bool dontEscape)
+      : base(uriString, dontEscape) {
+    OriginalUri = this;
+  }
+
+  /// <summary>
+  /// A new hyperlink with the specified URI and kind
+  /// </summary>
+  /// <param name="uriString">The URI</param>
+  /// <param name="uriKind">Kind (absolute/relative or indeterminate)</param>
+  public ExcelHyperLink(string uriString, UriKind uriKind)
+      : base(uriString, uriKind) {
+    OriginalUri = this;
+  }
+
+  /// <summary>
+  /// Sheet internal reference
+  /// </summary>
+  /// <param name="referenceAddress">Address</param>
+  /// <param name="display">Displayed text</param>
+  public ExcelHyperLink(string referenceAddress, string display)
+      : base(
+          "xl://internal") //URI is not used on internal links so put a dummy uri here.
+  {
+    _referenceAddress = referenceAddress;
+    _display = display;
+  }
+
+  private string _referenceAddress;
+
+  /// <summary>
+  /// The Excel address for internal links.
+  /// </summary>
+  public string ReferenceAddress {
+    get => _referenceAddress;
+    set => _referenceAddress = value;
+  }
+
+  private string _display = "";
+
+  /// <summary>
+  /// Displayed text
+  /// </summary>
+  public string Display {
+    get => _display;
+    set => _display = value;
+  }
+
+  /// <summary>
+  /// Tooltip
+  /// </summary>
+  public string ToolTip { get; set; }
+
+  private int _colSpann;
+
+  /// <summary>
+  /// If the hyperlink spans multiple columns
+  /// </summary>
+  public int ColSpann {
+    get => _colSpann;
+    set => _colSpann = value;
+  }
+
+  private int _rowSpann;
+
+  /// <summary>
+  /// If the hyperlink spans multiple rows
+  /// </summary>
+  public int RowSpann {
+    get => _rowSpann;
+    set => _rowSpann = value;
+  }
+
+  /// <summary>
+  /// Used to handle non absolute URI's.
+  /// Is used if IsAblsoluteUri is true. The base URI will have a dummy value of xl://nonAbsolute.
+  /// </summary>
+  public Uri OriginalUri { get; internal set; }
+
+  internal string RId { get; set; }
+}
diff --git a/AppsheetEpplus/ExcelNamedRange.cs b/AppsheetEpplus/ExcelNamedRange.cs
new file mode 100644
index 0000000..13cb291
--- /dev/null
+++ b/AppsheetEpplus/ExcelNamedRange.cs
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		Added this class		        2010-01-28
+ * Jan Källman		License changed GPL-->LGPL 2011-12-27
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// A named range.
+/// </summary>
+public sealed class ExcelNamedRange : ExcelRangeBase {
+  private readonly ExcelWorksheet _sheet;
+
+  /// <summary>
+  /// A named range
+  /// </summary>
+  /// <param name="name">The name</param>
+  /// <param name="nameSheet">The sheet containing the name. null if its a global name</param>
+  /// <param name="sheet">Sheet where the address points</param>
+  /// <param name="address">The address</param>
+  /// <param name="index">The index in the collection</param>
+  public ExcelNamedRange(
+      string name,
+      ExcelWorksheet nameSheet,
+      ExcelWorksheet sheet,
+      string address,
+      int index)
+      : base(sheet, address) {
+    Name = name;
+    _sheet = nameSheet;
+    Index = index;
+  }
+
+  internal ExcelNamedRange(string name, ExcelWorkbook wb, ExcelWorksheet nameSheet, int index)
+      : base(wb, nameSheet, name, true) {
+    Name = name;
+    _sheet = nameSheet;
+    Index = index;
+  }
+
+  /// <summary>
+  /// Name of the range
+  /// </summary>
+  public string Name { get; internal set; }
+
+  /// <summary>
+  /// Is the named range local for the sheet
+  /// </summary>
+  public int LocalSheetId {
+    get {
+      if (_sheet == null) {
+        return -1;
+      }
+      return _sheet.PositionID - 1;
+    }
+  }
+
+  internal int Index { get; set; }
+
+  /// <summary>
+  /// Is the name hidden
+  /// </summary>
+  public bool IsNameHidden { get; set; }
+
+  /// <summary>
+  /// A comment for the Name
+  /// </summary>
+  public string NameComment { get; set; }
+
+  internal object NameValue { get; set; }
+
+  internal string NameFormula { get; set; }
+
+  public override string ToString() {
+    return Name;
+  }
+}
diff --git a/AppsheetEpplus/ExcelNamedRangeCollection.cs b/AppsheetEpplus/ExcelNamedRangeCollection.cs
new file mode 100644
index 0000000..79f6471
--- /dev/null
+++ b/AppsheetEpplus/ExcelNamedRangeCollection.cs
@@ -0,0 +1,206 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		Added this class		        2010-01-28
+ * Jan Källman		License changed GPL-->LGPL 2011-12-27
+ *******************************************************************************/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Collection for named ranges
+/// </summary>
+public class ExcelNamedRangeCollection : IEnumerable<ExcelNamedRange> {
+  internal ExcelWorksheet _ws;
+  internal ExcelWorkbook _wb;
+
+  internal ExcelNamedRangeCollection(ExcelWorkbook wb) {
+    _wb = wb;
+    _ws = null;
+  }
+
+  internal ExcelNamedRangeCollection(ExcelWorkbook wb, ExcelWorksheet ws) {
+    _wb = wb;
+    _ws = ws;
+  }
+
+  private readonly List<ExcelNamedRange> _list = new();
+  private readonly Dictionary<string, int> _dic = new(StringComparer.InvariantCultureIgnoreCase);
+
+  /// <summary>
+  /// Add a new named range
+  /// </summary>
+  /// <param name="name">The name</param>
+  /// <param name="range">The range</param>
+  /// <returns></returns>
+  public ExcelNamedRange Add(string name, ExcelRangeBase range) {
+    ExcelNamedRange item;
+    if (range.IsName) {
+      item = new(name, _wb, _ws, _dic.Count);
+    } else {
+      item = new(name, _ws, range.Worksheet, range.Address, _dic.Count);
+    }
+
+    AddName(name, item);
+
+    return item;
+  }
+
+  private void AddName(string name, ExcelNamedRange item) {
+    // Is 'Name' already present
+    if (_dic.ContainsKey(name)) {
+      int index = _dic[name];
+      if ((0 <= index) && (index < _list.Count)) {
+        ExcelNamedRange listItem = _list[index];
+        if ((listItem != null)
+            && (listItem.FullAddress != null)
+            && (listItem.FullAddress == item.FullAddress)) {
+          return;
+        }
+
+        //throw new Exception(string.Format("Name '{0}' is defined in the worksheet more than once. First as '{1}' and second as '{2}'.", Name, listItem.FullAddress, item.FullAddress));
+        return;
+      }
+
+      //throw new Exception(string.Format("Name '{0}' is defined in the worksheet more than once.", Name));
+      return;
+    }
+
+    _dic.Add(name, _list.Count);
+    _list.Add(item);
+  }
+
+  /// <summary>
+  /// Add a defined name referencing value
+  /// </summary>
+  /// <param name="name"></param>
+  /// <param name="value"></param>
+  /// <returns></returns>
+  public ExcelNamedRange AddValue(string name, object value) {
+    var item = new ExcelNamedRange(name, _wb, _ws, _dic.Count);
+    item.NameValue = value;
+    AddName(name, item);
+    return item;
+  }
+
+  /// <summary>
+  /// Add a defined name referencing a formula -- the method name contains a typo.
+  /// This method is obsolete and will be removed in the future.
+  /// Use <see cref="AddFormula"/>
+  /// </summary>
+  /// <param name="name"></param>
+  /// <param name="formula"></param>
+  /// <returns></returns>
+  [Obsolete("Call AddFormula() instead.  See Issue Tracker Id #14687")]
+  public ExcelNamedRange AddFormla(string name, string formula) {
+    return AddFormula(name, formula);
+  }
+
+  /// <summary>
+  /// Add a defined name referencing a formula
+  /// </summary>
+  /// <param name="name"></param>
+  /// <param name="formula"></param>
+  /// <returns></returns>
+  public ExcelNamedRange AddFormula(string name, string formula) {
+    var item = new ExcelNamedRange(name, _wb, _ws, _dic.Count);
+    item.NameFormula = formula;
+    AddName(name, item);
+    return item;
+  }
+
+  /// <summary>
+  /// Remove a defined name from the collection
+  /// </summary>
+  /// <param name="name">The name</param>
+  public void Remove(string name) {
+    if (_dic.ContainsKey(name)) {
+      var ix = _dic[name];
+
+      for (int i = ix + 1; i < _list.Count; i++) {
+        _dic.Remove(_list[i].Name);
+        _list[i].Index--;
+        _dic.Add(_list[i].Name, _list[i].Index);
+      }
+      _dic.Remove(name);
+      _list.RemoveAt(ix);
+    }
+  }
+
+  /// <summary>
+  /// Checks collection for the presence of a key
+  /// </summary>
+  /// <param name="key">key to search for</param>
+  /// <returns>true if the key is in the collection</returns>
+  public bool ContainsKey(string key) {
+    return _dic.ContainsKey(key);
+  }
+
+  /// <summary>
+  /// The current number of items in the collection
+  /// </summary>
+  public int Count => _dic.Count;
+
+  /// <summary>
+  /// Name indexer
+  /// </summary>
+  /// <param name="name">The name (key) for a Named range</param>
+  /// <returns>a reference to the range</returns>
+  /// <remarks>
+  /// Throws a KeyNotFoundException if the key is not in the collection.
+  /// </remarks>
+  public ExcelNamedRange this[string name] => _list[_dic[name]];
+
+  public ExcelNamedRange this[int index] => _list[index];
+
+  /// <summary>
+  /// Implement interface method IEnumerator&lt;ExcelNamedRange&gt; GetEnumerator()
+  /// </summary>
+  /// <returns></returns>
+  public IEnumerator<ExcelNamedRange> GetEnumerator() {
+    return _list.GetEnumerator();
+  }
+
+  /// <summary>
+  /// Implement interface method IEnumeratable GetEnumerator()
+  /// </summary>
+  /// <returns></returns>
+  IEnumerator IEnumerable.GetEnumerator() {
+    return _list.GetEnumerator();
+  }
+
+  internal void Clear() {
+    while (Count > 0) {
+      Remove(_list[0].Name);
+    }
+  }
+}
diff --git a/AppsheetEpplus/ExcelPackage.cs b/AppsheetEpplus/ExcelPackage.cs
new file mode 100644
index 0000000..68f1b59
--- /dev/null
+++ b/AppsheetEpplus/ExcelPackage.cs
@@ -0,0 +1,213 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		                Initial Release		        2009-10-01
+ * Starnuto Di Topo & Jan Källman   Added stream constructors
+ *                                  and Load method Save as
+ *                                  stream                      2010-03-14
+ * Jan Källman		License changed GPL-->LGPL 2011-12-27
+ *******************************************************************************/
+
+using System;
+using System.IO;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Represents an Excel XLSX file package.
+/// This is the top-level object to access all parts of the document.
+/// </summary>
+public sealed class ExcelPackage {
+  /// <summary>
+  /// Extention Schema types
+  /// </summary>
+  internal const string _schemaXmlExtension = "application/xml";
+  internal const string _schemaRelsExtension =
+      "application/vnd.openxmlformats-package.relationships+xml";
+
+  /// <summary>
+  /// Main Xml schema name
+  /// </summary>
+  internal const string _schemaMain = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
+
+  /// <summary>
+  /// Relationship schema name
+  /// </summary>
+  internal const string _schemaRelationships =
+      "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
+
+  internal const string _schemaMicrosoftVml = "urn:schemas-microsoft-com:vml";
+  internal const string _schemaMicrosoftOffice = "urn:schemas-microsoft-com:office:office";
+  internal const string _schemaMicrosoftExcel = "urn:schemas-microsoft-com:office:excel";
+
+  internal const string _schemaChart = "http://schemas.openxmlformats.org/drawingml/2006/chart";
+  internal const string _schemaHyperlink =
+      "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
+  internal const string _schemaComment =
+      "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
+
+  //Office properties
+  internal const string _schemaCore =
+      "http://schemas.openxmlformats.org/package/2006/metadata/core-properties";
+  internal const string _schemaExtended =
+      "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties";
+  internal const string _schemaCustom =
+      "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties";
+  internal const string _schemaDc = "http://purl.org/dc/elements/1.1/";
+  internal const string _schemaDcTerms = "http://purl.org/dc/terms/";
+  internal const string _schemaDcmiType = "http://purl.org/dc/dcmitype/";
+  internal const string _schemaXsi = "http://www.w3.org/2001/XMLSchema-instance";
+  internal const string _schemaVt =
+      "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes";
+
+  internal const string _contentTypeSharedString =
+      "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml";
+
+  /// <summary>
+  /// Maximum number of columns in a worksheet (16384).
+  /// </summary>
+  public const int MaxColumns = 16384;
+
+  /// <summary>
+  /// Maximum number of rows in a worksheet (1048576).
+  /// </summary>
+  public const int MaxRows = 1048576;
+
+  /// <summary>
+  /// Create a new, empty package.
+  /// </summary>
+  public ExcelPackage() {
+    Package = new();
+    Workbook = new(this, CreateDefaultNsm());
+  }
+
+  /// <summary>
+  /// Create a new instance of the ExcelPackage class based on an existing file.
+  /// </summary>
+  public ExcelPackage(FileInfo newFile) {
+    using var inputStream = newFile.OpenRead();
+    Package = new(inputStream);
+    Workbook = new(this, CreateDefaultNsm());
+  }
+
+  /// <summary>
+  /// Create a new instance of the ExcelPackage class based on a stream.
+  /// </summary>
+  public ExcelPackage(Stream newStream) {
+    Package = new(newStream);
+    Workbook = new(this, CreateDefaultNsm());
+  }
+
+  internal ZipPackage Package { get; }
+
+  /// <summary>
+  /// Returns a reference to the workbook component within the package.
+  /// All worksheets and cells can be accessed through the workbook.
+  /// </summary>
+  public ExcelWorkbook Workbook { get; }
+
+  private XmlNamespaceManager CreateDefaultNsm() {
+    //  Create a NamespaceManager to handle the default namespace,
+    //  and create a prefix for the default namespace:
+    NameTable nt = new NameTable();
+    var ns = new XmlNamespaceManager(nt);
+    ns.AddNamespace(string.Empty, _schemaMain);
+    ns.AddNamespace("d", _schemaMain);
+    ns.AddNamespace("r", _schemaRelationships);
+    ns.AddNamespace("c", _schemaChart);
+    ns.AddNamespace("vt", _schemaVt);
+    // extended properties (app.xml)
+    ns.AddNamespace("xp", _schemaExtended);
+    // custom properties
+    ns.AddNamespace("ctp", _schemaCustom);
+    // core properties
+    ns.AddNamespace("cp", _schemaCore);
+    // core property namespaces
+    ns.AddNamespace("dc", _schemaDc);
+    ns.AddNamespace("dcterms", _schemaDcTerms);
+    ns.AddNamespace("dcmitype", _schemaDcmiType);
+    ns.AddNamespace("xsi", _schemaXsi);
+    return ns;
+  }
+
+  internal XmlDocument GetXmlDocument(Uri uri) {
+    var xmlDocument = new XmlDocument();
+    var part = Package.GetPart(uri);
+    XmlHelper.LoadXmlSafe(xmlDocument, part.GetStream());
+    part.SaveHandler = writer => xmlDocument.Save(writer);
+    return xmlDocument;
+  }
+
+  internal ZipPackageRelationship CreateXmlDocument(
+      Uri uri,
+      string contentType,
+      string relationship,
+      XmlDocument newDoc) {
+    Package.CreatePart(uri, contentType, newDoc.Save);
+    return Package.CreateRelationship(
+        UriHelper.GetRelativeUri(new("/xl", UriKind.Relative), uri),
+        TargetMode.Internal,
+        relationship);
+  }
+
+  internal XmlDocument GetOrCreateXmlDocument(
+      Uri uri,
+      string contentType,
+      string relationship,
+      Func<XmlDocument> createDocument) {
+    if (Package.PartExists(uri)) {
+      return GetXmlDocument(uri);
+    }
+    var newDoc = createDocument();
+    CreateXmlDocument(uri, contentType, relationship, newDoc);
+    return newDoc;
+  }
+
+  internal XmlDocument GetOrCreateXmlDocument(
+      Uri uri,
+      string contentType,
+      string relationship,
+      string initialDocumentXml) =>
+    GetOrCreateXmlDocument(
+        uri,
+        contentType,
+        relationship,
+        () => {
+          var emptyDocument = new XmlDocument();
+          emptyDocument.LoadXml(initialDocumentXml);
+          return emptyDocument;
+        });
+
+  public byte[] GetAsByteArray() {
+    var result = new MemoryStream();
+    Workbook.Save();
+    Package.Save(result);
+    return result.ToArray();
+  }
+}
diff --git a/AppsheetEpplus/ExcelProtectedRange.cs b/AppsheetEpplus/ExcelProtectedRange.cs
new file mode 100644
index 0000000..ac9a0ec
--- /dev/null
+++ b/AppsheetEpplus/ExcelProtectedRange.cs
@@ -0,0 +1,14 @@
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+public class ExcelProtectedRange : XmlHelper {
+  public string Name => GetXmlNodeString("@name");
+
+  private ExcelAddress _address;
+
+  public ExcelAddress Address => _address ??= new(GetXmlNodeString("@sqref"));
+
+  internal ExcelProtectedRange(XmlNamespaceManager ns, XmlNode topNode)
+      : base(ns, topNode) {}
+}
diff --git a/AppsheetEpplus/ExcelProtectedRangeCollection.cs b/AppsheetEpplus/ExcelProtectedRangeCollection.cs
new file mode 100644
index 0000000..71c399b
--- /dev/null
+++ b/AppsheetEpplus/ExcelProtectedRangeCollection.cs
@@ -0,0 +1,31 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+public class ExcelProtectedRangeCollection : XmlHelper, IEnumerable<ExcelProtectedRange> {
+  internal ExcelProtectedRangeCollection(XmlNamespaceManager nsm, XmlNode topNode)
+      : base(nsm, topNode) {
+    foreach (XmlNode protectedRangeNode in topNode.SelectNodes(
+        "d:protectedRanges/d:protectedRange",
+        nsm)) {
+      if (!(protectedRangeNode is XmlElement)) {
+        continue;
+      }
+      _baseList.Add(new(nsm, topNode));
+    }
+  }
+
+  private readonly List<ExcelProtectedRange> _baseList = new();
+
+  public ExcelProtectedRange this[int index] => _baseList[index];
+
+  IEnumerator<ExcelProtectedRange> IEnumerable<ExcelProtectedRange>.GetEnumerator() {
+    return _baseList.GetEnumerator();
+  }
+
+  IEnumerator IEnumerable.GetEnumerator() {
+    return _baseList.GetEnumerator();
+  }
+}
diff --git a/AppsheetEpplus/ExcelProtection.cs b/AppsheetEpplus/ExcelProtection.cs
new file mode 100644
index 0000000..de9ce06
--- /dev/null
+++ b/AppsheetEpplus/ExcelProtection.cs
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		    Added		10-AUG-2010
+ * Jan Källman		    License changed GPL-->LGPL 2011-12-27
+ *******************************************************************************/
+
+using System.Collections.Immutable;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Sets protection on the workbook level
+///<seealso cref="ExcelEncryption"/>
+///<seealso cref="ExcelSheetProtection"/>
+/// </summary>
+public class ExcelProtection : XmlHelper {
+  protected override ImmutableArray<string> SchemaNodeOrder =>
+    ExcelWorkbook.WorkbookSchemaNodeOrder;
+
+  internal ExcelProtection(XmlNamespaceManager ns, XmlNode topNode)
+      : base(ns, topNode) {}
+
+  private const string _lockStructurePath = "d:workbookProtection/@lockStructure";
+
+  /// <summary>
+  /// Locks the structure,which prevents users from adding or deleting worksheets or from displaying hidden worksheets.
+  /// </summary>
+  public bool LockStructure {
+    get => GetXmlNodeBool(_lockStructurePath, false);
+    set => SetXmlNodeBool(_lockStructurePath, value, false);
+  }
+
+  private const string _lockWindowsPath = "d:workbookProtection/@lockWindows";
+
+  /// <summary>
+  /// Locks the position of the workbook window.
+  /// </summary>
+  public bool LockWindows {
+    get => GetXmlNodeBool(_lockWindowsPath, false);
+    set => SetXmlNodeBool(_lockWindowsPath, value, false);
+  }
+
+  private const string _lockRevisionPath = "d:workbookProtection/@lockRevision";
+
+  /// <summary>
+  /// Lock the workbook for revision
+  /// </summary>
+  public bool LockRevision {
+    get => GetXmlNodeBool(_lockRevisionPath, false);
+    set => SetXmlNodeBool(_lockRevisionPath, value, false);
+  }
+}
diff --git a/AppsheetEpplus/ExcelRange.cs b/AppsheetEpplus/ExcelRange.cs
new file mode 100644
index 0000000..ada2477
--- /dev/null
+++ b/AppsheetEpplus/ExcelRange.cs
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		    Initial Release		        2009-10-01
+ * Jan Källman		    License changed GPL-->LGPL 2011-12-27
+ *******************************************************************************/
+
+using System;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// A range of cells.
+/// </summary>
+public class ExcelRange : ExcelRangeBase {
+  internal ExcelRange(ExcelWorksheet sheet, string address)
+      : base(sheet, address) {}
+
+  internal ExcelRange(ExcelWorksheet sheet, int fromRow, int fromCol, int toRow, int toCol)
+      : base(sheet) {
+    _fromRow = fromRow;
+    _fromCol = fromCol;
+    _toRow = toRow;
+    _toCol = toCol;
+  }
+
+  /// <summary>
+  /// Access the range using an address
+  /// </summary>
+  /// <param name="address">The address</param>
+  /// <returns>A range object</returns>
+  public ExcelRange this[string address] {
+    get {
+      if (_worksheet.Names.ContainsKey(address)) {
+        if (_worksheet.Names[address].IsName) {
+          return null;
+        }
+        Address = _worksheet.Names[address].Address;
+      } else {
+        Address = address;
+      }
+      return this;
+    }
+  }
+
+  /// <summary>
+  /// Access a single cell
+  /// </summary>
+  /// <param name="row">The row</param>
+  /// <param name="col">The column</param>
+  /// <returns>A range object</returns>
+  public ExcelRange this[int row, int col] {
+    get {
+      ValidateRowCol(row, col);
+
+      _fromCol = col;
+      _fromRow = row;
+      _toCol = col;
+      _toRow = row;
+      Address = GetAddress(_fromRow, _fromCol);
+      return this;
+    }
+  }
+
+  /// <summary>
+  /// Access a range of cells
+  /// </summary>
+  /// <param name="fromRow">Start row</param>
+  /// <param name="fromCol">Start column</param>
+  /// <param name="toRow">End Row</param>
+  /// <param name="toCol">End Column</param>
+  /// <returns></returns>
+  public ExcelRange this[int fromRow, int fromCol, int toRow, int toCol] {
+    get {
+      ValidateRowCol(fromRow, fromCol);
+      ValidateRowCol(toRow, toCol);
+
+      _fromCol = fromCol;
+      _fromRow = fromRow;
+      _toCol = toCol;
+      _toRow = toRow;
+      Address = GetAddress(_fromRow, _fromCol, _toRow, _toCol);
+      return this;
+    }
+  }
+
+  private static void ValidateRowCol(int row, int col) {
+    if (row < 1 || row > ExcelPackage.MaxRows) {
+      throw (new ArgumentException("Row out of range"));
+    }
+    if (col < 1 || col > ExcelPackage.MaxColumns) {
+      throw (new ArgumentException("Column out of range"));
+    }
+  }
+}
diff --git a/AppsheetEpplus/ExcelRangeBase.cs b/AppsheetEpplus/ExcelRangeBase.cs
new file mode 100644
index 0000000..f224f1a
--- /dev/null
+++ b/AppsheetEpplus/ExcelRangeBase.cs
@@ -0,0 +1,1530 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		    Initial Release		        2010-01-28
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ * Eyal Seagull		    Conditional Formatting      2012-04-03
+ *******************************************************************************/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Security;
+using System.Text;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// A range of cells
+/// </summary>
+public class ExcelRangeBase
+    : ExcelAddress,
+      IExcelCell,
+      IDisposable,
+      IEnumerable<ExcelRangeBase>,
+      IEnumerator<ExcelRangeBase> {
+  /// <summary>
+  /// Reference to the worksheet
+  /// </summary>
+  protected ExcelWorksheet _worksheet;
+  internal ExcelWorkbook _workbook;
+
+  private delegate void ChangePropHandler(SetValueHandler method, object value);
+
+  private delegate void SetValueHandler(object value, int row, int col);
+
+  private ChangePropHandler _changePropMethod;
+  private int _styleID;
+
+  private class CopiedCell {
+    internal int Row { get; set; }
+
+    internal int Column { get; set; }
+
+    internal object Value { get; set; }
+
+    internal string Type { get; set; }
+
+    internal object Formula { get; set; }
+
+    internal int? StyleID { get; set; }
+
+    internal Uri HyperLink { get; set; }
+
+    internal ExcelComment Comment { get; set; }
+
+    internal Byte Flag { get; set; }
+  }
+
+  //private class CopiedFlag
+  //{
+  //    internal int Row { get; set; }
+  //    internal int Column { get; set; }
+  //    internal Byte Flag { get; set; }
+  //}
+
+
+  internal ExcelRangeBase(ExcelWorksheet worksheet) {
+    _worksheet = worksheet;
+    _ws = _worksheet.Name;
+    _workbook = _worksheet.Workbook;
+    AddressChange += ExcelRangeBase_AddressChange;
+    SetDelegate();
+  }
+
+  private void ExcelRangeBase_AddressChange(object sender, EventArgs e) {
+    if (Table != null) {
+      SetRcFromTable(_workbook, null);
+    }
+    SetDelegate();
+  }
+
+  internal ExcelRangeBase(ExcelWorksheet worksheet, string address)
+      : base(worksheet == null ? "" : worksheet.Name, address) {
+    _worksheet = worksheet;
+    _workbook = worksheet.Workbook;
+    SetRcFromTable(_workbook, null);
+    if (string.IsNullOrEmpty(_ws)) {
+      _ws = _worksheet == null ? "" : _worksheet.Name;
+    }
+    AddressChange += ExcelRangeBase_AddressChange;
+    SetDelegate();
+  }
+
+  internal ExcelRangeBase(ExcelWorkbook wb, ExcelWorksheet xlWorksheet, string address, bool isName)
+      : base(xlWorksheet == null ? "" : xlWorksheet.Name, address, isName) {
+    SetRcFromTable(wb, null);
+    _worksheet = xlWorksheet;
+    _workbook = wb;
+    if (string.IsNullOrEmpty(_ws)) {
+      _ws = xlWorksheet?.Name;
+    }
+    AddressChange += ExcelRangeBase_AddressChange;
+    SetDelegate();
+  }
+
+  ~ExcelRangeBase() {
+    //this.AddressChange -= new EventHandler(ExcelRangeBase_AddressChange);
+  }
+
+  private void SetDelegate() {
+    if (_fromRow == -1) {
+      _changePropMethod = SetUnknown;
+    }
+    //Single cell
+    else if (_fromRow == _toRow && _fromCol == _toCol && Addresses == null) {
+      _changePropMethod = SetSingle;
+    }
+    //Range (ex A1:A2)
+    else if (Addresses == null) {
+      _changePropMethod = SetRange;
+    }
+    //Multi Range (ex A1:A2,C1:C2)
+    else {
+      _changePropMethod = SetMultiRange;
+    }
+  }
+
+  /// <summary>
+  /// We dont know the address yet. Set the delegate first time a property is set.
+  /// </summary>
+  /// <param name="valueMethod"></param>
+  /// <param name="value"></param>
+  private void SetUnknown(SetValueHandler valueMethod, object value) {
+    //Address is not set use, selected range
+    if (_fromRow == -1) {
+      SetToSelectedRange();
+    }
+    SetDelegate();
+    _changePropMethod(valueMethod, value);
+  }
+
+  /// <summary>
+  /// Set a single cell
+  /// </summary>
+  /// <param name="valueMethod"></param>
+  /// <param name="value"></param>
+  private void SetSingle(SetValueHandler valueMethod, object value) {
+    valueMethod(value, _fromRow, _fromCol);
+  }
+
+  /// <summary>
+  /// Set a range
+  /// </summary>
+  /// <param name="valueMethod"></param>
+  /// <param name="value"></param>
+  private void SetRange(SetValueHandler valueMethod, object value) {
+    SetValueAddress(this, valueMethod, value);
+  }
+
+  /// <summary>
+  /// Set a multirange (A1:A2,C1:C2)
+  /// </summary>
+  /// <param name="valueMethod"></param>
+  /// <param name="value"></param>
+  private void SetMultiRange(SetValueHandler valueMethod, object value) {
+    SetValueAddress(this, valueMethod, value);
+    foreach (var address in Addresses) {
+      SetValueAddress(address, valueMethod, value);
+    }
+  }
+
+  /// <summary>
+  /// Set the property for an address
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="valueMethod"></param>
+  /// <param name="value"></param>
+  private void SetValueAddress(ExcelAddress address, SetValueHandler valueMethod, object value) {
+    IsRangeValid("");
+    if (_fromRow == 1
+        && _fromCol == 1
+        && _toRow == ExcelPackage.MaxRows
+        && _toCol
+            == ExcelPackage.MaxColumns) //Full sheet (ex ws.Cells.Value=0). Set value for A1 only to avoid hanging
+    {
+      throw (new ArgumentException(
+              "Can't reference all cells. Please use the indexer to set the range"));
+    }
+    for (int col = address.Start.Column; col <= address.End.Column; col++) {
+      for (int row = address.Start.Row; row <= address.End.Row; row++) {
+        valueMethod(value, row, col);
+      }
+    }
+  }
+
+  private void Set_StyleID(object value, int row, int col) {
+    _worksheet._styles.SetValue(row, col, (int)value);
+  }
+
+  private void Set_Value(object value, int row, int col) {
+    //ExcelCell c = _worksheet.Cell(row, col);
+    var sfi = _worksheet._formulas.GetValue(row, col);
+    if (sfi is int) {
+      SplitFormulas(_worksheet.Cells[row, col]);
+    }
+    if (sfi != null) {
+      _worksheet._formulas.SetValue(row, col, string.Empty);
+    }
+    _worksheet._values.SetValue(row, col, value);
+  }
+
+  private void Set_Formula(object value, int row, int col) {
+    //ExcelCell c = _worksheet.Cell(row, col);
+    var f = _worksheet._formulas.GetValue(row, col);
+    if (f is int i && i >= 0) {
+      SplitFormulas(_worksheet.Cells[row, col]);
+    }
+
+    string formula = (value == null ? string.Empty : value.ToString());
+    if (formula == string.Empty) {
+      _worksheet._formulas.SetValue(row, col, string.Empty);
+    } else {
+      if (formula[0] == '=') {
+        value = formula.Substring(1, formula.Length - 1); // remove any starting equalsign.
+      }
+      _worksheet._formulas.SetValue(row, col, formula);
+      _worksheet._values.SetValue(row, col, null);
+    }
+  }
+
+  /// <summary>
+  /// Handles shared formulas
+  /// </summary>
+  /// <param name="value">The  formula</param>
+  /// <param name="address">The address of the formula</param>
+  /// <param name="isArray">If the forumla is an array formula.</param>
+  private void Set_SharedFormula(string value, ExcelAddress address, bool isArray) {
+    if (_fromRow == 1
+        && _fromCol == 1
+        && _toRow == ExcelPackage.MaxRows
+        && _toCol
+            == ExcelPackage.MaxColumns) //Full sheet (ex ws.Cells.Value=0). Set value for A1 only to avoid hanging
+    {
+      throw (new InvalidOperationException("Can't set a formula for the entire worksheet"));
+    }
+    if (address.Start.Row == address.End.Row
+        && address.Start.Column == address.End.Column
+        && !isArray) //is it really a shared formula? Arrayformulas can be one cell only
+    {
+      //Nope, single cell. Set the formula
+      Set_Formula(value, address.Start.Row, address.Start.Column);
+      return;
+    }
+    //RemoveFormuls(address);
+    CheckAndSplitSharedFormula(address);
+    ExcelWorksheet.Formulas f = new ExcelWorksheet.Formulas(SourceCodeTokenizer.Default);
+    f.Formula = value;
+    f.Index = _worksheet.GetMaxShareFunctionIndex(isArray);
+    f.Address = address.FirstAddress;
+    f.StartCol = address.Start.Column;
+    f.StartRow = address.Start.Row;
+    f.IsArray = isArray;
+
+    _worksheet._sharedFormulas.Add(f.Index, f);
+    //_worksheet.Cell(address.Start.Row, address.Start.Column).SharedFormulaID = f.Index;
+    //_worksheet.Cell(address.Start.Row, address.Start.Column).Formula = value;
+
+    for (int col = address.Start.Column; col <= address.End.Column; col++) {
+      for (int row = address.Start.Row; row <= address.End.Row; row++) {
+        //_worksheet.Cell(row, col).SharedFormulaID = f.Index;
+        _worksheet._formulas.SetValue(row, col, f.Index);
+        _worksheet._values.SetValue(row, col, null);
+      }
+    }
+  }
+
+  private void Set_HyperLink(object value, int row, int col) {
+    //_worksheet.Cell(row, col).Hyperlink = value as Uri;
+    if (value is Uri uri) {
+      _worksheet._hyperLinks.SetValue(row, col, uri);
+
+      if (uri is ExcelHyperLink link) {
+        _worksheet._values.SetValue(row, col, link.Display);
+      } else {
+        _worksheet._values.SetValue(row, col, uri.OriginalString);
+      }
+    } else {
+      _worksheet._hyperLinks.SetValue(row, col, null);
+      _worksheet._values.SetValue(row, col, null);
+    }
+  }
+
+  private void Set_IsArrayFormula(object value, int row, int col) {
+    _worksheet._flags.SetFlagValue(row, col, (bool)value, CellFlags.ArrayFormula);
+  }
+
+  private void Set_IsRichText(object value, int row, int col) {
+    //_worksheet.Cell(row, col).IsRichText = (bool)value;
+    _worksheet._flags.SetFlagValue(row, col, (bool)value, CellFlags.RichText);
+  }
+
+  private void Exists_Comment(object value, int row, int col) {
+    ulong cellId = GetCellId(_worksheet.SheetID, row, col);
+    if (_worksheet.Comments._comments.ContainsKey(cellId)) {
+      throw (new InvalidOperationException(
+              string.Format(
+                  "Cell {0} already contain a comment.",
+                  new ExcelCellAddress(row, col).Address)));
+    }
+  }
+
+  private void SetToSelectedRange() {
+    if (_worksheet.View.SelectedRange == "") {
+      Address = "A1";
+    } else {
+      Address = _worksheet.View.SelectedRange;
+    }
+  }
+
+  private void IsRangeValid(string type) {
+    if (_fromRow <= 0) {
+      if (_address == "") {
+        SetToSelectedRange();
+      } else {
+        if (type == "") {
+          throw (new InvalidOperationException(
+                  string.Format("Range is not valid for this operation: {0}", _address)));
+        }
+        throw (new InvalidOperationException(
+                string.Format("Range is not valid for {0} : {1}", type, _address)));
+      }
+    }
+  }
+
+  /// <summary>
+  /// The styleobject for the range.
+  /// </summary>
+  public ExcelStyle Style {
+    get {
+      IsRangeValid("styling");
+      int s = 0;
+      if (!_worksheet._styles.Exists(
+          _fromRow,
+          _fromCol,
+          ref s)) //Cell exists
+      {
+        if (!_worksheet._styles.Exists(
+            _fromRow,
+            0,
+            ref s)) //No, check Row style
+        {
+          var c = Worksheet.GetColumn(_fromCol);
+          if (c == null) {
+            s = 0;
+          } else {
+            s = c.StyleID;
+          }
+        }
+      }
+      return _worksheet.Workbook.Styles.GetStyleObject(s, _worksheet.PositionID, Address);
+    }
+  }
+
+  /// <summary>
+  /// The named style
+  /// </summary>
+  public string StyleName {
+    get {
+      IsRangeValid("styling");
+      int xfId;
+      if (_fromRow == 1 && _toRow == ExcelPackage.MaxRows) {
+        xfId = GetColumnStyle(_fromCol);
+      } else if (_fromCol == 1 && _toCol == ExcelPackage.MaxColumns) {
+        xfId = 0;
+        if (!_worksheet._styles.Exists(_fromRow, 0, ref xfId)) {
+          xfId = GetColumnStyle(_fromCol);
+        }
+      } else {
+        xfId = 0;
+        if (!_worksheet._styles.Exists(_fromRow, _fromCol, ref xfId)) {
+          if (!_worksheet._styles.Exists(_fromRow, 0, ref xfId)) {
+            xfId = GetColumnStyle(_fromCol);
+          }
+        }
+      }
+      int nsId;
+      if (xfId <= 0) {
+        nsId = Style.Styles.CellXfs[0].XfId;
+      } else {
+        nsId = Style.Styles.CellXfs[xfId].XfId;
+      }
+      foreach (var ns in Style.Styles.NamedStyles) {
+        if (ns.StyleXfId == nsId) {
+          return ns.Name;
+        }
+      }
+
+      return "";
+    }
+    set {
+      _styleID = _worksheet.Workbook.Styles.GetStyleIdFromName(value);
+      int col = _fromCol;
+      if (_fromRow == 1
+          && _toRow
+              == ExcelPackage.MaxRows) //Full column
+      {
+        ExcelColumn column;
+        //Get the startcolumn
+        //ulong colID = ExcelColumn.GetColumnID(_worksheet.SheetID, column);
+        var c = _worksheet.GetValue(0, _fromCol);
+        if (c == null) {
+          column = _worksheet.Column(_fromCol);
+          //if (_worksheet._values.PrevCell(ref row, ref col))
+          //{
+          //    var prevCol = (ExcelColumn)_worksheet._values.GetValue(row, col);
+          //    column = prevCol.Clone(_worksheet, column);
+          //    prevCol.ColumnMax = column - 1;
+          //}
+        } else {
+          column = (ExcelColumn)c;
+        }
+
+        column.StyleName = value;
+        column.StyleID = _styleID;
+
+        //var index = _worksheet._columns.IndexOf(colID);
+        var cols = new CellsStoreEnumerator<object>(_worksheet._values, 0, _fromCol + 1, 0, _toCol);
+        if (cols.Next()) {
+          col = _fromCol;
+          while (column.ColumnMin <= _toCol) {
+            if (column.ColumnMax > _toCol) {
+              var newCol = _worksheet.CopyColumn(column, _toCol + 1, column.ColumnMax);
+              column.ColumnMax = _toCol;
+            }
+
+            column._styleName = value;
+            column.StyleID = _styleID;
+
+            if (cols.Value == null) {
+              break;
+            }
+            var nextCol = (ExcelColumn)cols.Value;
+            if (column.ColumnMax < nextCol.ColumnMax - 1) {
+              column.ColumnMax = nextCol.ColumnMax - 1;
+            }
+            column = nextCol;
+            cols.Next();
+          }
+        }
+        if (column.ColumnMax < _toCol) {
+          column.ColumnMax = _toCol;
+        }
+        //if (column.ColumnMin == column)
+        //{
+        //    column.ColumnMax = _toCol;
+        //}
+        //else if (column._columnMax < _toCol)
+        //{
+        //    var newCol = _worksheet.Column(column._columnMax + 1) as ExcelColumn;
+        //    newCol._columnMax = _toCol;
+
+        //    newCol._styleID = _styleID;
+        //    newCol._styleName = value;
+        //}
+        if (_fromCol == 1
+            && _toCol
+                == ExcelPackage.MaxColumns) //FullRow
+        {
+          var rows = new CellsStoreEnumerator<object>(
+              _worksheet._values,
+              1,
+              0,
+              ExcelPackage.MaxRows,
+              0);
+          rows.Next();
+          while (rows.Value != null) {
+            _worksheet._styles.SetValue(rows.Row, 0, _styleID);
+            if (!rows.Next()) {
+              break;
+            }
+          }
+        }
+      } else if (_fromCol == 1
+          && _toCol
+              == ExcelPackage.MaxColumns) //FullRow
+      {
+        for (int r = _fromRow; r <= _toRow; r++) {
+          _worksheet.Row(r)._styleName = value;
+          _worksheet.Row(r).StyleID = _styleID;
+        }
+      }
+
+      if (!((_fromRow == 1 && _toRow == ExcelPackage.MaxRows)
+                  || (_fromCol == 1
+                          && _toCol
+                              == ExcelPackage.MaxColumns))) //Cell specific
+      {
+        for (int c = _fromCol; c <= _toCol; c++) {
+          for (int r = _fromRow; r <= _toRow; r++) {
+            _worksheet._styles.SetValue(r, c, _styleID);
+          }
+        }
+      } else //Only set name on created cells. (uncreated cells is set on full row or full column).
+      {
+        var cells = new CellsStoreEnumerator<object>(
+            _worksheet._values,
+            _fromRow,
+            _fromCol,
+            _toRow,
+            _toCol);
+        while (cells.Next()) {
+          _worksheet._styles.SetValue(cells.Row, cells.Column, _styleID);
+        }
+      }
+      //_changePropMethod(Set_StyleName, value);
+    }
+  }
+
+  private int GetColumnStyle(int col) {
+    object c = null;
+    if (_worksheet._values.Exists(0, col, ref c)) {
+      return (c as ExcelColumn).StyleID;
+    }
+    int row = 0;
+    if (_worksheet._values.PrevCell(ref row, ref col)) {
+      var column = _worksheet._values.GetValue(row, col) as ExcelColumn;
+      if (column.ColumnMax >= col) {
+        return _worksheet._styles.GetValue(row, col);
+      }
+    }
+    return 0;
+  }
+
+  /// <summary>
+  /// The style ID.
+  /// It is not recomended to use this one. Use Named styles as an alternative.
+  /// If you do, make sure that you use the Style.UpdateXml() method to update any new styles added to the workbook.
+  /// </summary>
+  public int StyleID {
+    get {
+      int s = 0;
+      if (!_worksheet._styles.Exists(_fromRow, _fromCol, ref s)) {
+        if (!_worksheet._styles.Exists(_fromRow, 0, ref s)) {
+          s = _worksheet._styles.GetValue(0, _fromCol);
+        }
+      }
+      return s;
+    }
+    set => _changePropMethod(Set_StyleID, value);
+  }
+
+  /// <summary>
+  /// Set the range to a specific value
+  /// </summary>
+  public object Value {
+    get {
+      if (IsName) {
+        if (_worksheet == null) {
+          return _workbook._names[_address].NameValue;
+        }
+        return _worksheet.Names[_address].NameValue;
+      }
+      if (_fromRow == _toRow && _fromCol == _toCol) {
+        return _worksheet.GetValue(_fromRow, _fromCol);
+      }
+      return GetValueArray();
+    }
+    set {
+      if (IsName) {
+        if (_worksheet == null) {
+          _workbook._names[_address].NameValue = value;
+        } else {
+          _worksheet.Names[_address].NameValue = value;
+        }
+      } else {
+        _changePropMethod(Set_Value, value);
+      }
+    }
+  }
+
+  private object GetValueArray() {
+    ExcelAddressBase addr;
+    if (_fromRow == 1
+        && _fromCol == 1
+        && _toRow == ExcelPackage.MaxRows
+        && _toCol == ExcelPackage.MaxColumns) {
+      addr = _worksheet.Dimension;
+      if (addr == null) {
+        return null;
+      }
+    } else {
+      addr = this;
+    }
+    object[,] v = new object[addr._toRow - addr._fromRow + 1, addr._toCol - addr._fromCol + 1];
+
+    for (int col = addr._fromCol; col <= addr._toCol; col++) {
+      for (int row = addr._fromRow; row <= addr._toRow; row++) {
+        if (_worksheet._values.Exists(row, col)) {
+          if (_worksheet._flags.GetFlagValue(row, col, CellFlags.RichText)) {
+            v[row - addr._fromRow, col - addr._fromCol] = GetRichText(row, col).Text;
+          } else {
+            v[row - addr._fromRow, col - addr._fromCol] = _worksheet._values.GetValue(row, col);
+          }
+        }
+      }
+    }
+    return v;
+  }
+
+  /// <summary>
+  /// Returns the formatted value.
+  /// </summary>
+  public string Text => GetFormattedText(false);
+
+  private string GetFormattedText(bool forWidthCalc) {
+    object v = Value;
+    if (v == null) {
+      return "";
+    }
+    var styles = Worksheet.Workbook.Styles;
+    var nfId = styles.CellXfs[StyleID].NumberFormatId;
+    ExcelNumberFormatXml.ExcelFormatTranslator nf = null;
+    for (int i = 0; i < styles.NumberFormats.Count; i++) {
+      if (nfId == styles.NumberFormats[i].NumFmtId) {
+        nf = styles.NumberFormats[i].FormatTranslator;
+        break;
+      }
+    }
+
+    string format,
+        textFormat;
+    if (forWidthCalc) {
+      format = nf.NetFormatForWidth;
+      textFormat = nf.NetTextFormatForWidth;
+    } else {
+      format = nf.NetFormat;
+      textFormat = nf.NetTextFormat;
+    }
+
+    return FormatValue(v, nf, format, textFormat);
+  }
+
+  internal static string FormatValue(
+      object v,
+      ExcelNumberFormatXml.ExcelFormatTranslator nf,
+      string format,
+      string textFormat) {
+    if (v is decimal || v.GetType().IsPrimitive) {
+      double d;
+      try {
+        d = Convert.ToDouble(v);
+      } catch {
+        return "";
+      }
+
+      if (nf.DataType == ExcelNumberFormatXml.eFormatType.Number) {
+        if (string.IsNullOrEmpty(nf.FractionFormat)) {
+          return d.ToString(format, nf.Culture);
+        }
+        return nf.FormatFraction(d);
+      }
+      if (nf.DataType == ExcelNumberFormatXml.eFormatType.DateTime) {
+        var date = DateTime.FromOADate(d);
+        return date.ToString(format, nf.Culture);
+      }
+    } else if (v is DateTime time) {
+      if (nf.DataType == ExcelNumberFormatXml.eFormatType.DateTime) {
+        return time.ToString(format, nf.Culture);
+      }
+      double d = time.ToOADate();
+      if (string.IsNullOrEmpty(nf.FractionFormat)) {
+        return d.ToString(format, nf.Culture);
+      }
+      return nf.FormatFraction(d);
+    } else if (v is TimeSpan span) {
+      if (nf.DataType == ExcelNumberFormatXml.eFormatType.DateTime) {
+        return new DateTime(span.Ticks).ToString(format, nf.Culture);
+      }
+      double d = (new DateTime(span.Ticks)).ToOADate();
+      if (string.IsNullOrEmpty(nf.FractionFormat)) {
+        return d.ToString(format, nf.Culture);
+      }
+      return nf.FormatFraction(d);
+    } else {
+      if (textFormat == "") {
+        return v.ToString();
+      }
+      return string.Format(textFormat, v);
+    }
+    return v.ToString();
+  }
+
+  /// <summary>
+  /// Gets or sets a formula for a range.
+  /// </summary>
+  public string Formula {
+    get {
+      if (IsName) {
+        if (_worksheet == null) {
+          return _workbook._names[_address].NameFormula;
+        }
+        return _worksheet.Names[_address].NameFormula;
+      }
+      return _worksheet.GetFormula(_fromRow, _fromCol);
+    }
+    set {
+      if (IsName) {
+        if (_worksheet == null) {
+          _workbook._names[_address].NameFormula = value;
+        } else {
+          _worksheet.Names[_address].NameFormula = value;
+        }
+      } else {
+        if (value == null || value.Trim() == "") {
+          //Set the cells to null
+          Value = null;
+        } else if (_fromRow == _toRow && _fromCol == _toCol) {
+          Set_Formula(value, _fromRow, _fromCol);
+        } else {
+          Set_SharedFormula(value, this, false);
+          if (Addresses != null) {
+            foreach (var address in Addresses) {
+              Set_SharedFormula(value, address, false);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  /// <summary>
+  /// Gets or Set a formula in R1C1 format.
+  /// </summary>
+  public string FormulaR1C1 {
+    get {
+      IsRangeValid("FormulaR1C1");
+      return _worksheet.GetFormulaR1C1(_fromRow, _fromCol);
+    }
+    set {
+      IsRangeValid("FormulaR1C1");
+      if (value.Length > 0 && value[0] == '=') {
+        value = value.Substring(1, value.Length - 1); // remove any starting equalsign.
+      }
+
+      if (value == null || value.Trim() == "") {
+        //Set the cells to null
+        _worksheet.Cells[TranslateFromR1C1(value, _fromRow, _fromCol)].Value = null;
+      } else if (Addresses == null) {
+        Set_SharedFormula(TranslateFromR1C1(value, _fromRow, _fromCol), this, false);
+      } else {
+        Set_SharedFormula(
+            TranslateFromR1C1(value, _fromRow, _fromCol),
+            new(WorkSheet, FirstAddress),
+            false);
+        foreach (var address in Addresses) {
+          Set_SharedFormula(
+              TranslateFromR1C1(value, address.Start.Row, address.Start.Column),
+              address,
+              false);
+        }
+      }
+    }
+  }
+
+  /// <summary>
+  /// Gets or Set a formula in R1C1 format.
+  ///
+  public string FormulaR1C1_V1 {
+    get {
+      IsRangeValid("FormulaR1C1");
+      return _worksheet.GetFormulaR1C1_V1(_fromRow, _fromCol);
+    }
+  }
+
+  public string ArrayFormulaAddress {
+    get {
+      IsRangeValid("FormulaR1C1");
+      return _worksheet.GetArrayFormulaAddress(_fromRow, _fromCol);
+    }
+  }
+
+  /// <summary>
+  /// Set the hyperlink property for a range of cells
+  /// </summary>
+  public Uri Hyperlink {
+    get {
+      IsRangeValid("formulaR1C1");
+      return _worksheet._hyperLinks.GetValue(_fromRow, _fromCol);
+    }
+    set => _changePropMethod(Set_HyperLink, value);
+  }
+
+  /// <summary>
+  /// If the cells in the range are merged.
+  /// </summary>
+  public bool Merge {
+    get {
+      IsRangeValid("merging");
+      for (int col = _fromCol; col <= _toCol; col++) {
+        for (int row = _fromRow; row <= _toRow; row++) {
+          if (_worksheet.MergedCells[row, col] == null) {
+            return false;
+          }
+          //if (!_worksheet._flags.GetFlagValue(row, col, CellFlags.Merged))
+          //{
+          //    return false;
+          //}
+        }
+      }
+      return true;
+    }
+    set {
+      IsRangeValid("merging");
+      //SetMerge(value, FirstAddress);
+      if (value) {
+        _worksheet.MergedCells.Add(new(FirstAddress), true);
+        if (Addresses != null) {
+          foreach (var address in Addresses) {
+            _worksheet.MergedCells.Add(address, true);
+            //SetMerge(value, address._address);
+          }
+        }
+      } else {
+        _worksheet.MergedCells.Clear(this);
+        if (Addresses != null) {
+          foreach (var address in Addresses) {
+            _worksheet.MergedCells.Clear(address);
+            ;
+          }
+        }
+      }
+    }
+  }
+
+  //private void SetMerge(bool value, string address)
+  //{
+  //    if (!value)
+  //    {
+  //        if (_worksheet.MergedCells.List.Contains(address))
+  //        {
+  //            SetCellMerge(false, address);
+  //            _worksheet.MergedCells.List.Remove(address);
+  //        }
+  //        else if (!CheckMergeDiff(false, address))
+  //        {
+  //            throw (new Exception("Range is not fully merged.Specify the exact range"));
+  //        }
+  //    }
+  //    else
+  //    {
+  //        if (CheckMergeDiff(false, address))
+  //        {
+  //            SetCellMerge(true, address);
+  //            _worksheet.MergedCells.List.Add(address);
+  //        }
+  //        else
+  //        {
+  //            if (!_worksheet.MergedCells.List.Contains(address))
+  //            {
+  //                throw (new Exception("Cells are already merged"));
+  //            }
+  //        }
+  //    }
+  //}
+  /// <summary>
+  /// Set an autofilter for the range
+  /// </summary>
+  public bool AutoFilter {
+    get {
+      IsRangeValid("autofilter");
+      ExcelAddressBase address = _worksheet.AutoFilterAddress;
+      if (address == null) {
+        return false;
+      }
+      if (_fromRow >= address.Start.Row
+          && _toRow <= address.End.Row
+          && _fromCol >= address.Start.Column
+          && _toCol <= address.End.Column) {
+        return true;
+      }
+      return false;
+    }
+    set {
+      IsRangeValid("autofilter");
+      _worksheet.AutoFilterAddress = this;
+      if (_worksheet.Names.ContainsKey("_xlnm._FilterDatabase")) {
+        _worksheet.Names.Remove("_xlnm._FilterDatabase");
+      }
+      var result = _worksheet.Names.Add("_xlnm._FilterDatabase", this);
+      result.IsNameHidden = true;
+    }
+  }
+
+  /// <summary>
+  /// If the value is in richtext format.
+  /// </summary>
+  public bool IsRichText {
+    get {
+      IsRangeValid("richtext");
+      return _worksheet._flags.GetFlagValue(_fromRow, _fromCol, CellFlags.RichText);
+    }
+    set => _changePropMethod(Set_IsRichText, value);
+  }
+
+  /// <summary>
+  /// Is the range a part of an Arrayformula
+  /// </summary>
+  public bool IsArrayFormula {
+    get {
+      IsRangeValid("arrayformulas");
+      return _worksheet._flags.GetFlagValue(_fromRow, _fromCol, CellFlags.ArrayFormula);
+    }
+    set => _changePropMethod(Set_IsArrayFormula, value);
+  }
+
+  private ExcelRichTextCollection _rtc;
+
+  /// <summary>
+  /// Cell value is richtext formatted.
+  /// Richtext-property only apply to the left-top cell of the range.
+  /// </summary>
+  public ExcelRichTextCollection RichText {
+    get {
+      IsRangeValid("richtext");
+      if (_rtc == null) {
+        _rtc = GetRichText(_fromRow, _fromCol);
+      }
+      return _rtc;
+    }
+  }
+
+  private ExcelRichTextCollection GetRichText(int row, int col) {
+    XmlDocument xml = new XmlDocument();
+    var v = _worksheet._values.GetValue(row, col);
+    var isRt = _worksheet._flags.GetFlagValue(row, col, CellFlags.RichText);
+    if (v != null) {
+      if (isRt) {
+        XmlHelper.LoadXmlSafe(
+            xml,
+            "<d:si xmlns:d=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" >"
+                + v
+                + "</d:si>",
+            Encoding.UTF8);
+      } else {
+        xml.LoadXml(
+            "<d:si xmlns:d=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" ><d:r><d:t>"
+                + SecurityElement.Escape(v.ToString())
+                + "</d:t></d:r></d:si>");
+      }
+    } else {
+      xml.LoadXml("<d:si xmlns:d=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" />");
+    }
+    var rtc = new ExcelRichTextCollection(
+        _worksheet.NameSpaceManager,
+        xml.SelectSingleNode("d:si", _worksheet.NameSpaceManager),
+        this);
+    return rtc;
+  }
+
+  /// <summary>
+  /// returns the comment object of the first cell in the range
+  /// </summary>
+  public ExcelComment Comment {
+    get {
+      IsRangeValid("comments");
+      ulong cellId = GetCellId(_worksheet.SheetID, _fromRow, _fromCol);
+      if (_worksheet.Comments._comments.ContainsKey(cellId)) {
+        return _worksheet._comments._comments[cellId] as ExcelComment;
+      }
+      return null;
+    }
+  }
+
+  /// <summary>
+  /// WorkSheet object
+  /// </summary>
+  public ExcelWorksheet Worksheet => _worksheet;
+
+  /// <summary>
+  /// Address including sheetname
+  /// </summary>
+  public string FullAddress {
+    get {
+      string fullAddress = GetFullAddress(_worksheet.Name, _address);
+      if (Addresses != null) {
+        foreach (var a in Addresses) {
+          fullAddress += "," + GetFullAddress(_worksheet.Name, a.Address);
+          ;
+        }
+      }
+      return fullAddress;
+    }
+  }
+
+  /// <summary>
+  /// Address including sheetname
+  /// </summary>
+  public string FullAddressAbsolute {
+    get {
+      string wbwsRef = string.IsNullOrEmpty(_wb) ? _ws : "[" + _wb.Replace("'", "''") + "]" + _ws;
+      string fullAddress = GetFullAddress(
+          wbwsRef,
+          GetAddress(_fromRow, _fromCol, _toRow, _toCol, true));
+      if (Addresses != null) {
+        foreach (var a in Addresses) {
+          fullAddress +=
+              ","
+                  + GetFullAddress(
+                      wbwsRef,
+                      GetAddress(a.Start.Row, a.Start.Column, a.End.Row, a.End.Column, true));
+          ;
+        }
+      }
+      return fullAddress;
+    }
+  }
+
+  /// <summary>
+  /// Address including sheetname
+  /// </summary>
+  internal string FullAddressAbsoluteNoFullRowCol {
+    get {
+      string wbwsRef = string.IsNullOrEmpty(_wb) ? _ws : "[" + _wb.Replace("'", "''") + "]" + _ws;
+      string fullAddress = GetFullAddress(
+          wbwsRef,
+          GetAddress(_fromRow, _fromCol, _toRow, _toCol, true),
+          false);
+      if (Addresses != null) {
+        foreach (var a in Addresses) {
+          fullAddress +=
+              ","
+                  + GetFullAddress(
+                      wbwsRef,
+                      GetAddress(a.Start.Row, a.Start.Column, a.End.Row, a.End.Column, true),
+                      false);
+          ;
+        }
+      }
+      return fullAddress;
+    }
+  }
+
+  /// <summary>
+  /// Set the value without altering the richtext property
+  /// </summary>
+  /// <param name="value">the value</param>
+  internal void SetValueRichText(object value) {
+    if (_fromRow == 1
+        && _fromCol == 1
+        && _toRow == ExcelPackage.MaxRows
+        && _toCol
+            == ExcelPackage.MaxColumns) //Full sheet (ex ws.Cells.Value=0). Set value for A1 only to avoid hanging
+    {
+      //_worksheet.Cell(1, 1).SetValueRichText(value);
+      SetValue(value, 1, 1);
+    } else {
+      //for (int col = _fromCol; col <= _toCol; col++)
+      //{
+      //    for (int row = _fromRow; row <= _toRow; row++)
+      //    {
+      //_worksheet.Cell(row, col).SetValueRichText(value);
+      SetValue(value, _fromRow, _fromCol);
+      //}
+      //}
+    }
+  }
+
+  private void SetValue(object value, int row, int col) {
+    _worksheet.SetValue(row, col, value);
+    // if (value is string) _worksheet._types.SetValue(row, col, "S"); else _worksheet._types.SetValue(row, col, "");
+    _worksheet._formulas.SetValue(row, col, "");
+  }
+
+  internal void SetSharedFormulaId(int id) {
+    for (int col = _fromCol; col <= _toCol; col++) {
+      for (int row = _fromRow; row <= _toRow; row++) {
+        _worksheet._formulas.SetValue(row, col, id);
+      }
+    }
+  }
+
+  private void CheckAndSplitSharedFormula(ExcelAddressBase address) {
+    for (int col = address._fromCol; col <= address._toCol; col++) {
+      for (int row = address._fromRow; row <= address._toRow; row++) {
+        var f = _worksheet._formulas.GetValue(row, col);
+        if (f is int i && i >= 0) {
+          SplitFormulas(address);
+          return;
+        }
+      }
+    }
+  }
+
+  private void SplitFormulas(ExcelAddressBase address) {
+    List<int> formulas = [];
+    for (int col = address._fromCol; col <= address._toCol; col++) {
+      for (int row = address._fromRow; row <= address._toRow; row++) {
+        var f = _worksheet._formulas.GetValue(row, col);
+        if (f is int id) {
+          if (id >= 0 && !formulas.Contains(id)) {
+            if (_worksheet._sharedFormulas[id].IsArray
+                && Collide(_worksheet.Cells[_worksheet._sharedFormulas[id].Address])
+                    == eAddressCollition.Partly) // If the formula is an array formula and its on the inside the overwriting range throw an exception
+            {
+              throw (new InvalidOperationException("Can not overwrite a part of an array-formula"));
+            }
+            formulas.Add(id);
+          }
+        }
+      }
+    }
+
+    foreach (int ix in formulas) {
+      SplitFormula(address, ix);
+    }
+
+    ////Clear any formula references inside the refered range
+    //_worksheet._formulas.Clear(address._fromRow, address._toRow, address._toRow - address._fromRow + 1, address._toCol - address.column + 1);
+  }
+
+  private void SplitFormula(ExcelAddressBase address, int ix) {
+    var f = _worksheet._sharedFormulas[ix];
+    var fRange = _worksheet.Cells[f.Address];
+    var collide = address.Collide(fRange);
+
+    //The formula is inside the currenct range, remove it
+    if (collide == eAddressCollition.Equal || collide == eAddressCollition.Inside) {
+      _worksheet._sharedFormulas.Remove(ix);
+      return;
+      //fRange.SetSharedFormulaID(int.MinValue);
+    }
+    var firstCellCollide = address.Collide(
+        new(fRange._fromRow, fRange._fromCol, fRange._fromRow, fRange._fromCol));
+    if (collide == eAddressCollition.Partly
+        && (firstCellCollide == eAddressCollition.Inside
+                || firstCellCollide
+                    == eAddressCollition.Equal)) //Do we need to split? Only if the functions first row is inside the new range.
+    {
+      //The formula partly collides with the current range
+      bool fIsSet = false;
+      string formulaR1C1 = fRange.FormulaR1C1;
+      //Top Range
+      if (fRange._fromRow < _fromRow) {
+        f.Address = GetAddress(fRange._fromRow, fRange._fromCol, _fromRow - 1, fRange._toCol);
+        fIsSet = true;
+      }
+      //Left Range
+      if (fRange._fromCol < address._fromCol) {
+        if (fIsSet) {
+          f = new(SourceCodeTokenizer.Default);
+          f.Index = _worksheet.GetMaxShareFunctionIndex(false);
+          f.StartCol = fRange._fromCol;
+          f.IsArray = false;
+          _worksheet._sharedFormulas.Add(f.Index, f);
+        } else {
+          fIsSet = true;
+        }
+        if (fRange._fromRow < address._fromRow) {
+          f.StartRow = address._fromRow;
+        } else {
+          f.StartRow = fRange._fromRow;
+        }
+        if (fRange._toRow < address._toRow) {
+          f.Address = GetAddress(f.StartRow, f.StartCol, fRange._toRow, address._fromCol - 1);
+        } else {
+          f.Address = GetAddress(f.StartRow, f.StartCol, address._toRow, address._fromCol - 1);
+        }
+        f.Formula = TranslateFromR1C1(formulaR1C1, f.StartRow, f.StartCol);
+        _worksheet.Cells[f.Address].SetSharedFormulaId(f.Index);
+      }
+      //Right Range
+      if (fRange._toCol > address._toCol) {
+        if (fIsSet) {
+          f = new(SourceCodeTokenizer.Default);
+          f.Index = _worksheet.GetMaxShareFunctionIndex(false);
+          f.IsArray = false;
+          _worksheet._sharedFormulas.Add(f.Index, f);
+        } else {
+          fIsSet = true;
+        }
+        f.StartCol = address._toCol + 1;
+        if (address._fromRow < fRange._fromRow) {
+          f.StartRow = fRange._fromRow;
+        } else {
+          f.StartRow = address._fromRow;
+        }
+
+        if (fRange._toRow < address._toRow) {
+          f.Address = GetAddress(f.StartRow, f.StartCol, fRange._toRow, fRange._toCol);
+        } else {
+          f.Address = GetAddress(f.StartRow, f.StartCol, address._toRow, fRange._toCol);
+        }
+        f.Formula = TranslateFromR1C1(formulaR1C1, f.StartRow, f.StartCol);
+        _worksheet.Cells[f.Address].SetSharedFormulaId(f.Index);
+      }
+      //Bottom Range
+      if (fRange._toRow > address._toRow) {
+        if (fIsSet) {
+          f = new(SourceCodeTokenizer.Default);
+          f.Index = _worksheet.GetMaxShareFunctionIndex(false);
+          f.IsArray = false;
+          _worksheet._sharedFormulas.Add(f.Index, f);
+        }
+
+        f.StartCol = fRange._fromCol;
+        f.StartRow = _toRow + 1;
+
+        f.Formula = TranslateFromR1C1(formulaR1C1, f.StartRow, f.StartCol);
+
+        f.Address = GetAddress(f.StartRow, f.StartCol, fRange._toRow, fRange._toCol);
+        _worksheet.Cells[f.Address].SetSharedFormulaId(f.Index);
+      }
+    }
+  }
+
+  private object ConvertData(ExcelTextFormat format, string v, int col, bool isText) {
+    if (isText && (format.DataTypes == null || format.DataTypes.Length < col)) {
+      return v;
+    }
+
+    double d;
+    DateTime dt;
+    if (format.DataTypes == null
+        || format.DataTypes.Length <= col
+        || format.DataTypes[col] == eDataTypes.Unknown) {
+      string v2 = v.EndsWith("%") ? v.Substring(0, v.Length - 1) : v;
+      if (double.TryParse(v2, NumberStyles.Any, format.Culture, out d)) {
+        if (v2 == v) {
+          return d;
+        }
+        return d / 100;
+      }
+      if (DateTime.TryParse(v, format.Culture, DateTimeStyles.None, out dt)) {
+        return dt;
+      }
+      return v;
+    }
+    switch (format.DataTypes[col]) {
+      case eDataTypes.Number:
+        if (double.TryParse(v, NumberStyles.Any, format.Culture, out d)) {
+          return d;
+        }
+        return v;
+      case eDataTypes.DateTime:
+        if (DateTime.TryParse(v, format.Culture, DateTimeStyles.None, out dt)) {
+          return dt;
+        }
+        return v;
+      case eDataTypes.Percent:
+        string v2 = v.EndsWith("%") ? v.Substring(0, v.Length - 1) : v;
+        if (double.TryParse(v2, NumberStyles.Any, format.Culture, out d)) {
+          return d / 100;
+        }
+        return v;
+
+      default:
+        return v;
+    }
+  }
+
+  /// <summary>
+  /// Conditional Formatting for this range.
+  /// </summary>
+  public IRangeConditionalFormatting ConditionalFormatting =>
+    new RangeConditionalFormatting(_worksheet, new(Address));
+
+  /// <summary>
+  /// Data validation for this range.
+  /// </summary>
+  public IRangeDataValidation DataValidation => new RangeDataValidation(_worksheet, Address);
+
+  /// <summary>
+  /// Get the strongly typed value of the cell.
+  /// </summary>
+  /// <typeparam name="T">The type</typeparam>
+  /// <returns>The value. If the value can't be converted to the specified type, the default value will be returned</returns>
+  public T GetValue<T>() {
+    return _worksheet.GetTypedValue<T>(Value);
+  }
+
+  /// <summary>
+  /// Get a range with an offset from the top left cell.
+  /// The new range has the same dimensions as the current range
+  /// </summary>
+  /// <param name="rowOffset">Row Offset</param>
+  /// <param name="columnOffset">Column Offset</param>
+  /// <returns></returns>
+  public ExcelRangeBase Offset(int rowOffset, int columnOffset) {
+    if (_fromRow + rowOffset < 1
+        || _fromCol + columnOffset < 1
+        || _fromRow + rowOffset > ExcelPackage.MaxRows
+        || _fromCol + columnOffset > ExcelPackage.MaxColumns) {
+      throw (new ArgumentOutOfRangeException("Offset value out of range"));
+    }
+    string address = GetAddress(
+        _fromRow + rowOffset,
+        _fromCol + columnOffset,
+        _toRow + rowOffset,
+        _toCol + columnOffset);
+    return new(_worksheet, address);
+  }
+
+  /// <summary>
+  /// Get a range with an offset from the top left cell.
+  /// </summary>
+  /// <param name="rowOffset">Row Offset</param>
+  /// <param name="columnOffset">Column Offset</param>
+  /// <param name="numberOfRows">Number of rows. Minimum 1</param>
+  /// <param name="numberOfColumns">Number of colums. Minimum 1</param>
+  /// <returns></returns>
+  public ExcelRangeBase Offset(
+      int rowOffset,
+      int columnOffset,
+      int numberOfRows,
+      int numberOfColumns) {
+    if (numberOfRows < 1 || numberOfColumns < 1) {
+      throw (new("Number of rows/columns must be greater than 0"));
+    }
+    numberOfRows--;
+    numberOfColumns--;
+    if (_fromRow + rowOffset < 1
+        || _fromCol + columnOffset < 1
+        || _fromRow + rowOffset > ExcelPackage.MaxRows
+        || _fromCol + columnOffset > ExcelPackage.MaxColumns
+        || _fromRow + rowOffset + numberOfRows < 1
+        || _fromCol + columnOffset + numberOfColumns < 1
+        || _fromRow + rowOffset + numberOfRows > ExcelPackage.MaxRows
+        || _fromCol + columnOffset + numberOfColumns > ExcelPackage.MaxColumns) {
+      throw (new ArgumentOutOfRangeException("Offset value out of range"));
+    }
+    string address = GetAddress(
+        _fromRow + rowOffset,
+        _fromCol + columnOffset,
+        _fromRow + rowOffset + numberOfRows,
+        _fromCol + columnOffset + numberOfColumns);
+    return new(_worksheet, address);
+  }
+
+  /// <summary>
+  /// Clear all cells
+  /// </summary>
+  public void Clear() {
+    Delete(this, false);
+  }
+
+  /// <summary>
+  /// Creates an array-formula.
+  /// </summary>
+  /// <param name="arrayFormula">The formula</param>
+  public void CreateArrayFormula(string arrayFormula) {
+    if (Addresses != null) {
+      throw (new("An Arrayformula can not have more than one address"));
+    }
+    Set_SharedFormula(arrayFormula, this, true);
+  }
+
+  //private void Clear(ExcelAddressBase Range)
+  //{
+  //    Clear(Range, true);
+  //}
+  internal void Delete(ExcelAddressBase range, bool shift) {
+    //DeleteCheckMergedCells(Range);
+    _worksheet.MergedCells.Clear(range);
+    //First find the start cell
+    int fromRow,
+        fromCol;
+    var d = Worksheet.Dimension;
+    if (d != null
+        && range._fromRow <= d._fromRow
+        && range._toRow
+            >= d._toRow) //EntireRow?
+    {
+      fromRow = 0;
+    } else {
+      fromRow = range._fromRow;
+    }
+    if (d != null
+        && range._fromCol <= d._fromCol
+        && range._toCol
+            >= d._toCol) //EntireRow?
+    {
+      fromCol = 0;
+    } else {
+      fromCol = range._fromCol;
+    }
+
+    var rows = range._toRow - fromRow + 1;
+    var cols = range._toCol - fromCol + 1;
+
+    _worksheet._values.Delete(fromRow, fromCol, rows, cols, shift);
+    _worksheet._types.Delete(fromRow, fromCol, rows, cols, shift);
+    _worksheet._styles.Delete(fromRow, fromCol, rows, cols, shift);
+    _worksheet._formulas.Delete(fromRow, fromCol, rows, cols, shift);
+    _worksheet._hyperLinks.Delete(fromRow, fromCol, rows, cols, shift);
+    _worksheet._flags.Delete(fromRow, fromCol, rows, cols, shift);
+    _worksheet._commentsStore.Delete(fromRow, fromCol, rows, cols, shift);
+
+    //if(shift)
+    //{
+    //    _worksheet.AdjustFormulasRow(fromRow, rows);
+    //}
+
+    //Clear multi addresses as well
+    if (Addresses != null) {
+      foreach (var sub in Addresses) {
+        Delete(sub, shift);
+      }
+    }
+  }
+
+  public void Dispose() {}
+
+  //int _index;
+  //ulong _toCellId;
+  //int _enumAddressIx;
+  private CellsStoreEnumerator<object> cellEnum;
+
+  public IEnumerator<ExcelRangeBase> GetEnumerator() {
+    Reset();
+    return this;
+  }
+
+  IEnumerator IEnumerable.GetEnumerator() {
+    Reset();
+    return this;
+  }
+
+  /// <summary>
+  /// The current range when enumerating
+  /// </summary>
+  public ExcelRangeBase Current => new(_worksheet, GetAddress(cellEnum.Row, cellEnum.Column));
+
+  /// <summary>
+  /// The current range when enumerating
+  /// </summary>
+  object IEnumerator.Current =>
+    new ExcelRangeBase(_worksheet, GetAddress(cellEnum.Row, cellEnum.Column));
+
+  private int _enumAddressIx = -1;
+
+  public bool MoveNext() {
+    if (cellEnum.Next()) {
+      return true;
+    }
+    if (_addresses != null) {
+      _enumAddressIx++;
+      if (_enumAddressIx < _addresses.Count) {
+        cellEnum = new(
+            _worksheet._values,
+            _addresses[_enumAddressIx]._fromRow,
+            _addresses[_enumAddressIx]._fromCol,
+            _addresses[_enumAddressIx]._toRow,
+            _addresses[_enumAddressIx]._toCol);
+        return MoveNext();
+      }
+      return false;
+    }
+    return false;
+  }
+
+  public void Reset() {
+    _enumAddressIx = -1;
+    cellEnum = new(_worksheet._values, _fromRow, _fromCol, _toRow, _toCol);
+  }
+
+  //private void GetNextIndexEnum(int fromRow, int fromCol, int toRow, int toCol)
+  //{
+  //    if (_index >= _worksheet._cells.Count) return;
+  //    ExcelCell cell = _worksheet._cells[_index] as ExcelCell;
+  //    while (cell.Column > toCol || cell.Column < fromCol)
+  //    {
+  //        if (cell.Column < fromCol)
+  //        {
+  //            _index = _worksheet._cells.IndexOf(ExcelAddress.GetCellID(_worksheet.SheetID, cell.Row, fromCol));
+  //        }
+  //        else
+  //        {
+  //            _index = _worksheet._cells.IndexOf(ExcelAddress.GetCellID(_worksheet.SheetID, cell.Row + 1, fromCol));
+  //        }
+
+  //        if (_index < 0)
+  //        {
+  //            _index = ~_index;
+  //        }
+  //        if (_index >= _worksheet._cells.Count || _worksheet._cells[_index].RangeID > _toCellId)
+  //        {
+  //            break;
+  //        }
+  //        cell = _worksheet._cells[_index] as ExcelCell;
+  //    }
+  //}
+
+  //private void GetStartIndexEnum(int fromRow, int fromCol, int toRow, int toCol)
+  //{
+  //    _index = _worksheet._cells.IndexOf(ExcelCellBase.GetCellID(_worksheet.SheetID, fromRow, fromCol));
+  //    _toCellId = ExcelCellBase.GetCellID(_worksheet.SheetID, toRow, toCol);
+  //    if (_index < 0)
+  //    {
+  //        _index = ~_index;
+  //    }
+  //    _index--;
+  //}
+}
diff --git a/AppsheetEpplus/ExcelRangeCopyOptionFlags.cs b/AppsheetEpplus/ExcelRangeCopyOptionFlags.cs
new file mode 100644
index 0000000..25f478c
--- /dev/null
+++ b/AppsheetEpplus/ExcelRangeCopyOptionFlags.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Flag enum, specify all flags that you want to exclude from the copy.
+/// </summary>
+[Flags]
+public enum ExcelRangeCopyOptionFlags {
+  /// <summary>
+  /// Exclude formulas from being copied
+  /// </summary>
+  ExcludeFormulas = 0x1,
+}
diff --git a/AppsheetEpplus/ExcelRow.cs b/AppsheetEpplus/ExcelRow.cs
new file mode 100644
index 0000000..d8069b0
--- /dev/null
+++ b/AppsheetEpplus/ExcelRow.cs
@@ -0,0 +1,257 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan K�llman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan K�llman		    Initial Release		        2009-10-01
+ * Jan K�llman		    License changed GPL-->LGPL 2011-12-27
+ *******************************************************************************/
+
+using System;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+internal class RowInternal {
+  internal double Height = -1;
+  internal bool Hidden;
+  internal bool Collapsed;
+  internal short OutlineLevel;
+  internal bool PageBreak;
+  internal bool Phonetic;
+  internal bool CustomHeight;
+}
+
+/// <summary>
+/// Represents an individual row in the spreadsheet.
+/// </summary>
+public class ExcelRow : IRangeId {
+  private readonly ExcelWorksheet _worksheet;
+  private readonly XmlElement _rowElement = null;
+
+  /// <summary>
+  /// Internal RowID.
+  /// </summary>
+  [Obsolete]
+  public ulong RowID => GetRowId(_worksheet.SheetID, Row);
+
+  /// <summary>
+  /// Creates a new instance of the ExcelRow class.
+  /// For internal use only!
+  /// </summary>
+  /// <param name="worksheet">The parent worksheet</param>
+  /// <param name="row">The row number</param>
+  internal ExcelRow(ExcelWorksheet worksheet, int row) {
+    _worksheet = worksheet;
+    Row = row;
+  }
+
+  /// <summary>
+  /// Provides access to the node representing the row.
+  /// </summary>
+  internal XmlNode Node => (_rowElement);
+
+  /// <summary>
+  /// Allows the row to be hidden in the worksheet
+  /// </summary>
+  public bool Hidden {
+    get {
+      var r = (RowInternal)_worksheet._values.GetValue(Row, 0);
+      if (r == null) {
+        return false;
+      }
+      return r.Hidden;
+    }
+    set {
+      var r = GetRowInternal();
+      r.Hidden = value;
+    }
+  }
+
+  /// <summary>
+  /// Sets the height of the row
+  /// </summary>
+  public double Height {
+    get {
+      var r = (RowInternal)_worksheet._values.GetValue(Row, 0);
+      if (r == null || r.Height < 0) {
+        return _worksheet.DefaultRowHeight;
+      }
+      return r.Height;
+    }
+    set {
+      var r = GetRowInternal();
+      r.Height = value;
+
+      if (r.Hidden && value != 0) {
+        Hidden = false;
+      }
+      r.CustomHeight = (value != _worksheet.DefaultRowHeight);
+    }
+  }
+
+  /// <summary>
+  /// Set to true if You don't want the row to Autosize
+  /// </summary>
+  public bool CustomHeight {
+    get {
+      var r = (RowInternal)_worksheet._values.GetValue(Row, 0);
+      if (r == null) {
+        return false;
+      }
+      return r.CustomHeight;
+    }
+    set {
+      var r = GetRowInternal();
+      r.CustomHeight = value;
+    }
+  }
+
+  internal string _styleName = "";
+
+  /// <summary>
+  /// Sets the style for the entire column using a style name.
+  /// </summary>
+  public string StyleName {
+    get => _styleName;
+    set {
+      StyleID = _worksheet.Workbook.Styles.GetStyleIdFromName(value);
+      _styleName = value;
+    }
+  }
+
+  /// <summary>
+  /// Sets the style for the entire row using the style ID.
+  /// </summary>
+  public int StyleID {
+    get => _worksheet._styles.GetValue(Row, 0);
+    set => _worksheet._styles.SetValue(Row, 0, value);
+  }
+
+  /// <summary>
+  /// Rownumber
+  /// </summary>
+  public int Row { get; set; }
+
+  /// <summary>
+  /// If outline level is set this tells that the row is collapsed
+  /// </summary>
+  public bool Collapsed {
+    get {
+      var r = (RowInternal)_worksheet._values.GetValue(Row, 0);
+      if (r == null) {
+        return false;
+      }
+      return r.Collapsed;
+    }
+    set {
+      var r = GetRowInternal();
+      r.Collapsed = value;
+    }
+  }
+
+  /// <summary>
+  /// Outline level.
+  /// </summary>
+  public int OutlineLevel {
+    get {
+      var r = (RowInternal)_worksheet._values.GetValue(Row, 0);
+      if (r == null) {
+        return 0;
+      }
+      return r.OutlineLevel;
+    }
+    set {
+      var r = GetRowInternal();
+      r.OutlineLevel = (short)value;
+    }
+  }
+
+  private RowInternal GetRowInternal() {
+    var r = (RowInternal)_worksheet._values.GetValue(Row, 0);
+    if (r == null) {
+      r = new();
+      _worksheet._values.SetValue(Row, 0, r);
+    }
+    return r;
+  }
+
+  /// <summary>
+  /// Show phonetic Information
+  /// </summary>
+  public bool Phonetic {
+    get {
+      var r = (RowInternal)_worksheet._values.GetValue(Row, 0);
+      if (r == null) {
+        return false;
+      }
+      return r.Phonetic;
+    }
+    set {
+      var r = GetRowInternal();
+      r.Phonetic = value;
+    }
+  }
+
+  /// <summary>
+  /// The Style applied to the whole row. Only effekt cells with no individual style set.
+  /// Use ExcelRange object if you want to set specific styles.
+  /// </summary>
+  public ExcelStyle Style =>
+    _worksheet.Workbook.Styles.GetStyleObject(StyleID, _worksheet.PositionID, Row + ":" + Row);
+
+  /// <summary>
+  /// Adds a manual page break after the row.
+  /// </summary>
+  public bool PageBreak {
+    get {
+      var r = (RowInternal)_worksheet._values.GetValue(Row, 0);
+      if (r == null) {
+        return false;
+      }
+      return r.PageBreak;
+    }
+    set {
+      var r = GetRowInternal();
+      r.PageBreak = value;
+    }
+  }
+
+  public bool Merged {
+    get => _worksheet.MergedCells[Row, 0] != null;
+    set => _worksheet.MergedCells.Add(new(Row, 1, Row, ExcelPackage.MaxColumns), true);
+  }
+
+  internal static ulong GetRowId(int sheetId, int row) {
+    return ((ulong)sheetId) + (((ulong)row) << 29);
+  }
+
+  [Obsolete]
+  ulong IRangeId.RangeID {
+    get => RowID;
+    set => Row = ((int)(value >> 29));
+  }
+}
diff --git a/AppsheetEpplus/ExcelSheetProtection.cs b/AppsheetEpplus/ExcelSheetProtection.cs
new file mode 100644
index 0000000..a538666
--- /dev/null
+++ b/AppsheetEpplus/ExcelSheetProtection.cs
@@ -0,0 +1,217 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		    Initial Release		        2010-03-14
+ * Jan Källman		    License changed GPL-->LGPL 2011-12-27
+ *******************************************************************************/
+
+using System.Collections.Immutable;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Sheet protection
+///<seealso cref="ExcelEncryption"/>
+///<seealso cref="ExcelProtection"/>
+/// </summary>
+public sealed class ExcelSheetProtection : XmlHelper {
+  protected override ImmutableArray<string> SchemaNodeOrder =>
+    ExcelWorksheet.WorksheetSchemaNodeOrder;
+
+  internal ExcelSheetProtection(XmlNamespaceManager nsm, XmlNode topNode)
+      : base(nsm, topNode) {}
+
+  private const string _isProtectedPath = "d:sheetProtection/@sheet";
+
+  /// <summary>
+  /// If the worksheet is protected.
+  /// </summary>
+  public bool IsProtected {
+    get => GetXmlNodeBool(_isProtectedPath, false);
+    set {
+      SetXmlNodeBool(_isProtectedPath, value, false);
+      if (value) {
+        AllowEditObject = true;
+        AllowEditScenarios = true;
+      } else {
+        DeleteAllNode(_isProtectedPath); //delete the whole sheetprotection node
+      }
+    }
+  }
+
+  private const string _allowSelectLockedCellsPath = "d:sheetProtection/@selectLockedCells";
+
+  /// <summary>
+  /// Allow users to select locked cells
+  /// </summary>
+  public bool AllowSelectLockedCells {
+    get => !GetXmlNodeBool(_allowSelectLockedCellsPath, false);
+    set => SetXmlNodeBool(_allowSelectLockedCellsPath, !value, false);
+  }
+
+  private const string _allowSelectUnlockedCellsPath = "d:sheetProtection/@selectUnlockedCells";
+
+  /// <summary>
+  /// Allow users to select unlocked cells
+  /// </summary>
+  public bool AllowSelectUnlockedCells {
+    get => !GetXmlNodeBool(_allowSelectUnlockedCellsPath, false);
+    set => SetXmlNodeBool(_allowSelectUnlockedCellsPath, !value, false);
+  }
+
+  private const string _allowObjectPath = "d:sheetProtection/@objects";
+
+  /// <summary>
+  /// Allow users to edit objects
+  /// </summary>
+  public bool AllowEditObject {
+    get => !GetXmlNodeBool(_allowObjectPath, false);
+    set => SetXmlNodeBool(_allowObjectPath, !value, false);
+  }
+
+  private const string _allowScenariosPath = "d:sheetProtection/@scenarios";
+
+  /// <summary>
+  /// Allow users to edit senarios
+  /// </summary>
+  public bool AllowEditScenarios {
+    get => !GetXmlNodeBool(_allowScenariosPath, false);
+    set => SetXmlNodeBool(_allowScenariosPath, !value, false);
+  }
+
+  private const string _allowFormatCellsPath = "d:sheetProtection/@formatCells";
+
+  /// <summary>
+  /// Allow users to format cells
+  /// </summary>
+  public bool AllowFormatCells {
+    get => !GetXmlNodeBool(_allowFormatCellsPath, true);
+    set => SetXmlNodeBool(_allowFormatCellsPath, !value, true);
+  }
+
+  private const string _allowFormatColumnsPath = "d:sheetProtection/@formatColumns";
+
+  /// <summary>
+  /// Allow users to Format columns
+  /// </summary>
+  public bool AllowFormatColumns {
+    get => !GetXmlNodeBool(_allowFormatColumnsPath, true);
+    set => SetXmlNodeBool(_allowFormatColumnsPath, !value, true);
+  }
+
+  private const string _allowFormatRowsPath = "d:sheetProtection/@formatRows";
+
+  /// <summary>
+  /// Allow users to Format rows
+  /// </summary>
+  public bool AllowFormatRows {
+    get => !GetXmlNodeBool(_allowFormatRowsPath, true);
+    set => SetXmlNodeBool(_allowFormatRowsPath, !value, true);
+  }
+
+  private const string _allowInsertColumnsPath = "d:sheetProtection/@insertColumns";
+
+  /// <summary>
+  /// Allow users to insert columns
+  /// </summary>
+  public bool AllowInsertColumns {
+    get => !GetXmlNodeBool(_allowInsertColumnsPath, true);
+    set => SetXmlNodeBool(_allowInsertColumnsPath, !value, true);
+  }
+
+  private const string _allowInsertRowsPath = "d:sheetProtection/@insertRows";
+
+  /// <summary>
+  /// Allow users to Format rows
+  /// </summary>
+  public bool AllowInsertRows {
+    get => !GetXmlNodeBool(_allowInsertRowsPath, true);
+    set => SetXmlNodeBool(_allowInsertRowsPath, !value, true);
+  }
+
+  private const string _allowInsertHyperlinksPath = "d:sheetProtection/@insertHyperlinks";
+
+  /// <summary>
+  /// Allow users to insert hyperlinks
+  /// </summary>
+  public bool AllowInsertHyperlinks {
+    get => !GetXmlNodeBool(_allowInsertHyperlinksPath, true);
+    set => SetXmlNodeBool(_allowInsertHyperlinksPath, !value, true);
+  }
+
+  private const string _allowDeleteColumns = "d:sheetProtection/@deleteColumns";
+
+  /// <summary>
+  /// Allow users to delete columns
+  /// </summary>
+  public bool AllowDeleteColumns {
+    get => !GetXmlNodeBool(_allowDeleteColumns, true);
+    set => SetXmlNodeBool(_allowDeleteColumns, !value, true);
+  }
+
+  private const string _allowDeleteRowsPath = "d:sheetProtection/@deleteRows";
+
+  /// <summary>
+  /// Allow users to delete rows
+  /// </summary>
+  public bool AllowDeleteRows {
+    get => !GetXmlNodeBool(_allowDeleteRowsPath, true);
+    set => SetXmlNodeBool(_allowDeleteRowsPath, !value, true);
+  }
+
+  private const string _allowSortPath = "d:sheetProtection/@sort";
+
+  /// <summary>
+  /// Allow users to sort a range
+  /// </summary>
+  public bool AllowSort {
+    get => !GetXmlNodeBool(_allowSortPath, true);
+    set => SetXmlNodeBool(_allowSortPath, !value, true);
+  }
+
+  private const string _allowAutoFilterPath = "d:sheetProtection/@autoFilter";
+
+  /// <summary>
+  /// Allow users to use autofilters
+  /// </summary>
+  public bool AllowAutoFilter {
+    get => !GetXmlNodeBool(_allowAutoFilterPath, true);
+    set => SetXmlNodeBool(_allowAutoFilterPath, !value, true);
+  }
+
+  private const string _allowPivotTablesPath = "d:sheetProtection/@pivotTables";
+
+  /// <summary>
+  /// Allow users to use pivottables
+  /// </summary>
+  public bool AllowPivotTables {
+    get => !GetXmlNodeBool(_allowPivotTablesPath, true);
+    set => SetXmlNodeBool(_allowPivotTablesPath, !value, true);
+  }
+}
diff --git a/AppsheetEpplus/ExcelStyleCollection.cs b/AppsheetEpplus/ExcelStyleCollection.cs
new file mode 100644
index 0000000..788e6c0
--- /dev/null
+++ b/AppsheetEpplus/ExcelStyleCollection.cs
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		    Initial Release		        2009-10-01
+ * Jan Källman		    License changed GPL-->LGPL 2011-12-27
+ *******************************************************************************/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Base collection class for styles.
+/// </summary>
+/// <typeparam name="T">The style type</typeparam>
+public class ExcelStyleCollection<T> : IEnumerable<T> {
+  public ExcelStyleCollection() {
+    _setNextIdManual = false;
+  }
+
+  private readonly bool _setNextIdManual;
+
+  public ExcelStyleCollection(bool setNextIdManual) {
+    _setNextIdManual = setNextIdManual;
+  }
+
+  public XmlNode TopNode { get; set; }
+
+  internal List<T> _list = new();
+  private readonly Dictionary<string, int> _dic = new(StringComparer.InvariantCultureIgnoreCase);
+  internal int NextId;
+
+  public IEnumerator<T> GetEnumerator() {
+    return _list.GetEnumerator();
+  }
+
+  IEnumerator IEnumerable.GetEnumerator() {
+    return _list.GetEnumerator();
+  }
+
+  public T this[int positionId] => _list[positionId];
+
+  public int Count => _list.Count;
+
+  //internal int Add(T item)
+  //{
+  //    _list.Add(item);
+  //    if (_setNextIdManual) NextId++;
+  //    return _list.Count-1;
+  //}
+  internal int Add(string key, T item) {
+    _list.Add(item);
+    if (!_dic.ContainsKey(key.ToLower(CultureInfo.InvariantCulture))) {
+      _dic.Add(key.ToLower(CultureInfo.InvariantCulture), _list.Count - 1);
+    }
+    if (_setNextIdManual) {
+      NextId++;
+    }
+    return _list.Count - 1;
+  }
+
+  /// <summary>
+  /// Finds the key
+  /// </summary>
+  /// <param name="key">the key to be found</param>
+  /// <param name="obj">The found object.</param>
+  /// <returns>True if found</returns>
+  internal bool FindById(string key, ref T obj) {
+    if (_dic.ContainsKey(key)) {
+      obj = _list[_dic[key.ToLower(CultureInfo.InvariantCulture)]];
+      return true;
+    }
+    return false;
+  }
+
+  /// <summary>
+  /// Find Index
+  /// </summary>
+  /// <param name="key"></param>
+  /// <returns></returns>
+  internal int FindIndexById(string key) {
+    if (_dic.ContainsKey(key)) {
+      return _dic[key];
+    }
+    return int.MinValue;
+  }
+
+  internal bool ExistsKey(string key) {
+    return _dic.ContainsKey(key);
+  }
+
+  internal void Sort(Comparison<T> c) {
+    _list.Sort(c);
+  }
+}
diff --git a/AppsheetEpplus/ExcelStyles.cs b/AppsheetEpplus/ExcelStyles.cs
new file mode 100644
index 0000000..dc169ed
--- /dev/null
+++ b/AppsheetEpplus/ExcelStyles.cs
@@ -0,0 +1,870 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan K�llman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan K�llman		    Initial Release		        2009-10-01
+ * Jan K�llman		    License changed GPL-->LGPL 2011-12-27
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Containts all shared cell styles for a workbook
+/// </summary>
+public sealed class ExcelStyles : XmlHelper {
+  private const string _numberFormatsPath = "d:styleSheet/d:numFmts";
+  private const string _fontsPath = "d:styleSheet/d:fonts";
+  private const string _fillsPath = "d:styleSheet/d:fills";
+  private const string _bordersPath = "d:styleSheet/d:borders";
+  private const string _cellStyleXfsPath = "d:styleSheet/d:cellStyleXfs";
+  private const string _cellXfsPath = "d:styleSheet/d:cellXfs";
+  private const string _cellStylesPath = "d:styleSheet/d:cellStyles";
+  private const string _dxfsPath = "d:styleSheet/d:dxfs";
+
+  //internal Dictionary<int, ExcelXfs> Styles = new Dictionary<int, ExcelXfs>();
+  private readonly XmlDocument _styleXml;
+  private readonly ExcelWorkbook _wb;
+  private readonly XmlNamespaceManager _nameSpaceManager;
+  internal int _nextDfxNumFmtID = 164;
+
+  protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
+    "numFmts",
+    "fonts",
+    "fills",
+    "borders",
+    "cellStyleXfs",
+    "cellXfs",
+    "cellStyles",
+    "dxfs",
+  ];
+
+  internal ExcelStyles(XmlNamespaceManager nameSpaceManager, XmlDocument xml, ExcelWorkbook wb)
+      : base(nameSpaceManager, xml) {
+    _styleXml = xml;
+    _wb = wb;
+    _nameSpaceManager = nameSpaceManager;
+    LoadFromDocument();
+  }
+
+  /// <summary>
+  /// Loads the style XML to memory
+  /// </summary>
+  private void LoadFromDocument() {
+    //NumberFormats
+    ExcelNumberFormatXml.AddBuildIn(NameSpaceManager, NumberFormats);
+    XmlNode numNode = _styleXml.SelectSingleNode(_numberFormatsPath, _nameSpaceManager);
+    if (numNode != null) {
+      foreach (XmlNode n in numNode) {
+        ExcelNumberFormatXml nf = new ExcelNumberFormatXml(_nameSpaceManager, n);
+        NumberFormats.Add(nf.Id, nf);
+        if (nf.NumFmtId >= NumberFormats.NextId) {
+          NumberFormats.NextId = nf.NumFmtId + 1;
+        }
+      }
+    }
+
+    //Fonts
+    XmlNode fontNode = _styleXml.SelectSingleNode(_fontsPath, _nameSpaceManager);
+    foreach (XmlNode n in fontNode) {
+      ExcelFontXml f = new ExcelFontXml(_nameSpaceManager, n);
+      Fonts.Add(f.Id, f);
+    }
+
+    //Fills
+    XmlNode fillNode = _styleXml.SelectSingleNode(_fillsPath, _nameSpaceManager);
+    foreach (XmlNode n in fillNode) {
+      ExcelFillXml f;
+      if (n.FirstChild != null && n.FirstChild.LocalName == "gradientFill") {
+        f = new ExcelGradientFillXml(_nameSpaceManager, n);
+      } else {
+        f = new(_nameSpaceManager, n);
+      }
+      Fills.Add(f.Id, f);
+    }
+
+    //Borders
+    XmlNode borderNode = _styleXml.SelectSingleNode(_bordersPath, _nameSpaceManager);
+    foreach (XmlNode n in borderNode) {
+      ExcelBorderXml b = new ExcelBorderXml(_nameSpaceManager, n);
+      Borders.Add(b.Id, b);
+    }
+
+    //cellStyleXfs
+    XmlNode styleXfsNode = _styleXml.SelectSingleNode(_cellStyleXfsPath, _nameSpaceManager);
+    if (styleXfsNode != null) {
+      foreach (XmlNode n in styleXfsNode) {
+        ExcelXfs item = new ExcelXfs(_nameSpaceManager, n, this);
+        CellStyleXfs.Add(item.Id, item);
+      }
+    }
+
+    XmlNode styleNode = _styleXml.SelectSingleNode(_cellXfsPath, _nameSpaceManager);
+    for (int i = 0; i < styleNode.ChildNodes.Count; i++) {
+      XmlNode n = styleNode.ChildNodes[i];
+      ExcelXfs item = new ExcelXfs(_nameSpaceManager, n, this);
+      CellXfs.Add(item.Id, item);
+    }
+
+    //cellStyle
+    XmlNode namedStyleNode = _styleXml.SelectSingleNode(_cellStylesPath, _nameSpaceManager);
+    if (namedStyleNode != null) {
+      foreach (XmlNode n in namedStyleNode) {
+        ExcelNamedStyleXml item = new ExcelNamedStyleXml(_nameSpaceManager, n, this);
+        NamedStyles.Add(item.Name, item);
+      }
+    }
+
+    //dxfsPath
+    XmlNode dxfsNode = _styleXml.SelectSingleNode(_dxfsPath, _nameSpaceManager);
+    if (dxfsNode != null) {
+      foreach (XmlNode x in dxfsNode) {
+        ExcelDxfStyleConditionalFormatting item = new ExcelDxfStyleConditionalFormatting(
+            _nameSpaceManager,
+            x,
+            this);
+        Dxfs.Add(item.Id, item);
+      }
+    }
+  }
+
+  internal ExcelStyle GetStyleObject(int id, int positionId, string address) {
+    if (id < 0) {
+      id = 0;
+    }
+    return new(this, PropertyChange, positionId, address, id);
+  }
+
+  /// <summary>
+  /// Handels changes of properties on the style objects
+  /// </summary>
+  /// <param name="sender"></param>
+  /// <param name="e"></param>
+  /// <returns></returns>
+  internal int PropertyChange(StyleBase sender, StyleChangeEventArgs e) {
+    var address = new ExcelAddressBase(e.Address);
+    var ws = _wb.Worksheets[e.PositionID];
+    Dictionary<int, int> styleCashe = new Dictionary<int, int>();
+    //Set single address
+    SetStyleAddress(sender, e, address, ws, ref styleCashe);
+    if (address.Addresses != null) {
+      //Handle multiaddresses
+      foreach (var innerAddress in address.Addresses) {
+        SetStyleAddress(sender, e, innerAddress, ws, ref styleCashe);
+      }
+    }
+    return 0;
+  }
+
+  private void SetStyleAddress(
+      StyleBase sender,
+      StyleChangeEventArgs e,
+      ExcelAddressBase address,
+      ExcelWorksheet ws,
+      ref Dictionary<int, int> styleCashe) {
+    if (address.Start.Column == 0 || address.Start.Row == 0) {
+      throw (new("error address"));
+    }
+    //Columns
+    if (address.Start.Row == 1 && address.End.Row == ExcelPackage.MaxRows) {
+      ExcelColumn column;
+      int col = address.Start.Column,
+          row = 0;
+      //Get the startcolumn
+      if (!ws._values.Exists(0, address.Start.Column)) {
+        column = ws.Column(address.Start.Column);
+      } else {
+        column = (ExcelColumn)ws._values.GetValue(0, address.Start.Column);
+      }
+
+      while (column.ColumnMin <= address.End.Column) {
+        if (column.ColumnMax > address.End.Column) {
+          var newCol = ws.CopyColumn(column, address.End.Column + 1, column.ColumnMax);
+          column.ColumnMax = address.End.Column;
+        }
+        var s = ws._styles.GetValue(0, column.ColumnMin);
+        if (styleCashe.ContainsKey(s)) {
+          ws.SetStyle(0, column.ColumnMin, styleCashe[s]);
+        } else {
+          ExcelXfs st = CellXfs[s];
+          int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
+          styleCashe.Add(s, newId);
+          ws.SetStyle(0, column.ColumnMin, newId);
+        }
+
+        //index++;
+
+        if (!ws._values.NextCell(ref row, ref col) || row > 0) {
+          column._columnMax = address.End.Column;
+          break;
+        }
+        column = (ws._values.GetValue(0, col) as ExcelColumn);
+      }
+
+      if (column._columnMax < address.End.Column) {
+        var newCol = ws.Column(column._columnMax + 1);
+        newCol._columnMax = address.End.Column;
+
+        var s = ws._styles.GetValue(0, column.ColumnMin);
+        if (styleCashe.ContainsKey(s)) {
+          ws.SetStyle(0, column.ColumnMin, styleCashe[s]);
+        } else {
+          ExcelXfs st = CellXfs[s];
+          int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
+          styleCashe.Add(s, newId);
+          ws.SetStyle(0, column.ColumnMin, newId);
+        }
+
+        column._columnMax = address.End.Column;
+      }
+
+      //Set for individual cells in the span. We loop all cells here since the cells are sorted with columns first.
+      var cse = new CellsStoreEnumerator<int>(
+          ws._styles,
+          1,
+          address._fromCol,
+          address._toRow,
+          address._toCol);
+      while (cse.Next()) {
+        if (cse.Column >= address.Start.Column && cse.Column <= address.End.Column) {
+          if (styleCashe.ContainsKey(cse.Value)) {
+            ws.SetStyle(cse.Row, cse.Column, styleCashe[cse.Value]);
+          } else {
+            ExcelXfs st = CellXfs[cse.Value];
+            int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
+            styleCashe.Add(cse.Value, newId);
+            cse.Value = newId;
+            //ws.SetStyle(cse.Row, cse.Column, newId);
+          }
+        }
+      }
+
+      //Update cells with styled columns
+      cse = new(ws._styles, 1, 0, address._toRow, 0);
+      while (cse.Next()) {
+        for (int c = address._fromRow; c <= address._toCol; c++) {
+          if (!ws._styles.Exists(cse.Row, c)) {
+            if (styleCashe.ContainsKey(cse.Value)) {
+              ws.SetStyle(cse.Row, c, styleCashe[cse.Value]);
+            } else {
+              ExcelXfs st = CellXfs[cse.Value];
+              int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
+              styleCashe.Add(cse.Value, newId);
+              ws.SetStyle(cse.Row, c, newId);
+            }
+          }
+        }
+      }
+    }
+    //Rows
+    else if (address.Start.Column == 1 && address.End.Column == ExcelPackage.MaxColumns) {
+      for (int rowNum = address.Start.Row; rowNum <= address.End.Row; rowNum++) {
+        var s = ws._styles.GetValue(rowNum, 0);
+        if (s == 0) {
+          //iterate all columns and set the row to the style of the last column
+          var cse = new CellsStoreEnumerator<int>(ws._styles, 0, 1, 0, ExcelPackage.MaxColumns);
+          while (cse.Next()) {
+            s = cse.Value;
+            var c = ws._values.GetValue(cse.Row, cse.Column) as ExcelColumn;
+            if (c != null && c.ColumnMax < ExcelPackage.MaxColumns) {
+              for (int col = c.ColumnMin; col < c.ColumnMax; col++) {
+                if (!ws._styles.Exists(rowNum, col)) {
+                  ws._styles.SetValue(rowNum, col, s);
+                }
+              }
+            }
+          }
+          ws.SetStyle(rowNum, 0, s);
+        }
+        if (styleCashe.ContainsKey(s)) {
+          ws.SetStyle(rowNum, 0, styleCashe[s]);
+        } else {
+          ExcelXfs st = CellXfs[s];
+          int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
+          styleCashe.Add(s, newId);
+          ws._styles.SetValue(rowNum, 0, newId);
+          ws.SetStyle(rowNum, 0, newId);
+        }
+      }
+
+      //Update individual cells
+      var cse2 = new CellsStoreEnumerator<int>(
+          ws._styles,
+          address._fromRow,
+          address._fromCol,
+          address._toRow,
+          address._toCol);
+      while (cse2.Next()) {
+        var s = cse2.Value;
+        if (styleCashe.ContainsKey(s)) {
+          ws.SetStyle(cse2.Row, cse2.Column, styleCashe[s]);
+        } else {
+          ExcelXfs st = CellXfs[s];
+          int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
+          styleCashe.Add(s, newId);
+          cse2.Value = newId;
+        }
+      }
+
+      //Update cells with styled rows
+      cse2 = new(ws._styles, 0, 1, 0, address._toCol);
+      while (cse2.Next()) {
+        for (int r = address._fromRow; r <= address._toRow; r++) {
+          if (!ws._styles.Exists(r, cse2.Column)) {
+            var s = cse2.Value;
+            if (styleCashe.ContainsKey(s)) {
+              ws.SetStyle(r, cse2.Column, styleCashe[s]);
+            } else {
+              ExcelXfs st = CellXfs[s];
+              int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
+              styleCashe.Add(s, newId);
+              ws.SetStyle(r, cse2.Column, newId);
+            }
+          }
+        }
+      }
+    } else //Cellrange
+    {
+      for (int col = address.Start.Column; col <= address.End.Column; col++) {
+        for (int row = address.Start.Row; row <= address.End.Row; row++) {
+          var s = GetStyleId(ws, row, col);
+          if (styleCashe.ContainsKey(s)) {
+            ws.SetStyle(row, col, styleCashe[s]);
+          } else {
+            ExcelXfs st = CellXfs[s];
+            int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
+            styleCashe.Add(s, newId);
+            ws.SetStyle(row, col, newId);
+          }
+        }
+      }
+    }
+  }
+
+  internal int GetStyleId(ExcelWorksheet ws, int row, int col) {
+    int v = 0;
+    if (ws._styles.Exists(row, col, ref v)) {
+      return v;
+    }
+    if (ws._styles.Exists(
+        row,
+        0,
+        ref v)) //First Row
+    {
+      return v;
+    } // then column
+    if (ws._styles.Exists(0, col, ref v)) {
+      return v;
+    }
+    int r = 0,
+        c = col;
+    if (ws._values.PrevCell(ref r, ref c)) {
+      var column = ws._values.GetValue(0, c) as ExcelColumn;
+      if (column != null
+          && column.ColumnMax
+              >= col) //Fixes issue 15174
+      {
+        return ws._styles.GetValue(0, c);
+      }
+      return 0;
+    }
+    return 0;
+  }
+
+  /// <summary>
+  /// Handles property changes on Named styles.
+  /// </summary>
+  /// <param name="sender"></param>
+  /// <param name="e"></param>
+  /// <returns></returns>
+  internal int NamedStylePropertyChange(StyleBase sender, StyleChangeEventArgs e) {
+    int index = NamedStyles.FindIndexById(e.Address);
+    if (index >= 0) {
+      int newId = CellStyleXfs[NamedStyles[index].StyleXfId]
+          .GetNewId(CellStyleXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
+      int prevIx = NamedStyles[index].StyleXfId;
+      NamedStyles[index].StyleXfId = newId;
+      NamedStyles[index].Style.Index = newId;
+
+      NamedStyles[index].XfId = int.MinValue;
+      foreach (var style in CellXfs) {
+        if (style.XfId == prevIx) {
+          style.XfId = newId;
+        }
+      }
+    }
+    return 0;
+  }
+
+  public ExcelStyleCollection<ExcelNumberFormatXml> NumberFormats = new();
+  public ExcelStyleCollection<ExcelFontXml> Fonts = new();
+  public ExcelStyleCollection<ExcelFillXml> Fills = new();
+  public ExcelStyleCollection<ExcelBorderXml> Borders = new();
+  public ExcelStyleCollection<ExcelXfs> CellStyleXfs = new();
+  public ExcelStyleCollection<ExcelXfs> CellXfs = new();
+  public ExcelStyleCollection<ExcelNamedStyleXml> NamedStyles = new();
+  public ExcelStyleCollection<ExcelDxfStyleConditionalFormatting> Dxfs = new();
+
+  internal string Id => "";
+
+  public ExcelNamedStyleXml CreateNamedStyle(string name) {
+    return CreateNamedStyle(name, null);
+  }
+
+  public ExcelNamedStyleXml CreateNamedStyle(string name, ExcelStyle template) {
+    if (_wb.Styles.NamedStyles.ExistsKey(name)) {
+      throw new(string.Format("Key {0} already exists in collection", name));
+    }
+
+    ExcelNamedStyleXml style;
+    style = new(NameSpaceManager, this);
+    int xfIdCopy,
+        positionId;
+    ExcelStyles styles;
+    if (template == null) {
+      //                style.Style = new ExcelStyle(this, NamedStylePropertyChange, -1, name, 0);
+      xfIdCopy = 0;
+      positionId = -1;
+      styles = this;
+    } else {
+      if (template.PositionID < 0 && template.Styles == this) {
+        xfIdCopy = template.Index;
+        positionId = template.PositionID;
+        styles = this;
+        //style.Style = new ExcelStyle(this, NamedStylePropertyChange, Template.PositionID, name, Template.Index);
+        //style.StyleXfId = Template.Index;
+      } else {
+        xfIdCopy = template.XfId;
+        positionId = -1;
+        styles = template.Styles;
+      }
+    }
+    //Clone namedstyle
+    int styleXfId = CloneStyle(styles, xfIdCopy, true);
+    //Close cells style
+    CellStyleXfs[styleXfId].XfId = CellStyleXfs.Count - 1;
+    int xfid = CloneStyle(styles, xfIdCopy, false, true); //Always add a new style (We create a new named style here)
+    CellXfs[xfid].XfId = styleXfId;
+    style.Style = new(this, NamedStylePropertyChange, positionId, name, styleXfId);
+    style.StyleXfId = styleXfId;
+
+    style.Name = name;
+    int ix = _wb.Styles.NamedStyles.Add(style.Name, style);
+    style.Style.SetIndex(ix);
+    //style.Style.XfId = ix;
+    return style;
+  }
+
+  public void UpdateXml() {
+    RemoveUnusedStyles();
+
+    //NumberFormat
+    XmlNode nfNode = _styleXml.SelectSingleNode(_numberFormatsPath, _nameSpaceManager);
+    if (nfNode == null) {
+      CreateNode(_numberFormatsPath, true);
+      nfNode = _styleXml.SelectSingleNode(_numberFormatsPath, _nameSpaceManager);
+    } else {
+      nfNode.RemoveAll();
+    }
+
+    int count = 0;
+    int normalIx = NamedStyles.FindIndexById("Normal");
+    if (NamedStyles.Count > 0
+        && normalIx >= 0
+        && NamedStyles[normalIx].Style.Numberformat.NumFmtID >= 164) {
+      ExcelNumberFormatXml nf = NumberFormats[NumberFormats.FindIndexById(
+            NamedStyles[normalIx].Style.Numberformat.Id)];
+      nfNode.AppendChild(
+          nf.CreateXmlNode(_styleXml.CreateElement("numFmt", ExcelPackage._schemaMain)));
+      nf.newID = count++;
+    }
+    foreach (ExcelNumberFormatXml nf in NumberFormats) {
+      if (!nf.BuildIn /*&& nf.newID<0*/) //Buildin formats are not updated.
+      {
+        nfNode.AppendChild(
+            nf.CreateXmlNode(_styleXml.CreateElement("numFmt", ExcelPackage._schemaMain)));
+        nf.newID = count;
+        count++;
+      }
+    }
+    (nfNode as XmlElement).SetAttribute("count", count.ToString());
+
+    //Font
+    count = 0;
+    XmlNode fntNode = _styleXml.SelectSingleNode(_fontsPath, _nameSpaceManager);
+    fntNode.RemoveAll();
+
+    //Normal should be first in the collection
+    if (NamedStyles.Count > 0 && normalIx >= 0 && NamedStyles[normalIx].Style.Font.Index > 0) {
+      ExcelFontXml fnt = Fonts[NamedStyles[normalIx].Style.Font.Index];
+      fntNode.AppendChild(
+          fnt.CreateXmlNode(_styleXml.CreateElement("font", ExcelPackage._schemaMain)));
+      fnt.newID = count++;
+    }
+
+    foreach (ExcelFontXml fnt in Fonts) {
+      if (fnt.useCnt
+          > 0 /* && fnt.newID<0*/) {
+        fntNode.AppendChild(
+            fnt.CreateXmlNode(_styleXml.CreateElement("font", ExcelPackage._schemaMain)));
+        fnt.newID = count;
+        count++;
+      }
+    }
+    (fntNode as XmlElement).SetAttribute("count", count.ToString());
+
+    //Fills
+    count = 0;
+    XmlNode fillsNode = _styleXml.SelectSingleNode(_fillsPath, _nameSpaceManager);
+    fillsNode.RemoveAll();
+    Fills[0].useCnt = 1; //Must exist (none);
+    Fills[1].useCnt = 1; //Must exist (gray125);
+    foreach (ExcelFillXml fill in Fills) {
+      if (fill.useCnt > 0) {
+        fillsNode.AppendChild(
+            fill.CreateXmlNode(_styleXml.CreateElement("fill", ExcelPackage._schemaMain)));
+        fill.newID = count;
+        count++;
+      }
+    }
+
+    (fillsNode as XmlElement).SetAttribute("count", count.ToString());
+
+    //Borders
+    count = 0;
+    XmlNode bordersNode = _styleXml.SelectSingleNode(_bordersPath, _nameSpaceManager);
+    bordersNode.RemoveAll();
+    Borders[0].useCnt = 1; //Must exist blank;
+    foreach (ExcelBorderXml border in Borders) {
+      if (border.useCnt > 0) {
+        bordersNode.AppendChild(
+            border.CreateXmlNode(_styleXml.CreateElement("border", ExcelPackage._schemaMain)));
+        border.newID = count;
+        count++;
+      }
+    }
+    (bordersNode as XmlElement).SetAttribute("count", count.ToString());
+
+    XmlNode styleXfsNode = _styleXml.SelectSingleNode(_cellStyleXfsPath, _nameSpaceManager);
+    if (styleXfsNode == null && NamedStyles.Count > 0) {
+      CreateNode(_cellStyleXfsPath);
+      styleXfsNode = _styleXml.SelectSingleNode(_cellStyleXfsPath, _nameSpaceManager);
+    }
+    if (NamedStyles.Count > 0) {
+      styleXfsNode.RemoveAll();
+    }
+    //NamedStyles
+    count = normalIx > -1 ? 1 : 0; //If we have a normal style, we make sure it's added first.
+
+    XmlNode cellStyleNode = _styleXml.SelectSingleNode(_cellStylesPath, _nameSpaceManager);
+    if (cellStyleNode != null) {
+      cellStyleNode.RemoveAll();
+    }
+    XmlNode cellXfsNode = _styleXml.SelectSingleNode(_cellXfsPath, _nameSpaceManager);
+    cellXfsNode.RemoveAll();
+
+    if (NamedStyles.Count > 0 && normalIx >= 0) {
+      NamedStyles[normalIx].newID = 0;
+      AddNamedStyle(0, styleXfsNode, cellXfsNode, NamedStyles[normalIx]);
+    }
+    foreach (ExcelNamedStyleXml style in NamedStyles) {
+      if (!style.Name.Equals("normal", StringComparison.InvariantCultureIgnoreCase)) {
+        AddNamedStyle(count++, styleXfsNode, cellXfsNode, style);
+      } else {
+        style.newID = 0;
+      }
+      cellStyleNode.AppendChild(
+          style.CreateXmlNode(_styleXml.CreateElement("cellStyle", ExcelPackage._schemaMain)));
+    }
+    if (cellStyleNode != null) {
+      (cellStyleNode as XmlElement).SetAttribute("count", count.ToString());
+    }
+    if (styleXfsNode != null) {
+      (styleXfsNode as XmlElement).SetAttribute("count", count.ToString());
+    }
+
+    //CellStyle
+    int xfix = 0;
+    foreach (ExcelXfs xf in CellXfs) {
+      if (xf.useCnt > 0 && !(normalIx >= 0 && NamedStyles[normalIx].XfId == xfix)) {
+        cellXfsNode.AppendChild(
+            xf.CreateXmlNode(_styleXml.CreateElement("xf", ExcelPackage._schemaMain)));
+        xf.newID = count;
+        count++;
+      }
+      xfix++;
+    }
+    (cellXfsNode as XmlElement).SetAttribute("count", count.ToString());
+
+    //Set dxf styling for conditional Formatting
+    XmlNode dxfsNode = _styleXml.SelectSingleNode(_dxfsPath, _nameSpaceManager);
+    foreach (var ws in _wb.Worksheets) {
+      if (ws is ExcelChartsheet) {
+        continue;
+      }
+      foreach (var cf in ws.ConditionalFormatting) {
+        if (cf.Style.HasValue) {
+          int ix = Dxfs.FindIndexById(cf.Style.Id);
+          if (ix < 0) {
+            ((ExcelConditionalFormattingRule)cf).DxfId = Dxfs.Count;
+            Dxfs.Add(cf.Style.Id, cf.Style);
+            var elem = ((XmlDocument)TopNode).CreateElement("d", "dxf", ExcelPackage._schemaMain);
+            cf.Style.CreateNodes(new XmlHelperInstance(NameSpaceManager, elem), "");
+            dxfsNode.AppendChild(elem);
+          } else {
+            ((ExcelConditionalFormattingRule)cf).DxfId = ix;
+          }
+        }
+      }
+    }
+    if (dxfsNode != null) {
+      (dxfsNode as XmlElement).SetAttribute("count", Dxfs.Count.ToString());
+    }
+  }
+
+  private void AddNamedStyle(
+      int id,
+      XmlNode styleXfsNode,
+      XmlNode cellXfsNode,
+      ExcelNamedStyleXml style) {
+    var styleXfs = CellStyleXfs[style.StyleXfId];
+    styleXfsNode.AppendChild(
+        styleXfs.CreateXmlNode(_styleXml.CreateElement("xf", ExcelPackage._schemaMain), true));
+    styleXfs.newID = id;
+    styleXfs.XfId = style.StyleXfId;
+
+    var ix = CellXfs.FindIndexById(styleXfs.Id);
+    if (ix < 0) {
+      cellXfsNode.AppendChild(
+          styleXfs.CreateXmlNode(_styleXml.CreateElement("xf", ExcelPackage._schemaMain)));
+    } else {
+      if (id < 0) {
+        CellXfs[ix].XfId = id;
+      }
+      cellXfsNode.AppendChild(
+          CellXfs[ix].CreateXmlNode(_styleXml.CreateElement("xf", ExcelPackage._schemaMain)));
+      CellXfs[ix].useCnt = 0;
+      CellXfs[ix].newID = id;
+    }
+
+    if (style.XfId >= 0) {
+      style.XfId = CellXfs[style.XfId].newID;
+    } else {
+      style.XfId = 0;
+    }
+  }
+
+  private void RemoveUnusedStyles() {
+    CellXfs[0].useCnt = 1; //First item is allways used.
+    foreach (ExcelWorksheet sheet in _wb.Worksheets) {
+      var cse = new CellsStoreEnumerator<int>(sheet._styles);
+      while (cse.Next()) {
+        var v = cse.Value;
+        if (v >= 0) {
+          CellXfs[v].useCnt++;
+        }
+      }
+    }
+    foreach (ExcelNamedStyleXml ns in NamedStyles) {
+      CellStyleXfs[ns.StyleXfId].useCnt++;
+    }
+
+    foreach (ExcelXfs xf in CellXfs) {
+      if (xf.useCnt > 0) {
+        if (xf.FontId >= 0) {
+          Fonts[xf.FontId].useCnt++;
+        }
+        if (xf.FillId >= 0) {
+          Fills[xf.FillId].useCnt++;
+        }
+        if (xf.BorderId >= 0) {
+          Borders[xf.BorderId].useCnt++;
+        }
+      }
+    }
+    foreach (ExcelXfs xf in CellStyleXfs) {
+      if (xf.useCnt > 0) {
+        if (xf.FontId >= 0) {
+          Fonts[xf.FontId].useCnt++;
+        }
+        if (xf.FillId >= 0) {
+          Fills[xf.FillId].useCnt++;
+        }
+        if (xf.BorderId >= 0) {
+          Borders[xf.BorderId].useCnt++;
+        }
+      }
+    }
+  }
+
+  internal int GetStyleIdFromName(string name) {
+    int i = NamedStyles.FindIndexById(name);
+    if (i >= 0) {
+      int id = NamedStyles[i].XfId;
+      if (id < 0) {
+        int styleXfId = NamedStyles[i].StyleXfId;
+        ExcelXfs newStyle = CellStyleXfs[styleXfId].Copy();
+        newStyle.XfId = styleXfId;
+        id = CellXfs.FindIndexById(newStyle.Id);
+        if (id < 0) {
+          id = CellXfs.Add(newStyle.Id, newStyle);
+        }
+        NamedStyles[i].XfId = id;
+      }
+      return id;
+    }
+    return 0;
+    //throw(new Exception("Named style does not exist"));
+  }
+
+  private string GetXmlNode(XmlNode node) {
+    if (node == null) {
+      return "";
+    }
+    if (node.Value != null) {
+      return node.Value;
+    }
+    return "";
+  }
+
+  internal int CloneStyle(ExcelStyles style, int styleId) {
+    return CloneStyle(style, styleId, false, false);
+  }
+
+  internal int CloneStyle(ExcelStyles style, int styleId, bool isNamedStyle) {
+    return CloneStyle(style, styleId, isNamedStyle, false);
+  }
+
+  internal int CloneStyle(ExcelStyles style, int styleId, bool isNamedStyle, bool allwaysAdd) {
+    var xfs = isNamedStyle ? style.CellStyleXfs[styleId] : style.CellXfs[styleId];
+    ExcelXfs newXfs = xfs.Copy(this);
+    //Numberformat
+    if (xfs.NumberFormatId > 0) {
+      //rake36: Two problems here...
+      //rake36:  1. the first time through when format stays equal to String.Empty, it adds a string.empty to the list of Number Formats
+      //rake36:  2. when adding a second sheet, if the numberformatid == 164, it finds the 164 added by previous sheets but was using the array index
+      //rake36:      for the numberformatid
+
+      string format = string.Empty;
+      foreach (var fmt in style.NumberFormats) {
+        if (fmt.NumFmtId == xfs.NumberFormatId) {
+          format = fmt.Format;
+          break;
+        }
+      }
+      //rake36: Don't add another format if it's blank
+      if (!String.IsNullOrEmpty(format)) {
+        int ix = NumberFormats.FindIndexById(format);
+        if (ix < 0) {
+          var item = new ExcelNumberFormatXml(NameSpaceManager) {
+            Format = format,
+            NumFmtId = NumberFormats.NextId++,
+          };
+          NumberFormats.Add(format, item);
+          //rake36: Use the just added format id
+          newXfs.NumberFormatId = item.NumFmtId;
+        } else {
+          //rake36: Use the format id defined by the index... not the index itself
+          newXfs.NumberFormatId = NumberFormats[ix].NumFmtId;
+        }
+      }
+    }
+
+    //Font
+    if (xfs.FontId > -1) {
+      int ix = Fonts.FindIndexById(xfs.Font.Id);
+      if (ix < 0) {
+        ExcelFontXml item = style.Fonts[xfs.FontId].Copy();
+        ix = Fonts.Add(xfs.Font.Id, item);
+      }
+      newXfs.FontId = ix;
+    }
+
+    //Border
+    if (xfs.BorderId > -1) {
+      int ix = Borders.FindIndexById(xfs.Border.Id);
+      if (ix < 0) {
+        ExcelBorderXml item = style.Borders[xfs.BorderId].Copy();
+        ix = Borders.Add(xfs.Border.Id, item);
+      }
+      newXfs.BorderId = ix;
+    }
+
+    //Fill
+    if (xfs.FillId > -1) {
+      int ix = Fills.FindIndexById(xfs.Fill.Id);
+      if (ix < 0) {
+        var item = style.Fills[xfs.FillId].Copy();
+        ix = Fills.Add(xfs.Fill.Id, item);
+      }
+      newXfs.FillId = ix;
+    }
+
+    //Named style reference
+    if (xfs.XfId > 0) {
+      var id = style.CellStyleXfs[xfs.XfId].Id;
+      var newId = CellStyleXfs.FindIndexById(id);
+      if (newId >= 0) {
+        newXfs.XfId = newId;
+      } else if (style._wb != _wb
+          && allwaysAdd
+              == false) //Not the same workbook, copy the namedstyle to the workbook or match the id
+      {
+        var nsFind = style.NamedStyles.ToDictionary(d => (d.StyleXfId));
+        if (nsFind.ContainsKey(xfs.XfId)) {
+          var st = nsFind[xfs.XfId];
+          if (NamedStyles.ExistsKey(st.Name)) {
+            newXfs.XfId = NamedStyles.FindIndexById(st.Name);
+          } else {
+            var ns = CreateNamedStyle(st.Name, st.Style);
+            newXfs.XfId = NamedStyles.Count - 1;
+          }
+        }
+      }
+    }
+
+    int index;
+    if (isNamedStyle) {
+      index = CellStyleXfs.Add(newXfs.Id, newXfs);
+    } else {
+      if (allwaysAdd) {
+        index = CellXfs.Add(newXfs.Id, newXfs);
+      } else {
+        index = CellXfs.FindIndexById(newXfs.Id);
+        if (index < 0) {
+          index = CellXfs.Add(newXfs.Id, newXfs);
+        }
+      }
+    }
+    return index;
+  }
+}
diff --git a/AppsheetEpplus/ExcelTextFormat.cs b/AppsheetEpplus/ExcelTextFormat.cs
new file mode 100644
index 0000000..8c46b1e
--- /dev/null
+++ b/AppsheetEpplus/ExcelTextFormat.cs
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		    Initial Release		        2011-01-01
+ * Jan Källman		    License changed GPL-->LGPL 2011-12-27
+ *******************************************************************************/
+
+using System.Globalization;
+using System.Text;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Discribes a column when reading a text using the ExcelRangeBase.LoadFromText method
+/// </summary>
+public enum eDataTypes {
+  /// <summary>
+  /// Let the the import decide.
+  /// </summary>
+  Unknown,
+
+  /// <summary>
+  /// Always a string.
+  /// </summary>
+  String,
+
+  /// <summary>
+  /// Try to convert it to a number. If it fails then add it as a string.
+  /// </summary>
+  Number,
+
+  /// <summary>
+  /// Try to convert it to a date. If it fails then add it as a string.
+  /// </summary>
+  DateTime,
+
+  /// <summary>
+  /// Try to convert it to a number and divide with 100.
+  /// Removes any tailing percent sign (%). If it fails then add it as a string.
+  /// </summary>
+  Percent,
+}
+
+/// <summary>
+/// Describes how to split a CSV text. Used by the ExcelRange.LoadFromText method
+/// </summary>
+public class ExcelTextFormat {
+  /// <summary>
+  /// Describes how to split a CSV text
+  ///
+  /// Default values
+  /// <list>
+  /// <listheader><term>Property</term><description>Value</description></listheader>
+  /// <item><term>Delimiter</term><description>,</description></item>
+  /// <item><term>TextQualifier</term><description>None (\0)</description></item>
+  /// <item><term>EOL</term><description>CRLF</description></item>
+  /// <item><term>Culture</term><description>CultureInfo.InvariantCulture</description></item>
+  /// <item><term>DataTypes</term><description>End of line default CRLF</description></item>
+  /// <item><term>SkipLinesBeginning</term><description>0</description></item>
+  /// <item><term>SkipLinesEnd</term><description>0</description></item>
+  /// <item><term>Encoding</term><description>Encoding.ASCII</description></item>
+  /// </list>
+  /// </summary>
+  public ExcelTextFormat() {}
+
+  /// <summary>
+  /// Delimiter character
+  /// </summary>
+  public char Delimiter { get; set; } = ',';
+
+  /// <summary>
+  /// Text qualifier character
+  /// </summary>
+  public char TextQualifier { get; set; } = '\0';
+
+  /// <summary>
+  /// End of line characters. Default CRLF
+  /// </summary>
+  public string EOL { get; set; } = "\r\n";
+
+  /// <summary>
+  /// Datatypes list for each column (if column is not present Unknown is assumed)
+  /// </summary>
+  public eDataTypes[] DataTypes { get; set; } = null;
+
+  /// <summary>
+  /// Culture used when parsing. Default CultureInfo.InvariantCulture
+  /// </summary>
+  public CultureInfo Culture { get; set; } = CultureInfo.InvariantCulture;
+
+  /// <summary>
+  /// Number of lines skiped in the begining of the file. Default 0.
+  /// </summary>
+  public int SkipLinesBeginning { get; set; } = 0;
+
+  /// <summary>
+  /// Number of lines skiped at the end of the file. Default 0.
+  /// </summary>
+  public int SkipLinesEnd { get; set; } = 0;
+
+  /// <summary>
+  /// Only used when reading files from disk using a FileInfo object. Default AscII
+  /// </summary>
+  public Encoding Encoding { get; set; } = Encoding.ASCII;
+}
diff --git a/AppsheetEpplus/ExcelWorkbook.cs b/AppsheetEpplus/ExcelWorkbook.cs
new file mode 100644
index 0000000..c98142d
--- /dev/null
+++ b/AppsheetEpplus/ExcelWorkbook.cs
@@ -0,0 +1,781 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		    Initial Release		       2011-01-01
+ * Jan Källman		    License changed GPL-->LGPL 2011-12-27
+ * Richard Tallent		Fix escaping of quotes					2012-10-31
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Globalization;
+using System.IO;
+using System.Text;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// How the application should calculate formulas in the workbook
+/// </summary>
+public enum ExcelCalcMode {
+  /// <summary>
+  /// Indicates that calculations in the workbook are performed automatically when cell values change.
+  /// The application recalculates those cells that are dependent on other cells that contain changed values.
+  /// This mode of calculation helps to avoid unnecessary calculations.
+  /// </summary>
+  Automatic,
+
+  /// <summary>
+  /// Indicates tables be excluded during automatic calculation
+  /// </summary>
+  AutomaticNoTable,
+
+  /// <summary>
+  /// Indicates that calculations in the workbook be triggered manually by the user.
+  /// </summary>
+  Manual,
+}
+
+/// <summary>
+/// Represents the Excel workbook and provides access to all the
+/// document properties and worksheets within the workbook.
+/// </summary>
+public sealed class ExcelWorkbook : XmlHelper {
+  internal class SharedStringItem {
+    internal int pos;
+    internal string Text;
+    internal bool isRichText;
+  }
+
+  private readonly ExcelPackage _package;
+  private ExcelWorksheets _worksheets;
+  private OfficeProperties _properties;
+
+  private ExcelStyles _styles;
+
+  internal static ImmutableArray<string> WorkbookSchemaNodeOrder = [
+    "fileVersion",
+    "fileSharing",
+    "workbookPr",
+    "workbookProtection",
+    "bookViews",
+    "sheets",
+    "functionGroups",
+    "functionPrototypes",
+    "externalReferences",
+    "definedNames",
+    "calcPr",
+    "oleSize",
+    "customWorkbookViews",
+    "pivotCaches",
+    "smartTagPr",
+    "smartTagTypes",
+    "webPublishing",
+    "fileRecoveryPr",
+  ];
+
+  protected override ImmutableArray<string> SchemaNodeOrder => WorkbookSchemaNodeOrder;
+
+  internal ExcelWorkbook(ExcelPackage package, XmlNamespaceManager namespaceManager)
+      : base(namespaceManager) {
+    _package = package;
+    _names = new(this);
+    _namespaceManager = namespaceManager;
+
+    WorkbookXml = package.GetOrCreateXmlDocument(
+        WorkbookUri,
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
+        ExcelPackage._schemaRelationships + "/officeDocument",
+        () => CreateEmptyWorkbookXml(namespaceManager));
+    _stylesXml = package.GetOrCreateXmlDocument(
+        StylesUri,
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
+        ExcelPackage._schemaRelationships + "/styles",
+        CreateEmptyStylesXml);
+
+    TopNode = WorkbookXml.DocumentElement;
+    FullCalcOnLoad = true; //Full calculation on load by default, for both new workbooks and templates.
+
+    GetSharedStrings();
+    GetExternalReferences();
+    GetDefinedNames();
+  }
+
+  private static XmlDocument CreateEmptyWorkbookXml(XmlNamespaceManager namespaceManager) {
+    var result = new XmlDocument(namespaceManager.NameTable);
+    var wbElem = result.CreateElement("workbook", ExcelPackage._schemaMain);
+
+    // Add the relationships namespace
+    wbElem.SetAttribute("xmlns:r", ExcelPackage._schemaRelationships);
+    result.AppendChild(wbElem);
+
+    // Create the bookViews and workbooks element
+    var bookViews = result.CreateElement("bookViews", ExcelPackage._schemaMain);
+    wbElem.AppendChild(bookViews);
+    var workbookView = result.CreateElement("workbookView", ExcelPackage._schemaMain);
+    bookViews.AppendChild(workbookView);
+
+    return result;
+  }
+
+  private static XmlDocument CreateEmptyStylesXml() {
+    StringBuilder xml = new StringBuilder(
+        "<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">");
+    xml.Append("<numFmts />");
+    xml.Append("<fonts count=\"1\"><font><sz val=\"11\" /><name val=\"Calibri\" /></font></fonts>");
+    xml.Append(
+        "<fills><fill><patternFill patternType=\"none\" /></fill><fill><patternFill patternType=\"gray125\" /></fill></fills>");
+    xml.Append(
+        "<borders><border><left /><right /><top /><bottom /><diagonal /></border></borders>");
+    xml.Append("<cellStyleXfs count=\"1\"><xf numFmtId=\"0\" fontId=\"0\" /></cellStyleXfs>");
+    xml.Append("<cellXfs count=\"1\"><xf numFmtId=\"0\" fontId=\"0\" xfId=\"0\" /></cellXfs>");
+    xml.Append("<cellStyles><cellStyle name=\"Normal\" xfId=\"0\" builtinId=\"0\" /></cellStyles>");
+    xml.Append("<dxfs count=\"0\" />");
+    xml.Append("</styleSheet>");
+
+    var result = new XmlDocument();
+    result.LoadXml(xml.ToString());
+    return result;
+  }
+
+  internal readonly Dictionary<string, SharedStringItem> _sharedStrings = new(); //Used when reading cells.
+  internal List<SharedStringItem> _sharedStringsList = new(); //Used when reading cells.
+  internal ExcelNamedRangeCollection _names;
+  internal int _nextTableID = int.MinValue;
+  internal int _nextPivotTableID = int.MinValue;
+  private readonly XmlNamespaceManager _namespaceManager;
+  private FormulaParser _formulaParser;
+  private FormulaParserManager _parserManager;
+  internal CellStore<List<Token>> _formulaTokens;
+
+  /// <summary>
+  /// Read shared strings to list
+  /// </summary>
+  private void GetSharedStrings() {
+    if (_package.Package.PartExists(SharedStringsUri)) {
+      var xml = _package.GetXmlDocument(SharedStringsUri);
+      XmlNodeList nl = xml.SelectNodes("//d:sst/d:si", NameSpaceManager);
+      _sharedStringsList = new();
+      if (nl != null) {
+        foreach (XmlNode node in nl) {
+          XmlNode n = node.SelectSingleNode("d:t", NameSpaceManager);
+          if (n != null) {
+            _sharedStringsList.Add(
+                new() {
+                  Text = ConvertUtil.ExcelDecodeString(n.InnerText),
+                });
+          } else {
+            _sharedStringsList.Add(
+                new() {
+                  Text = node.InnerXml,
+                  isRichText = true,
+                });
+          }
+        }
+      }
+      //Delete the shared string part, it will be recreated when the package is saved.
+      foreach (var rel in Part.GetRelationships()) {
+        if (rel.TargetUri.OriginalString.EndsWith(
+            "sharedstrings.xml",
+            StringComparison.InvariantCultureIgnoreCase)) {
+          Part.DeleteRelationship(rel.Id);
+          break;
+        }
+      }
+      _package.Package.DeletePart(SharedStringsUri); //Remove the part, it is recreated when saved.
+    }
+  }
+
+  internal void GetDefinedNames() {
+    XmlNodeList nl = WorkbookXml.SelectNodes("//d:definedNames/d:definedName", NameSpaceManager);
+    if (nl != null) {
+      foreach (XmlElement elem in nl) {
+        string fullAddress = elem.InnerText;
+
+        ExcelWorksheet nameWorksheet;
+        if (!int.TryParse(elem.GetAttribute("localSheetId"), out var localSheetId)) {
+          localSheetId = -1;
+          nameWorksheet = null;
+        } else {
+          nameWorksheet = Worksheets[localSheetId + 1];
+        }
+        var addressType = ExcelAddressBase.IsValid(fullAddress);
+        ExcelRangeBase range;
+        ExcelNamedRange namedRange;
+
+        if (fullAddress.IndexOf("[") == 0) {
+          int start = fullAddress.IndexOf("[");
+          int end = fullAddress.IndexOf("]", start);
+          if (start >= 0 && end >= 0) {
+            string externalIndex = fullAddress.Substring(start + 1, end - start - 1);
+            if (int.TryParse(externalIndex, out var index)) {
+              if (index > 0 && index <= _externalReferences.Count) {
+                fullAddress =
+                    fullAddress.Substring(0, start)
+                        + "["
+                        + _externalReferences[index - 1]
+                        + "]"
+                        + fullAddress.Substring(end + 1);
+              }
+            }
+          }
+        }
+
+        if (addressType == ExcelAddressBase.AddressType.Invalid
+            || addressType == ExcelAddressBase.AddressType.InternalName
+            || addressType == ExcelAddressBase.AddressType.ExternalName
+            || addressType == ExcelAddressBase.AddressType.Formula
+            || addressType
+                == ExcelAddressBase
+                    .AddressType
+                    .ExternalAddress) //A value or a formula
+        {
+          range = new(this, nameWorksheet, elem.GetAttribute("name"), true);
+          if (nameWorksheet == null) {
+            namedRange = _names.Add(elem.GetAttribute("name"), range);
+          } else {
+            namedRange = nameWorksheet.Names.Add(elem.GetAttribute("name"), range);
+          }
+
+          if (fullAddress.StartsWith(
+              "\"")) //String value
+          {
+            namedRange.NameValue = fullAddress.Substring(1, fullAddress.Length - 2);
+          } else if (double.TryParse(
+              fullAddress,
+              NumberStyles.Any,
+              CultureInfo.InvariantCulture,
+              out var value)) {
+            namedRange.NameValue = value;
+          } else {
+            //if (addressType == ExcelAddressBase.AddressType.ExternalAddress || addressType == ExcelAddressBase.AddressType.ExternalName)
+            //{
+            //    var r = new ExcelAddress(fullAddress);
+            //    namedRange.NameFormula = '\'[' + r._wb
+            //}
+            //else
+            //{
+            namedRange.NameFormula = fullAddress;
+            //}
+          }
+        } else {
+          ExcelAddress addr = new ExcelAddress(fullAddress, this, null);
+          if (localSheetId > -1) {
+            if (string.IsNullOrEmpty(addr._ws)) {
+              namedRange = Worksheets[localSheetId + 1].Names.Add(
+                  elem.GetAttribute("name"),
+                  new(this, Worksheets[localSheetId + 1], fullAddress, false));
+            } else {
+              namedRange = Worksheets[localSheetId + 1].Names.Add(
+                  elem.GetAttribute("name"),
+                  new(this, Worksheets[addr._ws], fullAddress, false));
+            }
+          } else {
+            var ws = Worksheets[addr._ws];
+            namedRange = _names.Add(elem.GetAttribute("name"), new(this, ws, fullAddress, false));
+          }
+        }
+        if (elem.GetAttribute("hidden") == "1" && namedRange != null) {
+          namedRange.IsNameHidden = true;
+        }
+        if (!string.IsNullOrEmpty(elem.GetAttribute("comment"))) {
+          namedRange.NameComment = elem.GetAttribute("comment");
+        }
+      }
+    }
+  }
+
+  /// <summary>
+  /// Provides access to all the worksheets in the workbook.
+  /// </summary>
+  public ExcelWorksheets Worksheets {
+    get {
+      if (_worksheets == null) {
+        var sheetsNode = WorkbookXml.DocumentElement.SelectSingleNode(
+            "d:sheets",
+            _namespaceManager);
+        if (sheetsNode == null) {
+          sheetsNode = CreateNode("d:sheets");
+        }
+
+        _worksheets = new(_package, this, _namespaceManager, sheetsNode);
+      }
+      return (_worksheets);
+    }
+  }
+
+  /// <summary>
+  /// Provides access to named ranges
+  /// </summary>
+  public ExcelNamedRangeCollection Names => _names;
+
+  internal FormulaParser FormulaParser {
+    get {
+      if (_formulaParser == null) {
+        _formulaParser = new(new EpplusExcelDataProvider(this));
+      }
+      return _formulaParser;
+    }
+  }
+
+  public FormulaParserManager FormulaParserManager {
+    get {
+      if (_parserManager == null) {
+        _parserManager = new(FormulaParser);
+      }
+      return _parserManager;
+    }
+  }
+
+  private ExcelProtection _protection;
+
+  /// <summary>
+  /// Access properties to protect or unprotect a workbook
+  /// </summary>
+  public ExcelProtection Protection => _protection ??= new(NameSpaceManager, TopNode);
+
+  private ExcelWorkbookView _view;
+
+  /// <summary>
+  /// Access to workbook view properties
+  /// </summary>
+  public ExcelWorkbookView View {
+    get {
+      if (_view == null) {
+        _view = new(NameSpaceManager, TopNode, this);
+      }
+      return _view;
+    }
+  }
+
+  /// <summary>
+  /// URI to the workbook inside the package
+  /// </summary>
+  internal static Uri WorkbookUri { get; } = new("/xl/workbook.xml", UriKind.Relative);
+
+  /// <summary>
+  /// URI to the styles inside the package
+  /// </summary>
+  private static Uri StylesUri { get; } = new("/xl/styles.xml", UriKind.Relative);
+
+  /// <summary>
+  /// URI to the shared strings inside the package
+  /// </summary>
+  private static Uri SharedStringsUri { get; } = new("/xl/sharedStrings.xml", UriKind.Relative);
+
+  /// <summary>
+  /// Returns a reference to the workbook's part within the package
+  /// </summary>
+  internal ZipPackagePart Part => (_package.Package.GetPart(WorkbookUri));
+
+  /// <summary>
+  /// Provides access to the XML data representing the workbook in the package.
+  /// </summary>
+  internal XmlDocument WorkbookXml { get; }
+
+  private const string _codeModuleNamePath = "d:workbookPr/@codeName";
+
+  internal string CodeModuleName {
+    get => GetXmlNodeString(_codeModuleNamePath);
+    set => SetXmlNodeString(_codeModuleNamePath, value);
+  }
+
+  internal void CodeNameChange(string value) {
+    CodeModuleName = value;
+  }
+
+  private const string _date1904Path = "d:workbookPr/@date1904";
+  internal const double _date1904Offset = 365.5 * 4; // offset to fix 1900 and 1904 differences, 4 OLE years
+
+  /// <summary>
+  /// The date systems used by Microsoft Excel can be based on one of two different dates. By default, a serial number of 1 in Microsoft Excel represents January 1, 1900.
+  /// The default for the serial number 1 can be changed to represent January 2, 1904.
+  /// This option was included in Microsoft Excel for Windows to make it compatible with Excel for the Macintosh, which defaults to January 2, 1904.
+  /// </summary>
+  public bool Date1904 {
+    get => GetXmlNodeBool(_date1904Path, false);
+    set {
+      if (Date1904 != value) {
+        // Like Excel when the option it's changed update it all cells with Date format
+        foreach (var item in Worksheets) {
+          item.UpdateCellsWithDate1904Setting();
+        }
+      }
+
+      SetXmlNodeBool(_date1904Path, value, false);
+    }
+  }
+
+  private readonly XmlDocument _stylesXml;
+
+  /// <summary>
+  /// Package styles collection. Used internally to access style data.
+  /// </summary>
+  public ExcelStyles Styles {
+    get {
+      if (_styles == null) {
+        _styles = new(NameSpaceManager, _stylesXml, this);
+      }
+      return _styles;
+    }
+  }
+
+  /// <summary>
+  /// The office document properties
+  /// </summary>
+  public OfficeProperties Properties {
+    get {
+      if (_properties == null) {
+        //  Create a NamespaceManager to handle the default namespace,
+        //  and create a prefix for the default namespace:
+        _properties = new(_package, NameSpaceManager);
+      }
+      return _properties;
+    }
+  }
+
+  private readonly string _calcModePath = "d:calcPr/@calcMode";
+
+  /// <summary>
+  /// Calculation mode for the workbook.
+  /// </summary>
+  public ExcelCalcMode CalcMode {
+    get {
+      string calcMode = GetXmlNodeString(_calcModePath);
+      switch (calcMode) {
+        case "autoNoTable":
+          return ExcelCalcMode.AutomaticNoTable;
+        case "manual":
+          return ExcelCalcMode.Manual;
+        default:
+          return ExcelCalcMode.Automatic;
+      }
+    }
+    set {
+      switch (value) {
+        case ExcelCalcMode.AutomaticNoTable:
+          SetXmlNodeString(_calcModePath, "autoNoTable");
+          break;
+        case ExcelCalcMode.Manual:
+          SetXmlNodeString(_calcModePath, "manual");
+          break;
+        default:
+          SetXmlNodeString(_calcModePath, "auto");
+          break;
+      }
+    }
+  }
+
+  private const string _fullCalcOnLoadPath = "d:calcPr/@fullCalcOnLoad";
+
+  /// <summary>
+  /// Should Excel do a full calculation after the workbook has been loaded?
+  /// <remarks>This property is always true for both new workbooks and loaded templates(on load). If this is not the wanted behavior set this property to false.</remarks>
+  /// </summary>
+  public bool FullCalcOnLoad {
+    get => GetXmlNodeBool(_fullCalcOnLoadPath);
+    set => SetXmlNodeBool(_fullCalcOnLoadPath, value);
+  }
+
+  internal void Save() {
+    if (Worksheets.Count == 0) {
+      throw new InvalidOperationException("The workbook must contain at least one worksheet");
+    }
+
+    DeleteCalcChain();
+    UpdateDefinedNamesXml();
+
+    // save the style sheet
+    Styles.UpdateXml();
+
+    // save all the open worksheets
+    var isProtected = Protection.LockWindows || Protection.LockStructure;
+    foreach (ExcelWorksheet worksheet in Worksheets) {
+      if (isProtected && Protection.LockWindows) {
+        worksheet.View.WindowProtection = true;
+      }
+      worksheet.Save();
+    }
+
+    _package.Package.CreatePart(
+        SharedStringsUri,
+        ExcelPackage._contentTypeSharedString,
+        SaveSharedStringHandler);
+    Part.CreateRelationship(
+        UriHelper.GetRelativeUri(WorkbookUri, SharedStringsUri),
+        TargetMode.Internal,
+        ExcelPackage._schemaRelationships + "/sharedStrings");
+
+    // Data validation
+    ValidateDataValidations();
+  }
+
+  private void DeleteCalcChain() {
+    //Remove the calc chain if it exists.
+    Uri uriCalcChain = new Uri("/xl/calcChain.xml", UriKind.Relative);
+    if (_package.Package.PartExists(uriCalcChain)) {
+      Uri calcChain = new Uri("calcChain.xml", UriKind.Relative);
+      foreach (var relationship in Part.GetRelationships()) {
+        if (relationship.TargetUri == calcChain) {
+          Part.DeleteRelationship(relationship.Id);
+          break;
+        }
+      }
+      // delete the calcChain part
+      _package.Package.DeletePart(uriCalcChain);
+    }
+  }
+
+  private void ValidateDataValidations() {
+    foreach (var sheet in Worksheets) {
+      if (!(sheet is ExcelChartsheet)) {
+        sheet.DataValidations.ValidateAll();
+      }
+    }
+  }
+
+  private void SaveSharedStringHandler(StreamWriter sw) {
+    var cache = new StringBuilder();
+    cache.AppendFormat(
+        "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><sst xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" count=\"{0}\" uniqueCount=\"{0}\">",
+        _sharedStrings.Count);
+    foreach (string t in _sharedStrings.Keys) {
+      SharedStringItem ssi = _sharedStrings[t];
+      if (ssi.isRichText) {
+        cache.Append("<si>");
+        ConvertUtil.ExcelEncodeString(cache, t);
+        cache.Append("</si>");
+      } else {
+        if (t.Length > 0
+            && (t[0] == ' '
+                    || t[t.Length - 1] == ' '
+                    || t.Contains("  ")
+                    || t.Contains("\t")
+                    || t.Contains("\n")
+                    || t.Contains(
+                        "\n"))) //Fixes issue 14849
+        {
+          cache.Append("<si><t xml:space=\"preserve\">");
+        } else {
+          cache.Append("<si><t>");
+        }
+        ConvertUtil.ExcelEncodeString(cache, ConvertUtil.ExcelEscapeString(t));
+        cache.Append("</t></si>");
+      }
+      if (cache.Length > 0x600000) {
+        sw.Write(cache.ToString());
+        cache = new();
+      }
+    }
+    cache.Append("</sst>");
+    sw.Write(cache.ToString());
+    sw.Flush();
+    Part.CreateRelationship(
+        UriHelper.GetRelativeUri(WorkbookUri, SharedStringsUri),
+        TargetMode.Internal,
+        ExcelPackage._schemaRelationships + "/sharedStrings");
+  }
+
+  private void UpdateDefinedNamesXml() {
+    try {
+      XmlNode top = WorkbookXml.SelectSingleNode("//d:definedNames", NameSpaceManager);
+      if (!ExistsNames()) {
+        if (top != null) {
+          TopNode.RemoveChild(top);
+        }
+        return;
+      }
+      if (top == null) {
+        CreateNode("d:definedNames");
+        top = WorkbookXml.SelectSingleNode("//d:definedNames", NameSpaceManager);
+      } else {
+        top.RemoveAll();
+      }
+      foreach (ExcelNamedRange name in _names) {
+        XmlElement elem = WorkbookXml.CreateElement("definedName", ExcelPackage._schemaMain);
+        top.AppendChild(elem);
+        elem.SetAttribute("name", name.Name);
+        if (name.IsNameHidden) {
+          elem.SetAttribute("hidden", "1");
+        }
+        if (!string.IsNullOrEmpty(name.NameComment)) {
+          elem.SetAttribute("comment", name.NameComment);
+        }
+        SetNameElement(name, elem);
+      }
+      foreach (ExcelWorksheet ws in _worksheets) {
+        if (!(ws is ExcelChartsheet)) {
+          foreach (ExcelNamedRange name in ws.Names) {
+            XmlElement elem = WorkbookXml.CreateElement("definedName", ExcelPackage._schemaMain);
+            top.AppendChild(elem);
+            elem.SetAttribute("name", name.Name);
+            elem.SetAttribute("localSheetId", name.LocalSheetId.ToString());
+            if (name.IsNameHidden) {
+              elem.SetAttribute("hidden", "1");
+            }
+            if (!string.IsNullOrEmpty(name.NameComment)) {
+              elem.SetAttribute("comment", name.NameComment);
+            }
+            SetNameElement(name, elem);
+          }
+        }
+      }
+    } catch (Exception ex) {
+      throw new("Internal error updating named ranges ", ex);
+    }
+  }
+
+  private void SetNameElement(ExcelNamedRange name, XmlElement elem) {
+    if (name.IsName) {
+      if (string.IsNullOrEmpty(name.NameFormula)) {
+        if ((name.NameValue.GetType().IsPrimitive
+                    || name.NameValue is double
+                    || name.NameValue is decimal)) {
+          elem.InnerText = Convert
+              .ToDouble(name.NameValue, CultureInfo.InvariantCulture)
+              .ToString("R15", CultureInfo.InvariantCulture);
+        } else if (name.NameValue is DateTime time) {
+          elem.InnerText = time.ToOADate().ToString(CultureInfo.InvariantCulture);
+        } else {
+          elem.InnerText = "\"" + name.NameValue + "\"";
+        }
+      } else {
+        elem.InnerText = name.NameFormula;
+      }
+    } else {
+      elem.InnerText = name.FullAddressAbsolute;
+    }
+  }
+
+  /// <summary>
+  /// Is their any names in the workbook or in the sheets.
+  /// </summary>
+  /// <returns>?</returns>
+  private bool ExistsNames() {
+    if (_names.Count == 0) {
+      foreach (ExcelWorksheet ws in Worksheets) {
+        if (ws is ExcelChartsheet) {
+          continue;
+        }
+        if (ws.Names.Count > 0) {
+          return true;
+        }
+      }
+    } else {
+      return true;
+    }
+    return false;
+  }
+
+  internal bool ExistsTableName(string name) {
+    foreach (var ws in Worksheets) {
+      if (ws.Tables._tableNames.ContainsKey(name)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  internal bool ExistsPivotTableName(string name) {
+    foreach (var ws in Worksheets) {
+      if (ws.PivotTables._pivotTableNames.ContainsKey(name)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  internal void AddPivotTable(string cacheId, Uri defUri) {
+    CreateNode("d:pivotCaches");
+
+    XmlElement item = WorkbookXml.CreateElement("pivotCache", ExcelPackage._schemaMain);
+    item.SetAttribute("cacheId", cacheId);
+    var rel = Part.CreateRelationship(
+        UriHelper.ResolvePartUri(WorkbookUri, defUri),
+        TargetMode.Internal,
+        ExcelPackage._schemaRelationships + "/pivotCacheDefinition");
+    item.SetAttribute("id", ExcelPackage._schemaRelationships, rel.Id);
+
+    var pivotCaches = WorkbookXml.SelectSingleNode("//d:pivotCaches", NameSpaceManager);
+    pivotCaches.AppendChild(item);
+  }
+
+  internal List<string> _externalReferences = new();
+
+  //internal bool _isCalculated=false;
+  internal void GetExternalReferences() {
+    XmlNodeList nl = WorkbookXml.SelectNodes(
+        "//d:externalReferences/d:externalReference",
+        NameSpaceManager);
+    if (nl != null) {
+      foreach (XmlElement elem in nl) {
+        string rId = elem.GetAttribute("r:id");
+        var rel = Part.GetRelationship(rId);
+        var part = _package.Package.GetPart(UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri));
+        XmlDocument xmlExtRef = new XmlDocument();
+        LoadXmlSafe(xmlExtRef, part.GetStream());
+
+        XmlElement book =
+            xmlExtRef.SelectSingleNode("//d:externalBook", NameSpaceManager) as XmlElement;
+        if (book != null) {
+          string rIdExtRef = book.GetAttribute("r:id");
+          var relExtRef = part.GetRelationship(rIdExtRef);
+          if (relExtRef != null) {
+            _externalReferences.Add(relExtRef.TargetUri.OriginalString);
+          }
+        }
+      }
+    }
+  }
+
+  internal void ReadAllTables() {
+    if (_nextTableID > 0) {
+      return;
+    }
+    _nextTableID = 1;
+    _nextPivotTableID = 1;
+    foreach (var ws in Worksheets) {
+      if (!(ws
+                  is ExcelChartsheet)) //Fixes 15273. Chartsheets should be ignored.
+      {
+        foreach (var tbl in ws.Tables) {
+          if (tbl.Id >= _nextTableID) {
+            _nextTableID = tbl.Id + 1;
+          }
+        }
+        foreach (var pt in ws.PivotTables) {
+          if (pt.CacheID >= _nextPivotTableID) {
+            _nextPivotTableID = pt.CacheID + 1;
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/AppsheetEpplus/ExcelWorkbookView.cs b/AppsheetEpplus/ExcelWorkbookView.cs
new file mode 100644
index 0000000..263bddb
--- /dev/null
+++ b/AppsheetEpplus/ExcelWorkbookView.cs
@@ -0,0 +1,162 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		    Initial Release		       2011-11-02
+ * Jan Källman		    License changed GPL-->LGPL 2011-12-27
+ *******************************************************************************/
+
+using System.Collections.Immutable;
+using System.Globalization;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Access to workbook view properties
+/// </summary>
+public class ExcelWorkbookView : XmlHelper {
+  protected override ImmutableArray<string> SchemaNodeOrder =>
+    ExcelWorkbook.WorkbookSchemaNodeOrder;
+
+  /// <summary>
+  /// Creates a new ExcelWorkbookView which provides access to all the
+  /// view states of the worksheet.
+  /// </summary>
+  /// <param name="ns"></param>
+  /// <param name="node"></param>
+  /// <param name="wb"></param>
+  internal ExcelWorkbookView(XmlNamespaceManager ns, XmlNode node, ExcelWorkbook wb)
+      : base(ns, node) {}
+
+  private const string _leftPath = "d:bookViews/d:workbookView/@xWindow";
+
+  /// <summary>
+  /// Position of the upper left corner of the workbook window. In twips.
+  /// </summary>
+  public int Left {
+    get => GetXmlNodeInt(_leftPath);
+    internal set => SetXmlNodeString(_leftPath, value.ToString());
+  }
+
+  private const string _topPath = "d:bookViews/d:workbookView/@yWindow";
+
+  /// <summary>
+  /// Position of the upper left corner of the workbook window. In twips.
+  /// </summary>
+  public int Top {
+    get => GetXmlNodeInt(_topPath);
+    internal set => SetXmlNodeString(_topPath, value.ToString());
+  }
+
+  private const string _widthPath = "d:bookViews/d:workbookView/@windowWidth";
+
+  /// <summary>
+  /// Width of the workbook window. In twips.
+  /// </summary>
+  public int Width {
+    get => GetXmlNodeInt(_widthPath);
+    internal set => SetXmlNodeString(_widthPath, value.ToString());
+  }
+
+  private const string _heightPath = "d:bookViews/d:workbookView/@windowHeight";
+
+  /// <summary>
+  /// Height of the workbook window. In twips.
+  /// </summary>
+  public int Height {
+    get => GetXmlNodeInt(_heightPath);
+    internal set => SetXmlNodeString(_heightPath, value.ToString());
+  }
+
+  private const string _minimizedPath = "d:bookViews/d:workbookView/@minimized";
+
+  /// <summary>
+  /// If true the the workbook window is minimized.
+  /// </summary>
+  public bool Minimized {
+    get => GetXmlNodeBool(_minimizedPath);
+    set => SetXmlNodeString(_minimizedPath, value.ToString());
+  }
+
+  private const string _showverticalscrollPath = "d:bookViews/d:workbookView/@showVerticalScroll";
+
+  /// <summary>
+  /// Show the vertical scrollbar
+  /// </summary>
+  public bool ShowVerticalScrollBar {
+    get => GetXmlNodeBool(_showverticalscrollPath, true);
+    set => SetXmlNodeBool(_showverticalscrollPath, value, true);
+  }
+
+  private const string _showhorizontalscrPath = "d:bookViews/d:workbookView/@showHorizontalScroll";
+
+  /// <summary>
+  /// Show the horizontal scrollbar
+  /// </summary>
+  public bool ShowHorizontalScrollBar {
+    get => GetXmlNodeBool(_showhorizontalscrPath, true);
+    set => SetXmlNodeBool(_showhorizontalscrPath, value, true);
+  }
+
+  private const string _showsheettabsPath = "d:bookViews/d:workbookView/@showSheetTabs";
+
+  /// <summary>
+  /// Show the sheet tabs
+  /// </summary>
+  public bool ShowSheetTabs {
+    get => GetXmlNodeBool(_showsheettabsPath, true);
+    set => SetXmlNodeBool(_showsheettabsPath, value, true);
+  }
+
+  /// <summary>
+  /// Set the window position in twips
+  /// </summary>
+  /// <param name="left"></param>
+  /// <param name="top"></param>
+  /// <param name="width"></param>
+  /// <param name="height"></param>
+  public void SetWindowSize(int left, int top, int width, int height) {
+    Left = left;
+    Top = top;
+    Width = width;
+    Height = height;
+  }
+
+  private const string _activetabPath = "d:bookViews/d:workbookView/@activeTab";
+
+  public int ActiveTab {
+    get {
+      var v = GetXmlNodeInt(_activetabPath);
+      if (v < 0) {
+        return 0;
+      }
+      return v;
+    }
+    set => SetXmlNodeString(_activetabPath, value.ToString(CultureInfo.InvariantCulture));
+  }
+}
diff --git a/AppsheetEpplus/ExcelWorksheet.cs b/AppsheetEpplus/ExcelWorksheet.cs
new file mode 100644
index 0000000..2031fe3
--- /dev/null
+++ b/AppsheetEpplus/ExcelWorksheet.cs
@@ -0,0 +1,3227 @@
+/*******************************************************************************
+* You may amend and distribute as you like, but don't remove this header!
+*
+* EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+* See http://www.codeplex.com/EPPlus for details.
+*
+* Copyright (C) 2011  Jan Källman
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU Lesser General Public License for more details.
+*
+* The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+* If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+*
+* All code and executables are provided "as is" with no warranty either express or implied.
+* The author accepts no liability for any damage or loss of business that this product may cause.
+*
+* Code change notes:
+*
+* Author							Change						Date
+* ******************************************************************************
+* Jan Källman		    Initial Release		        2011-11-02
+* Jan Källman          Total rewrite               2010-03-01
+* Jan Källman		    License changed GPL-->LGPL  2011-12-27
+*******************************************************************************/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.ComponentModel;
+using System.Globalization;
+using System.IO;
+using System.Security;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Worksheet hidden enumeration
+/// </summary>
+public enum eWorkSheetHidden {
+  /// <summary>
+  /// The worksheet is visible
+  /// </summary>
+  Visible,
+
+  /// <summary>
+  /// The worksheet is hidden but can be shown by the user via the user interface
+  /// </summary>
+  Hidden,
+
+  /// <summary>
+  /// The worksheet is hidden and cannot be shown by the user via the user interface
+  /// </summary>
+  VeryHidden,
+}
+
+[Flags]
+internal enum CellFlags {
+  //Merged = 0x1,
+  RichText = 0x2,
+  SharedFormula = 0x4,
+  ArrayFormula = 0x8,
+}
+
+/// <summary>
+/// Represents an Excel Chartsheet and provides access to its properties and methods
+/// </summary>
+public class ExcelChartsheet : ExcelWorksheet {
+  public ExcelChartsheet(
+      XmlNamespaceManager ns,
+      ExcelPackage pck,
+      ExcelWorkbook workbook,
+      Uri worksheetUri,
+      string name,
+      int sheetId,
+      int positionId,
+      eWorkSheetHidden hidden)
+      : base(ns, pck, workbook, worksheetUri, name, sheetId, positionId, hidden) {}
+}
+
+/// <summary>
+/// Represents an Excel worksheet and provides access to its properties and methods
+/// </summary>
+public class ExcelWorksheet : XmlHelper, IEqualityComparer<ExcelWorksheet> {
+  internal class Formulas {
+    public Formulas(ISourceCodeTokenizer tokenizer) {
+      _tokenizer = tokenizer;
+    }
+
+    public static string RemoveDummyFunction(string formula) {
+      const string dummyFunctionConcatenate = "\"&\"";
+      const string dummyFunctionPrefix = "IFERROR(__xludf.DUMMYFUNCTION(\"";
+      const string dummyFunctionSuffix = "\"),";
+
+      if (string.IsNullOrEmpty(formula)) {
+        return formula;
+      }
+
+      // Look for Prefix
+      if (!formula.StartsWith(dummyFunctionPrefix)) {
+        return formula;
+      }
+
+      // Look for Suffix
+      int index = formula.LastIndexOf(dummyFunctionSuffix);
+      if (index < 0) {
+        return formula;
+      }
+
+      // Trim Suffix
+      formula = formula.Substring(0, index);
+
+      // Trim Prefix
+      formula = formula.Replace(dummyFunctionPrefix, "");
+
+      // Remove string concatentations from long formulas.
+      // Google break the quoted string into 254 character segments which are concatenated.
+      if (formula.Length >= 254) {
+        formula = formula.Replace(dummyFunctionConcatenate, "");
+      }
+
+      // Replace doubled quotes with single quote
+      formula = formula.Replace("\"\"", "\"");
+
+      // Return formula
+      return formula;
+    }
+
+    private readonly ISourceCodeTokenizer _tokenizer;
+
+    internal int Index { get; set; }
+
+    internal string Address { get; set; }
+
+    internal bool IsArray { get; set; }
+
+    public string Formula { get; set; }
+
+    public int StartRow { get; set; }
+
+    public int StartCol { get; set; }
+
+    private IEnumerable<Token> Tokens { get; set; }
+
+    internal string GetFormula(int row, int column, string worksheet) {
+      if ((StartRow == row && StartCol == column) || IsArray) {
+        return RemoveDummyFunction(Formula);
+      }
+
+      if (Tokens == null) {
+        Tokens = _tokenizer.Tokenize(RemoveDummyFunction(Formula), worksheet);
+      }
+
+      string f = "";
+      foreach (var token in Tokens) {
+        if (token.TokenType == TokenType.ExcelAddress) {
+          var a = new ExcelFormulaAddress(token.Value);
+          f += a.GetOffset(row - StartRow, column - StartCol);
+        } else {
+          f += token.Value;
+        }
+      }
+      return f;
+    }
+  }
+
+  /// <summary>
+  /// Collection containing merged cell addresses
+  /// </summary>
+  public class MergeCellsCollection : IEnumerable<string> {
+    internal MergeCellsCollection() {}
+
+    internal readonly CellStore<int> _cells = new();
+    private readonly List<string> _list = [];
+
+    internal List<string> List => _list;
+
+    public string this[int row, int column] {
+      get {
+        int ix = -1;
+        if (_cells.Exists(row, column, ref ix)
+            && ix >= 0
+            && ix
+                < List.Count) //Fixes issue 15075
+        {
+          return List[ix];
+        }
+        return null;
+      }
+    }
+
+    public string this[int index] => _list[index];
+
+    internal void Add(ExcelAddressBase address, bool doValidate) {
+      //Validate
+      if (doValidate && Validate(address) == false) {
+        throw (new ArgumentException("Can't merge and already merged range"));
+      }
+      var ix = _list.Count;
+      _list.Add(address.Address);
+      SetIndex(address, ix);
+    }
+
+    private bool Validate(ExcelAddressBase address) {
+      int ix = 0;
+      if (_cells.Exists(address._fromRow, address._fromCol, ref ix)) {
+        if (ix >= 0 && ix < _list.Count && _list[ix] != null && address.Address == _list[ix]) {
+          return true;
+        }
+        return false;
+      }
+
+      var cse = new CellsStoreEnumerator<int>(
+          _cells,
+          address._fromRow,
+          address._fromCol,
+          address._toRow,
+          address._toCol);
+      //cells
+      while (cse.Next()) {
+        return false;
+      }
+      //Entire column
+      cse = new(_cells, 0, address._fromCol, 0, address._toCol);
+      while (cse.Next()) {
+        return false;
+      }
+      //Entire row
+      cse = new(_cells, address._fromRow, 0, address._toRow, 0);
+      while (cse.Next()) {
+        return false;
+      }
+      return true;
+    }
+
+    internal void SetIndex(ExcelAddressBase address, int ix) {
+      if (address._fromRow == 1
+          && address._toRow
+              == ExcelPackage.MaxRows) //Entire row
+      {
+        for (int col = address._fromCol; col <= address._toCol; col++) {
+          _cells.SetValue(0, col, ix);
+        }
+      } else if (address._fromCol == 1
+          && address._toCol
+              == ExcelPackage.MaxColumns) //Entire row
+      {
+        for (int row = address._fromRow; row <= address._toRow; row++) {
+          _cells.SetValue(row, 0, ix);
+        }
+      } else {
+        for (int col = address._fromCol; col <= address._toCol; col++) {
+          for (int row = address._fromRow; row <= address._toRow; row++) {
+            _cells.SetValue(row, col, ix);
+          }
+        }
+      }
+    }
+
+    public int Count => _list.Count;
+
+    internal void Remove(string item) {
+      _list.Remove(item);
+    }
+
+    public IEnumerator<string> GetEnumerator() {
+      return _list.GetEnumerator();
+    }
+
+    IEnumerator IEnumerable.GetEnumerator() {
+      return _list.GetEnumerator();
+    }
+
+    internal void Clear(ExcelAddressBase destination) {
+      var cse = new CellsStoreEnumerator<int>(
+          _cells,
+          destination._fromRow,
+          destination._fromCol,
+          destination._toRow,
+          destination._toCol);
+      var used = new HashSet<int>();
+      while (cse.Next()) {
+        var v = cse.Value;
+        if (!used.Contains(v) && _list[v] != null) {
+          var adr = new ExcelAddressBase(_list[v]);
+          if (!(destination.Collide(adr) == ExcelAddressBase.eAddressCollition.Inside
+                      || destination.Collide(adr) == ExcelAddressBase.eAddressCollition.Equal)) {
+            throw (new InvalidOperationException(
+                    string.Format(
+                        "Can't delete merged cells. A range is partly merged with the deleted range. {0}",
+                        adr._address)));
+          }
+          used.Add(v);
+        }
+      }
+
+      _cells.Clear(
+          destination._fromRow,
+          destination._fromCol,
+          destination._toRow - destination._fromRow + 1,
+          destination._toCol - destination._fromCol + 1);
+      foreach (var i in used) {
+        _list[i] = null;
+      }
+    }
+  }
+
+  internal readonly CellStore<object> _values = new();
+  internal readonly CellStore<string> _types = new();
+  internal readonly CellStore<int> _styles = new();
+  internal readonly CellStore<object> _formulas = new();
+  internal readonly FlagCellStore _flags = new();
+  internal CellStore<List<Token>> _formulaTokens;
+
+  internal readonly CellStore<Uri> _hyperLinks = new();
+  internal readonly CellStore<ExcelComment> _commentsStore = new();
+
+  internal readonly Dictionary<int, Formulas> _sharedFormulas = new();
+
+  internal readonly ExcelPackage _package;
+  private readonly ExcelWorkbook _workbook;
+  private ExcelWorksheetView _sheetView;
+
+  internal static ImmutableArray<string> WorksheetSchemaNodeOrder = [
+    "sheetPr",
+    "tabColor",
+    "outlinePr",
+    "pageSetUpPr",
+    "dimension",
+    "sheetViews",
+    "sheetFormatPr",
+    "cols",
+    "sheetData",
+    "sheetProtection",
+    "protectedRanges",
+    "scenarios",
+    "autoFilter",
+    "sortState",
+    "dataConsolidate",
+    "customSheetViews",
+    "customSheetViews",
+    "mergeCells",
+    "phoneticPr",
+    "conditionalFormatting",
+    "dataValidations",
+    "hyperlinks",
+    "printOptions",
+    "pageMargins",
+    "pageSetup",
+    "headerFooter",
+    "linePrint",
+    "rowBreaks",
+    "colBreaks",
+    "customProperties",
+    "cellWatches",
+    "ignoredErrors",
+    "smartTags",
+    "drawing",
+    "legacyDrawing",
+    "legacyDrawingHF",
+    "picture",
+    "oleObjects",
+    "activeXControls",
+    "webPublishItems",
+    "tableParts",
+    "extLst",
+  ];
+
+  protected override ImmutableArray<string> SchemaNodeOrder => WorksheetSchemaNodeOrder;
+
+  internal ExcelWorksheet(
+      XmlNamespaceManager ns,
+      ExcelPackage excelPackage,
+      ExcelWorkbook workbook,
+      Uri worksheetUri,
+      string name,
+      int sheetId,
+      int positionId,
+      eWorkSheetHidden hidden)
+      : base(ns, null) {
+    _workbook = workbook;
+    _package = excelPackage;
+    _names = new(Workbook, this);
+
+    Hidden = hidden;
+    Name = name;
+    PositionID = positionId;
+    SheetID = sheetId;
+
+    Part = _package.Package.GetPart(worksheetUri);
+    Part.SaveHandler = SaveHandler;
+
+    // First Columns, rows, cells, mergecells, hyperlinks and pagebreakes are loaded from an
+    // XmlTextReader to optimize speed.
+    using var stream = Part.GetStream();
+    var xr = new XmlTextReader(stream);
+    xr.ProhibitDtd = true;
+    xr.WhitespaceHandling = WhitespaceHandling.None;
+    LoadColumns(xr); //columnXml
+    long start = stream.Position;
+    LoadCells(xr);
+    var nextElementLength = GetAttributeLength(xr);
+    long end = stream.Position - nextElementLength;
+    LoadMergeCells(xr);
+    LoadHyperLinks(xr);
+    LoadRowPageBreakes(xr);
+    LoadColPageBreakes(xr);
+
+    // Then the rest of the XML is extracted and loaded into the WorksheetXml document.
+    stream.Seek(0, SeekOrigin.Begin);
+    var xml = GetWorkSheetXml(stream, start, end, out var encoding);
+
+    //first char is invalid sometimes??
+    if (xml[0] != '<') {
+      LoadXmlSafe(WorksheetXml, xml.Substring(1, xml.Length - 1), encoding);
+    } else {
+      LoadXmlSafe(WorksheetXml, xml, encoding);
+    }
+    ClearNodes();
+
+    TopNode = WorksheetXml.DocumentElement;
+  }
+
+  /// <summary>
+  /// The Zip.ZipPackagePart for the worksheet within the package
+  /// </summary>
+  internal ZipPackagePart Part { get; }
+
+  /// <summary>
+  /// The unique identifier for the worksheet.
+  /// </summary>
+  internal int SheetID { get; }
+
+  /// <summary>
+  /// The position of the worksheet.
+  /// </summary>
+  internal int PositionID { get; }
+
+  /// <summary>
+  /// Address for autofilter
+  /// <seealso cref="ExcelRangeBase.AutoFilter" />
+  /// </summary>
+  public ExcelAddressBase AutoFilterAddress {
+    get {
+      CheckSheetType();
+      string address = GetXmlNodeString("d:autoFilter/@ref");
+      if (address == "") {
+        return null;
+      }
+      return new(address);
+    }
+    internal set {
+      CheckSheetType();
+      SetXmlNodeString("d:autoFilter/@ref", value.Address);
+    }
+  }
+
+  internal void CheckSheetType() {
+    if (this is ExcelChartsheet) {
+      throw (new NotSupportedException(
+              "This property or method is not supported for a Chartsheet"));
+    }
+  }
+
+  /// <summary>
+  /// Returns a ExcelWorksheetView object that allows you to set the view state properties of the worksheet
+  /// </summary>
+  public ExcelWorksheetView View {
+    get {
+      if (_sheetView == null) {
+        XmlNode node = TopNode.SelectSingleNode("d:sheetViews/d:sheetView", NameSpaceManager);
+        if (node == null) {
+          CreateNode("d:sheetViews/d:sheetView"); //this one shouls always exist. but check anyway
+          node = TopNode.SelectSingleNode("d:sheetViews/d:sheetView", NameSpaceManager);
+        }
+        _sheetView = new(NameSpaceManager, node, this);
+      }
+      return (_sheetView);
+    }
+  }
+
+  /// <summary>
+  /// The worksheet's display name as it appears on the tab
+  /// </summary>
+  public string Name { get; }
+
+  private readonly ExcelNamedRangeCollection _names;
+
+  /// <summary>
+  /// Provides access to named ranges
+  /// </summary>
+  public ExcelNamedRangeCollection Names {
+    get {
+      CheckSheetType();
+      return _names;
+    }
+  }
+
+  /// <summary>
+  /// Indicates if the worksheet is hidden in the workbook
+  /// </summary>
+  public eWorkSheetHidden Hidden {
+    get {
+      string state = _workbook.GetXmlNodeString(
+          string.Format("d:sheets/d:sheet[@sheetId={0}]/@state", SheetID));
+      if (state == "hidden") {
+        return eWorkSheetHidden.Hidden;
+      }
+      if (state == "veryHidden") {
+        return eWorkSheetHidden.VeryHidden;
+      }
+      return eWorkSheetHidden.Visible;
+    }
+    set {
+      if (value == eWorkSheetHidden.Visible) {
+        _workbook.DeleteNode(string.Format("d:sheets/d:sheet[@sheetId={0}]/@state", SheetID));
+      } else {
+        string v;
+        v = value.ToString();
+        v = v.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + v.Substring(1);
+        _workbook.SetXmlNodeString(
+            string.Format("d:sheets/d:sheet[@sheetId={0}]/@state", SheetID),
+            v);
+      }
+    }
+  }
+
+  private double _defaultRowHeight = double.NaN;
+
+  /// <summary>
+  /// Get/set the default height of all rows in the worksheet
+  /// </summary>
+  public double DefaultRowHeight {
+    get {
+      CheckSheetType();
+      if (double.IsNaN(_defaultRowHeight)) {
+        _defaultRowHeight = GetXmlNodeDouble("d:sheetFormatPr/@defaultRowHeight");
+        if (double.IsNaN(_defaultRowHeight)) {
+          _defaultRowHeight = 15; // Excel default height
+        }
+      }
+      return _defaultRowHeight;
+    }
+    set {
+      CheckSheetType();
+      _defaultRowHeight = value;
+      SetXmlNodeString(
+          "d:sheetFormatPr/@defaultRowHeight",
+          value.ToString(CultureInfo.InvariantCulture));
+      SetXmlNodeBool("d:sheetFormatPr/@customHeight", value != 15);
+
+      if (double.IsNaN(GetXmlNodeDouble("d:sheetFormatPr/@defaultColWidth"))) {
+        DefaultColWidth = 9.140625;
+      }
+    }
+  }
+
+  /// <summary>
+  /// Get/set the default width of all rows in the worksheet
+  /// </summary>
+  public double DefaultColWidth {
+    get {
+      CheckSheetType();
+      double ret = GetXmlNodeDouble("d:sheetFormatPr/@defaultColWidth");
+      if (double.IsNaN(ret)) {
+        ret = 9.140625; // Excel's default width
+      }
+      return ret;
+    }
+    set {
+      CheckSheetType();
+      SetXmlNodeString(
+          "d:sheetFormatPr/@defaultColWidth",
+          value.ToString(CultureInfo.InvariantCulture));
+
+      if (double.IsNaN(GetXmlNodeDouble("d:sheetFormatPr/@defaultRowHeight"))) {
+        DefaultRowHeight = 15;
+      }
+    }
+  }
+
+  /** <outlinePr applyStyles="1" summaryBelow="0" summaryRight="0" /> **/
+  private const string _outLineSummaryBelowPath = "d:sheetPr/d:outlinePr/@summaryBelow";
+
+  /// <summary>
+  /// Summary rows below details
+  /// </summary>
+  public bool OutLineSummaryBelow {
+    get {
+      CheckSheetType();
+      return GetXmlNodeBool(_outLineSummaryBelowPath);
+    }
+    set {
+      CheckSheetType();
+      SetXmlNodeString(_outLineSummaryBelowPath, value ? "1" : "0");
+    }
+  }
+
+  private const string _outLineSummaryRightPath = "d:sheetPr/d:outlinePr/@summaryRight";
+
+  /// <summary>
+  /// Summary rows to right of details
+  /// </summary>
+  public bool OutLineSummaryRight {
+    get {
+      CheckSheetType();
+      return GetXmlNodeBool(_outLineSummaryRightPath);
+    }
+    set {
+      CheckSheetType();
+      SetXmlNodeString(_outLineSummaryRightPath, value ? "1" : "0");
+    }
+  }
+
+  private const string _outLineApplyStylePath = "d:sheetPr/d:outlinePr/@applyStyles";
+
+  /// <summary>
+  /// Automatic styles
+  /// </summary>
+  public bool OutLineApplyStyle {
+    get {
+      CheckSheetType();
+      return GetXmlNodeBool(_outLineApplyStylePath);
+    }
+    set {
+      CheckSheetType();
+      SetXmlNodeString(_outLineApplyStylePath, value ? "1" : "0");
+    }
+  }
+
+  private const string _codeModuleNamePath = "d:sheetPr/@codeName";
+
+  internal string CodeModuleName {
+    get => GetXmlNodeString(_codeModuleNamePath);
+    set => SetXmlNodeString(_codeModuleNamePath, value);
+  }
+
+  /// <summary>
+  /// The XML document holding the worksheet data.
+  /// All column, row, cell, pagebreak, merged cell and hyperlink-data are loaded into memory and removed from the document when loading the document.
+  /// </summary>
+  internal XmlDocument WorksheetXml { get; } = new();
+
+  internal ExcelVmlDrawingCommentCollection _vmlDrawings;
+
+  /// <summary>
+  /// Vml drawings. underlaying object for comments
+  /// </summary>
+  internal ExcelVmlDrawingCommentCollection VmlDrawingsComments {
+    get {
+      if (_vmlDrawings == null) {
+        CreateVmlCollection();
+      }
+      return _vmlDrawings;
+    }
+  }
+
+  internal ExcelCommentCollection _comments;
+
+  /// <summary>
+  /// Collection of comments
+  /// </summary>
+  public ExcelCommentCollection Comments {
+    get {
+      CheckSheetType();
+      if (_comments == null) {
+        CreateVmlCollection();
+        _comments = new(_package, this, NameSpaceManager);
+      }
+      return _comments;
+    }
+  }
+
+  private void CreateVmlCollection() {
+    var vmlNode = WorksheetXml.DocumentElement.SelectSingleNode(
+        "d:legacyDrawing/@r:id",
+        NameSpaceManager);
+    if (vmlNode == null) {
+      _vmlDrawings = new(_package, this, null);
+    } else {
+      if (Part.RelationshipExists(vmlNode.Value)) {
+        var rel = Part.GetRelationship(vmlNode.Value);
+        var vmlUri = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri);
+
+        _vmlDrawings = new(_package, this, vmlUri);
+        _vmlDrawings.RelId = rel.Id;
+      }
+    }
+  }
+
+  /// <summary>
+  /// Get the lenth of the attributes
+  /// Conditional formatting attributes can be extremly long som get length of the attributes to finetune position.
+  /// </summary>
+  /// <param name="xr"></param>
+  /// <returns></returns>
+  private int GetAttributeLength(XmlTextReader xr) {
+    if (xr.NodeType != XmlNodeType.Element) {
+      return 0;
+    }
+    var length = 0;
+
+    for (int i = 0; i < xr.AttributeCount; i++) {
+      var a = xr.GetAttribute(i);
+      length += string.IsNullOrEmpty(a) ? 0 : a.Length;
+    }
+    return length;
+  }
+
+  private void LoadRowPageBreakes(XmlTextReader xr) {
+    if (!ReadUntil(xr, "rowBreaks", "colBreaks")) {
+      return;
+    }
+    while (xr.Read()) {
+      if (xr.LocalName == "brk") {
+        if (xr.NodeType == XmlNodeType.Element) {
+          if (int.TryParse(xr.GetAttribute("id"), out var id)) {
+            Row(id).PageBreak = true;
+          }
+        }
+      } else {
+        break;
+      }
+    }
+  }
+
+  private void LoadColPageBreakes(XmlTextReader xr) {
+    if (!ReadUntil(xr, "colBreaks")) {
+      return;
+    }
+    while (xr.Read()) {
+      if (xr.LocalName == "brk") {
+        if (xr.NodeType == XmlNodeType.Element) {
+          if (int.TryParse(xr.GetAttribute("id"), out var id)) {
+            Column(id).PageBreak = true;
+          }
+        }
+      } else {
+        break;
+      }
+    }
+  }
+
+  private void ClearNodes() {
+    if (WorksheetXml.SelectSingleNode("//d:cols", NameSpaceManager) != null) {
+      WorksheetXml.SelectSingleNode("//d:cols", NameSpaceManager).RemoveAll();
+    }
+    if (WorksheetXml.SelectSingleNode("//d:mergeCells", NameSpaceManager) != null) {
+      WorksheetXml.SelectSingleNode("//d:mergeCells", NameSpaceManager).RemoveAll();
+    }
+    if (WorksheetXml.SelectSingleNode("//d:hyperlinks", NameSpaceManager) != null) {
+      WorksheetXml.SelectSingleNode("//d:hyperlinks", NameSpaceManager).RemoveAll();
+    }
+    if (WorksheetXml.SelectSingleNode("//d:rowBreaks", NameSpaceManager) != null) {
+      WorksheetXml.SelectSingleNode("//d:rowBreaks", NameSpaceManager).RemoveAll();
+    }
+    if (WorksheetXml.SelectSingleNode("//d:colBreaks", NameSpaceManager) != null) {
+      WorksheetXml.SelectSingleNode("//d:colBreaks", NameSpaceManager).RemoveAll();
+    }
+  }
+
+  private const int _blocksize = 8192;
+
+  private string GetWorkSheetXml(Stream stream, long start, long end, out Encoding encoding) {
+    StreamReader sr = new StreamReader(stream);
+    int length = 0;
+    char[] block;
+    int pos;
+    StringBuilder sb = new StringBuilder();
+    Match startmMatch,
+        endMatch;
+    do {
+      int size = stream.Length < _blocksize ? (int)stream.Length : _blocksize;
+      block = new char[size];
+      pos = sr.ReadBlock(block, 0, size);
+      sb.Append(block, 0, pos);
+      length += size;
+    } while (length < start + 20 && length < end);
+    startmMatch = Regex.Match(sb.ToString(), string.Format("(<[^>]*{0}[^>]*>)", "sheetData"));
+    if (!startmMatch.Success) //Not found
+    {
+      encoding = sr.CurrentEncoding;
+      return sb.ToString();
+    }
+    string s = sb.ToString();
+    string xml = s.Substring(0, startmMatch.Index);
+    if (startmMatch.Value.EndsWith("/>")) {
+      xml += s.Substring(startmMatch.Index, s.Length - startmMatch.Index);
+    } else {
+      if (sr.Peek() != -1) {
+        /**** Fixes issue 14788. Fix by Philip Garrett ****/
+        long endSeekStart = end;
+
+        while (endSeekStart >= 0) {
+          endSeekStart = Math.Max(endSeekStart - _blocksize, 0);
+          int size = (int)(end - endSeekStart);
+          stream.Seek(endSeekStart, SeekOrigin.Begin);
+          block = new char[size];
+          sr = new(stream);
+          pos = sr.ReadBlock(block, 0, size);
+          sb = new();
+          sb.Append(block, 0, pos);
+          s = sb.ToString();
+          endMatch = Regex.Match(s, string.Format("(</[^>]*{0}[^>]*>)", "sheetData"));
+          if (endMatch.Success) {
+            break;
+          }
+        }
+      }
+      endMatch = Regex.Match(s, string.Format("(</[^>]*{0}[^>]*>)", "sheetData"));
+      xml +=
+          "<sheetData/>"
+              + s.Substring(
+                  endMatch.Index + endMatch.Length,
+                  s.Length - (endMatch.Index + endMatch.Length));
+    }
+    if (sr.Peek() > -1) {
+      xml += sr.ReadToEnd();
+    }
+
+    encoding = sr.CurrentEncoding;
+    return xml;
+  }
+
+  private void GetBlockPos(string xml, string tag, ref int start, ref int end) {
+    Match startmMatch,
+        endMatch;
+    startmMatch = Regex.Match(xml.Substring(start), string.Format("(<[^>]*{0}[^>]*>)", tag)); //"<[a-zA-Z:]*" + tag + "[?]*>");
+
+    if (!startmMatch.Success) //Not found
+    {
+      start = -1;
+      end = -1;
+      return;
+    }
+    var startPos = startmMatch.Index + start;
+    if (startmMatch.Value.Substring(startmMatch.Value.Length - 2, 1) == "/") {
+      end = startPos + startmMatch.Length;
+    } else {
+      endMatch = Regex.Match(xml.Substring(start), string.Format("(</[^>]*{0}[^>]*>)", tag));
+      if (endMatch.Success) {
+        end = endMatch.Index + endMatch.Length + start;
+      }
+    }
+    start = startPos;
+  }
+
+  private bool ReadUntil(XmlTextReader xr, params string[] tagName) {
+    if (xr.EOF) {
+      return false;
+    }
+    while (!Array.Exists(tagName, tag => xr.LocalName.EndsWith(tag))) {
+      xr.Read();
+      if (xr.EOF) {
+        return false;
+      }
+    }
+    return (xr.LocalName.EndsWith(tagName[0]));
+  }
+
+  private void LoadColumns(
+      XmlTextReader xr) //(string xml)
+  {
+    var colList = new List<IRangeId>();
+    if (ReadUntil(xr, "cols", "sheetData")) {
+      //if (xml != "")
+      //{
+      //var xr=new XmlTextReader(new StringReader(xml));
+      while (xr.Read()) {
+        if (xr.NodeType == XmlNodeType.Whitespace) {
+          continue;
+        }
+        if (xr.LocalName != "col") {
+          break;
+        }
+        if (xr.NodeType == XmlNodeType.Element) {
+          int min = int.Parse(xr.GetAttribute("min"));
+
+          ExcelColumn col = new ExcelColumn(this, min);
+
+          col.ColumnMax = int.Parse(xr.GetAttribute("max"));
+          col.Width =
+              xr.GetAttribute("width") == null
+                  ? 0
+                  : double.Parse(xr.GetAttribute("width"), CultureInfo.InvariantCulture);
+          col.BestFit =
+              xr.GetAttribute("bestFit") != null && xr.GetAttribute("bestFit") == "1"
+                  ? true
+                  : false;
+          col.Collapsed =
+              xr.GetAttribute("collapsed") != null && xr.GetAttribute("collapsed") == "1"
+                  ? true
+                  : false;
+          col.Phonetic =
+              xr.GetAttribute("phonetic") != null && xr.GetAttribute("phonetic") == "1"
+                  ? true
+                  : false;
+          col.OutlineLevel = (short)(xr.GetAttribute("outlineLevel") == null
+              ? 0
+              : int.Parse(xr.GetAttribute("outlineLevel"), CultureInfo.InvariantCulture));
+          col.Hidden =
+              xr.GetAttribute("hidden") != null && xr.GetAttribute("hidden") == "1" ? true : false;
+          _values.SetValue(0, min, col);
+
+          if (!(xr.GetAttribute("style") == null
+                      || !int.TryParse(xr.GetAttribute("style"), out var style))) {
+            _styles.SetValue(0, min, style);
+          }
+        }
+      }
+    }
+  }
+
+  /// <summary>
+  /// Load Hyperlinks
+  /// </summary>
+  /// <param name="xr">The reader</param>
+  private void LoadHyperLinks(XmlTextReader xr) {
+    if (!ReadUntil(xr, "hyperlinks", "rowBreaks", "colBreaks")) {
+      return;
+    }
+    while (xr.Read()) {
+      if (xr.LocalName == "hyperlink") {
+        ExcelCellBase.GetRowColFromAddress(
+            xr.GetAttribute("ref"),
+            out var fromRow,
+            out var fromCol,
+            out int toRow,
+            out var toCol);
+        ExcelHyperLink hl = null;
+        if (xr.GetAttribute("id", ExcelPackage._schemaRelationships) != null) {
+          var rId = xr.GetAttribute("id", ExcelPackage._schemaRelationships);
+          var uri = Part.GetRelationship(rId).TargetUri;
+
+          // Get Location, if any.  EPPlus Bug 15517
+          var location = xr.GetAttribute("location");
+          location = (string.IsNullOrEmpty(location)) ? "" : "#" + location;
+
+          if (uri.IsAbsoluteUri) {
+            try {
+              hl = new(uri.AbsoluteUri + location);
+            } catch {
+              hl = new(uri.OriginalString + location, UriKind.Absolute);
+            }
+          } else {
+            hl = new(uri.OriginalString + location, UriKind.Relative);
+          }
+
+          hl.RId = rId;
+          Part.DeleteRelationship(rId); //Delete the relationship, it is recreated when we save the package.
+        } else if (xr.GetAttribute("location") != null) {
+          hl = new(xr.GetAttribute("location"), xr.GetAttribute("display"));
+          hl.RowSpann = toRow - fromRow;
+          hl.ColSpann = toCol - fromCol;
+        }
+
+        string tt = xr.GetAttribute("tooltip");
+        if (!string.IsNullOrEmpty(tt)) {
+          hl.ToolTip = tt;
+        }
+        _hyperLinks.SetValue(fromRow, fromCol, hl);
+      } else {
+        break;
+      }
+    }
+  }
+
+  /// <summary>
+  /// Load cells
+  /// </summary>
+  /// <param name="xr">The reader</param>
+  private void LoadCells(XmlTextReader xr) {
+    //var cellList=new List<IRangeID>();
+    //var rowList = new List<IRangeID>();
+    //var formulaList = new List<IRangeID>();
+    ReadUntil(xr, "sheetData", "mergeCells", "hyperlinks", "rowBreaks", "colBreaks");
+    ExcelAddressBase address = null;
+    string type = "";
+    int style = 0;
+    int row = 0;
+    int col = 0;
+    xr.Read();
+
+    while (!xr.EOF) {
+      while (xr.NodeType == XmlNodeType.EndElement) {
+        xr.Read();
+      }
+      if (xr.LocalName == "row") {
+        var r = xr.GetAttribute("r");
+        if (r == null) {
+          row++;
+        } else {
+          row = Convert.ToInt32(r);
+        }
+
+        if (DoAddRow(xr)) {
+          _values.SetValue(row, 0, AddRow(xr, row));
+          if (xr.GetAttribute("s") != null) {
+            _styles.SetValue(row, 0, int.Parse(xr.GetAttribute("s"), CultureInfo.InvariantCulture));
+          }
+        }
+        xr.Read();
+      } else if (xr.LocalName == "c") {
+        //if (cell != null) cellList.Add(cell);
+        //cell = new ExcelCell(this, xr.GetAttribute("r"));
+        var r = xr.GetAttribute("r");
+        if (r == null) {
+          //Handle cells with no reference
+          col++;
+          address = new(row, col, row, col);
+        } else {
+          address = new(r);
+          col = address._fromCol;
+        }
+
+        //Datetype
+        if (xr.GetAttribute("t") != null) {
+          type = xr.GetAttribute("t");
+          _types.SetValue(address._fromRow, address._fromCol, type);
+        } else {
+          type = "";
+        }
+        //Style
+        if (xr.GetAttribute("s") != null) {
+          style = int.Parse(xr.GetAttribute("s"));
+          _styles.SetValue(address._fromRow, address._fromCol, style);
+          _values.SetValue(address._fromRow, address._fromCol, null); //TODO:Better Performance ??
+        } else {
+          style = 0;
+        }
+        xr.Read();
+      } else if (xr.LocalName == "v") {
+        SetValueFromXml(xr, type, style, address._fromRow, address._fromCol);
+
+        xr.Read();
+      } else if (xr.LocalName == "f") {
+        string t = xr.GetAttribute("t");
+        if (t == null) {
+          _formulas.SetValue(address._fromRow, address._fromCol, xr.ReadElementContentAsString());
+          _values.SetValue(address._fromRow, address._fromCol, null);
+          //formulaList.Add(cell);
+        } else if (t == "shared") {
+          string si = xr.GetAttribute("si");
+          if (si != null) {
+            var sfIndex = int.Parse(si);
+            _formulas.SetValue(address._fromRow, address._fromCol, sfIndex);
+            _values.SetValue(address._fromRow, address._fromCol, null);
+            string fAddress = xr.GetAttribute("ref");
+            string formula = ConvertUtil.ExcelDecodeString(xr.ReadElementContentAsString());
+            if (formula != "") {
+              _sharedFormulas.Add(
+                  sfIndex,
+                  new(SourceCodeTokenizer.Default) {
+                    Index = sfIndex,
+                    Formula = formula,
+                    Address = fAddress,
+                    StartRow = address._fromRow,
+                    StartCol = address._fromCol,
+                  });
+            }
+          } else {
+            xr.Read(); //Something is wrong in the sheet, read next
+          }
+        } else if (t
+            == "array") //TODO: Array functions are not support yet. Read the formula for the start cell only.
+        {
+          string aAddress = xr.GetAttribute("ref");
+          ExcelRange addressRange = new ExcelRange(this, aAddress);
+          string formula = xr.ReadElementContentAsString();
+          bool isIndexMatchFormula =
+              Regex.IsMatch(formula, @"INDEX\(", RegexOptions.IgnoreCase)
+                  && Regex.IsMatch(formula, @"MATCH\(", RegexOptions.IgnoreCase)
+                  && !aAddress.Contains(":");
+          if (isIndexMatchFormula) {
+            addressRange.IsArrayFormula = false;
+            for (int colIndex = addressRange.Start.Column;
+                colIndex <= addressRange.End.Column;
+                colIndex++) {
+              for (int rowIndex = addressRange.Start.Row;
+                  rowIndex <= addressRange.End.Row;
+                  rowIndex++) {
+                var afIndex = GetMaxShareFunctionIndex(true);
+                _formulas.SetValue(rowIndex, colIndex, afIndex);
+                _values.SetValue(rowIndex, colIndex, null);
+                _sharedFormulas.Add(
+                    afIndex,
+                    new(SourceCodeTokenizer.Default) {
+                      Index = afIndex,
+                      Formula = formula,
+                      Address = aAddress,
+                      StartRow = address._fromRow,
+                      StartCol = address._fromCol,
+                      IsArray = false,
+                    });
+              }
+            }
+          } else {
+            addressRange.IsArrayFormula = true;
+            var afIndex = GetMaxShareFunctionIndex(true);
+            for (int colIndex = addressRange.Start.Column;
+                colIndex <= addressRange.End.Column;
+                colIndex++) {
+              for (int rowIndex = addressRange.Start.Row;
+                  rowIndex <= addressRange.End.Row;
+                  rowIndex++) {
+                _formulas.SetValue(rowIndex, colIndex, afIndex);
+                _values.SetValue(rowIndex, colIndex, null);
+              }
+            }
+            _sharedFormulas.Add(
+                afIndex,
+                new(SourceCodeTokenizer.Default) {
+                  Index = afIndex,
+                  Formula = formula,
+                  Address = aAddress,
+                  StartRow = address._fromRow,
+                  StartCol = address._fromCol,
+                  IsArray = true,
+                });
+          }
+        } else // ??? some other type
+        {
+          xr.Read(); //Something is wrong in the sheet, read next
+        }
+      } else if (xr.LocalName
+          == "is") //Inline string
+      {
+        xr.Read();
+        if (xr.LocalName == "t") {
+          _values.SetValue(
+              address._fromRow,
+              address._fromCol,
+              ConvertUtil.ExcelDecodeString(xr.ReadElementContentAsString()));
+          //cell._value = xr.ReadInnerXml();
+        } else {
+          _values.SetValue(address._fromRow, address._fromCol, xr.ReadOuterXml());
+          _types.SetValue(address._fromRow, address._fromCol, "rt");
+          _flags.SetFlagValue(address._fromRow, address._fromCol, true, CellFlags.RichText);
+          //cell.IsRichText = true;
+        }
+      } else {
+        break;
+      }
+    }
+  }
+
+  private bool DoAddRow(XmlTextReader xr) {
+    var c = xr.GetAttribute("r") == null ? 0 : 1;
+    if (xr.GetAttribute("spans") != null) {
+      c++;
+    }
+    return xr.AttributeCount > c;
+  }
+
+  /// <summary>
+  /// Load merged cells
+  /// </summary>
+  /// <param name="xr"></param>
+  private void LoadMergeCells(XmlTextReader xr) {
+    if (ReadUntil(xr, "mergeCells", "hyperlinks", "rowBreaks", "colBreaks") && !xr.EOF) {
+      while (xr.Read()) {
+        if (xr.LocalName != "mergeCell") {
+          break;
+        }
+        if (xr.NodeType == XmlNodeType.Element) {
+          string address = xr.GetAttribute("ref");
+          _mergedCells.Add(new ExcelAddress(address), false);
+        }
+      }
+    }
+  }
+
+  /// <summary>
+  /// Update merged cells
+  /// </summary>
+  /// <param name="sw">The writer</param>
+  private void UpdateMergedCells(StreamWriter sw) {
+    sw.Write("<mergeCells>");
+    foreach (string address in _mergedCells) {
+      sw.Write("<mergeCell ref=\"{0}\" />", address);
+    }
+    sw.Write("</mergeCells>");
+  }
+
+  /// <summary>
+  /// Reads a row from the XML reader
+  /// </summary>
+  /// <param name="xr">The reader</param>
+  /// <param name="row">The row number</param>
+  /// <returns></returns>
+  private RowInternal AddRow(XmlTextReader xr, int row) {
+    return new() {
+      Collapsed =
+          (xr.GetAttribute("collapsed") != null && xr.GetAttribute("collapsed") == "1"
+              ? true
+              : false),
+      OutlineLevel =
+          (xr.GetAttribute("outlineLevel") == null
+              ? (short)0
+              : short.Parse(xr.GetAttribute("outlineLevel"), CultureInfo.InvariantCulture)),
+      Height =
+          (xr.GetAttribute("ht") == null
+              ? -1
+              : double.Parse(xr.GetAttribute("ht"), CultureInfo.InvariantCulture)),
+      Hidden =
+          (xr.GetAttribute("hidden") != null && xr.GetAttribute("hidden") == "1" ? true : false),
+      Phonetic = xr.GetAttribute("ph") != null && xr.GetAttribute("ph") == "1" ? true : false,
+      CustomHeight =
+          xr.GetAttribute("customHeight") == null ? false : xr.GetAttribute("customHeight") == "1",
+    };
+  }
+
+  private static readonly DateTime _excelEpoch = new(1899, 12, 30);
+
+  public static DateTime IncorrectDurationFromOaDate(double value) {
+    // This behavior is wrong. Real OADate values have a discontinuity on 30 December 1899.
+    // For real OADate values, the negative sign applies only to the integer portion of
+    // the float, *not* to the decimal portion. For example, -0.5 and 0.5 both refer to the
+    // same date, and -1.5 is actually 1899-12-29 12:00 (1 day before 1899-12-30 00:00
+    // plus 0.5 days), *not* 1899-12-28 12:00 (1.5 days before 1899-12-30 00:00).
+    //
+    // Unfortunately, AppSheet's duration-handling code gets this very wrong, and treats the
+    // duration as the offset from 1899-12-30 00:00. This is correct for positive durations,
+    // but it's wrong for negative durations. This code tries to fix the bug that exists in
+    // AppSheet's duration-handling code here, and it succeeds in some cases and fails in
+    // others.
+    //
+    // This code also breaks date/time handling for dates before 1899-12-30 00:00 in some
+    // cases. Specifically, dates end up being offset by one day.
+    //
+    // Regardless, changing this behavior is risky, so this code simply replicates the
+    // existing behavior for
+    if (value >= 0) {
+      return DateTime.FromOADate(value);
+    }
+    // This looks like a very complicated way to call TimeSpan.FromDays(value), but
+    // TimeSpan.FromDays actually only guarantees millisecond precision, and critically
+    // rounding is different on .NET Core, resulting in values like (e.g.) 3:15:00 being
+    // incorrectly rounded.
+    var offset = DateTime.FromOADate(-value) - _excelEpoch;
+    return _excelEpoch - offset;
+  }
+
+  private void SetValueFromXml(XmlTextReader xr, string type, int styleId, int row, int col) {
+    //XmlNode vnode = colNode.SelectSingleNode("d:v", NameSpaceManager);
+    //if (vnode == null) return null;
+    if (type == "s") {
+      int ix = xr.ReadElementContentAsInt();
+
+      // Temporary debugging code to locate intermittent 'Index was out of range' exception.
+      if (ix < 0) {
+        throw new(
+            string.Format(
+                "ReadElementContentAsInt returned value '{0}' which is less than zero.",
+                ix));
+      }
+      if (ix >= _workbook._sharedStringsList.Count) {
+        throw new(
+            string.Format(
+                "ReadElementContentAsInt returned index value '{0}' which is greater than _sharedStringsList count of {1}.",
+                ix,
+                _workbook._sharedStringsList.Count));
+      }
+
+      _values.SetValue(row, col, _workbook._sharedStringsList[ix].Text);
+      if (_workbook._sharedStringsList[ix].isRichText) {
+        _flags.SetFlagValue(row, col, true, CellFlags.RichText);
+      }
+    } else if (type == "str") {
+      _values.SetValue(row, col, ConvertUtil.ExcelDecodeString(xr.ReadElementContentAsString()));
+    } else if (type == "b") {
+      _values.SetValue(row, col, (xr.ReadElementContentAsString() != "0"));
+    } else if (type == "e") {
+      _values.SetValue(row, col, GetErrorType(xr.ReadElementContentAsString()));
+    } else {
+      string v = xr.ReadElementContentAsString();
+      var nf = Workbook.Styles.CellXfs[styleId].NumberFormatId;
+      if ((nf >= 20 && nf <= 21)
+          || (nf >= 45
+                  && nf
+                      <= 47)) // Duration
+      {
+        if (double.TryParse(v, NumberStyles.Any, CultureInfo.InvariantCulture, out var res)) {
+          if (Workbook.Date1904) {
+            res += ExcelWorkbook._date1904Offset;
+          }
+          if (res >= -657435.0 && res < 2958465.9999999) {
+            // Get the Duration value expressed as a DateTime.
+            _values.SetValue(row, col, IncorrectDurationFromOaDate(res));
+          } else {
+            // Cope with Google Sheets export of cells having a formula.
+            // Rather than exporting the native value, they export the formatted value.
+            _values.SetValue(row, col, v);
+          }
+        } else {
+          // Cope with Google Sheets export of cells having a formula.
+          // Rather than exporting the native value, they export the formatted value.
+          _values.SetValue(row, col, v);
+        }
+      } else if ((nf >= 14 && nf <= 19)
+          || (nf
+                  == 22)) // DateTime
+      {
+        if (double.TryParse(v, NumberStyles.Any, CultureInfo.InvariantCulture, out var res)) {
+          if (Workbook.Date1904) {
+            res += ExcelWorkbook._date1904Offset;
+          }
+          if (res >= -657435.0 && res < 2958465.9999999) {
+            _values.SetValue(row, col, DateTime.FromOADate(res));
+          } else {
+            // Cope with Google Sheets export of cells having a formula.
+            // Rather than exporting the native value, they export the formatted value.
+            _values.SetValue(row, col, v);
+          }
+        } else {
+          // Cope with Google Sheets export of cells having a formula.
+          // Rather than exporting the native value, they export the formatted value.
+          _values.SetValue(row, col, v);
+        }
+      } else {
+        if (double.TryParse(v, NumberStyles.Any, CultureInfo.InvariantCulture, out var d)) {
+          _values.SetValue(row, col, d);
+        } else {
+          // Cope with Google Sheets export of cells having a formula.
+          // Rather than exporting the native value, they export the formatted value.
+          _values.SetValue(row, col, v);
+
+          //_values.SetValue(row, col, double.NaN);
+        }
+      }
+    }
+  }
+
+  private object GetErrorType(string v) {
+    return ExcelErrorValue.Parse(v.ToUpper(CultureInfo.InvariantCulture));
+    //switch(v.ToUpper())
+    //{
+    //    case "#DIV/0!":
+    //        return new ExcelErrorValue.cre(eErrorType.Div0);
+    //    case "#REF!":
+    //        return new ExcelErrorValue(eErrorType.Ref);
+    //    case "#N/A":
+    //        return new ExcelErrorValue(eErrorType.NA);
+    //    case "#NAME?":
+    //        return new ExcelErrorValue(eErrorType.Name);
+    //    case "#NULL!":
+    //        return new ExcelErrorValue(eErrorType.Null);
+    //    case "#NUM!":
+    //        return new ExcelErrorValue(eErrorType.Num);
+    //    default:
+    //        return new ExcelErrorValue(eErrorType.Value);
+    //}
+  }
+
+  ///// <summary>
+  ///// Provides access to an individual cell within the worksheet.
+  ///// </summary>
+  ///// <param name="row">The row number in the worksheet</param>
+  ///// <param name="col">The column number in the worksheet</param>
+  ///// <returns></returns>
+  //internal ExcelCell Cell(int row, int col)
+  //{
+  //    return new ExcelCell(_values, row, col);
+  //}
+  /// <summary>
+  /// Provides access to a range of cells
+  /// </summary>
+  public ExcelRange Cells {
+    get {
+      CheckSheetType();
+      return new(this, 1, 1, ExcelPackage.MaxRows, ExcelPackage.MaxColumns);
+    }
+  }
+
+  /// <summary>
+  /// Provides access to the selected range of cells
+  /// </summary>
+  public ExcelRange SelectedRange {
+    get {
+      CheckSheetType();
+      return new(this, View.SelectedRange);
+    }
+  }
+
+  private readonly MergeCellsCollection _mergedCells = new();
+
+  /// <summary>
+  /// Addresses to merged ranges
+  /// </summary>
+  public MergeCellsCollection MergedCells {
+    get {
+      CheckSheetType();
+      return _mergedCells;
+    }
+  }
+
+  /// <summary>
+  /// Provides access to an individual row within the worksheet so you can set its properties.
+  /// </summary>
+  /// <param name="row">The row number in the worksheet</param>
+  /// <returns></returns>
+  public ExcelRow Row(int row) {
+    //ExcelRow r;
+    //ulong id = ExcelRow.GetRowID(_sheetID, row);
+    //TODO: Fixa.
+    //var v = _values.GetValue(row, 0);
+    //if (v!=null)
+    //{
+    //    var ri=(RowInternal)v;
+    //    r = new ExcelRow(this, row)
+    //}
+    //else
+    //{
+    //r = new ExcelRow(this, row);
+    //_values.SetValue(row, 0, r);
+    //_rows.Add(r);
+    //}
+    CheckSheetType();
+    if (row < 1 || row > ExcelPackage.MaxRows) {
+      throw (new ArgumentException("Row number out of bounds"));
+    }
+    return new(this, row);
+    //return r;
+  }
+
+  /// <summary>
+  /// Provides access to an individual column within the worksheet so you can set its properties.
+  /// </summary>
+  /// <param name="col">The column number in the worksheet</param>
+  /// <returns></returns>
+  public ExcelColumn Column(int col) {
+    CheckSheetType();
+    if (col < 1 || col > ExcelPackage.MaxColumns) {
+      throw (new ArgumentException("Column number out of bounds"));
+    }
+    var column = _values.GetValue(0, col) as ExcelColumn;
+    if (column != null) {
+      if (column.ColumnMin != column.ColumnMax) {
+        int maxCol = column.ColumnMax;
+        column.ColumnMax = col;
+        ExcelColumn copy = CopyColumn(column, col + 1, maxCol);
+      }
+    } else {
+      int r = 0,
+          c = col;
+      if (_values.PrevCell(ref r, ref c)) {
+        column = _values.GetValue(0, c) as ExcelColumn;
+        int maxCol = column.ColumnMax;
+        if (maxCol >= col) {
+          column.ColumnMax = col - 1;
+          if (maxCol > col) {
+            ExcelColumn newC = CopyColumn(column, col + 1, maxCol);
+          }
+          return CopyColumn(column, col, col);
+        }
+      }
+      //foreach (ExcelColumn checkColumn in _columns)
+      //{
+      //    if (col > checkColumn.ColumnMin && col <= checkColumn.ColumnMax)
+      //    {
+      //        int maxCol = checkColumn.ColumnMax;
+      //        checkColumn.ColumnMax = col - 1;
+      //        if (maxCol > col)
+      //        {
+      //            ExcelColumn newC = CopyColumn(checkColumn, col + 1, maxCol);
+      //        }
+      //        return CopyColumn(checkColumn, col,col);
+      //    }
+      //}
+      column = new(this, col);
+      _values.SetValue(0, col, column);
+      //_columns.Add(column);
+    }
+    return column;
+  }
+
+  /// <summary>
+  /// Returns the name of the worksheet
+  /// </summary>
+  /// <returns>The name of the worksheet</returns>
+  public override string ToString() {
+    return Name;
+  }
+
+  internal ExcelColumn CopyColumn(ExcelColumn c, int col, int maxCol) {
+    ExcelColumn newC = new ExcelColumn(this, col);
+    newC.ColumnMax = maxCol < ExcelPackage.MaxColumns ? maxCol : ExcelPackage.MaxColumns;
+    if (c.StyleName != "") {
+      newC.StyleName = c.StyleName;
+    } else {
+      newC.StyleID = c.StyleID;
+    }
+
+    newC.OutlineLevel = c.OutlineLevel;
+    newC.Phonetic = c.Phonetic;
+    newC.BestFit = c.BestFit;
+    //_columns.Add(newC);
+    _values.SetValue(0, col, newC);
+    newC._width = c._width;
+    newC._hidden = c._hidden;
+    return newC;
+  }
+
+  /// <summary>
+  /// Make the current worksheet active.
+  /// </summary>
+  public void Select() {
+    View.TabSelected = true;
+    //Select(Address, true);
+  }
+
+  /// <summary>
+  /// Selects a range in the worksheet. The active cell is the topmost cell.
+  /// Make the current worksheet active.
+  /// </summary>
+  /// <param name="address">An address range</param>
+  public void Select(string address) {
+    Select(address, true);
+  }
+
+  /// <summary>
+  /// Selects a range in the worksheet. The actice cell is the topmost cell.
+  /// </summary>
+  /// <param name="address">A range of cells</param>
+  /// <param name="selectSheet">Make the sheet active</param>
+  public void Select(string address, bool selectSheet) {
+    CheckSheetType();
+    int toCol,
+        toRow;
+    //Get rows and columns and validate as well
+    ExcelCellBase.GetRowColFromAddress(
+        address,
+        out var fromRow,
+        out var fromCol,
+        out toRow,
+        out toCol);
+
+    if (selectSheet) {
+      View.TabSelected = true;
+    }
+    View.SelectedRange = address;
+    View.ActiveCell = ExcelCellBase.GetAddress(fromRow, fromCol);
+  }
+
+  /// <summary>
+  /// Selects a range in the worksheet. The active cell is the topmost cell of the first address.
+  /// Make the current worksheet active.
+  /// </summary>
+  /// <param name="address">An address range</param>
+  public void Select(ExcelAddress address) {
+    CheckSheetType();
+    Select(address, true);
+  }
+
+  /// <summary>
+  /// Selects a range in the worksheet. The active cell is the topmost cell of the first address.
+  /// </summary>
+  /// <param name="address">A range of cells</param>
+  /// <param name="selectSheet">Make the sheet active</param>
+  public void Select(ExcelAddress address, bool selectSheet) {
+    CheckSheetType();
+    if (selectSheet) {
+      View.TabSelected = true;
+    }
+    string selAddress =
+        ExcelCellBase.GetAddress(address.Start.Row, address.Start.Column)
+            + ":"
+            + ExcelCellBase.GetAddress(address.End.Row, address.End.Column);
+    if (address.Addresses != null) {
+      foreach (var a in address.Addresses) {
+        selAddress +=
+            " "
+                + ExcelCellBase.GetAddress(a.Start.Row, a.Start.Column)
+                + ":"
+                + ExcelCellBase.GetAddress(a.End.Row, a.End.Column);
+      }
+    }
+    View.SelectedRange = selAddress;
+    View.ActiveCell = ExcelCellBase.GetAddress(address.Start.Row, address.Start.Column);
+  }
+
+  /// <summary>
+  /// Inserts a new row into the spreadsheet.  Existing rows below the position are
+  /// shifted down.  All formula are updated to take account of the new row.
+  /// </summary>
+  /// <param name="rowFrom">The position of the new row</param>
+  /// <param name="rows">Number of rows to insert</param>
+  public void InsertRow(int rowFrom, int rows) {
+    InsertRow(rowFrom, rows, 0);
+  }
+
+  /// <summary>
+  /// Inserts a new row into the spreadsheet.  Existing rows below the position are
+  /// shifted down.  All formula are updated to take account of the new row.
+  /// </summary>
+  /// <param name="rowFrom">The position of the new row</param>
+  /// <param name="rows">Number of rows to insert.</param>
+  /// <param name="copyStylesFromRow">Copy Styles from this row. Applied to all inserted rows</param>
+  public void InsertRow(int rowFrom, int rows, int copyStylesFromRow) {
+    CheckSheetType();
+    var d = Dimension;
+
+    if (rowFrom < 1) {
+      throw (new ArgumentOutOfRangeException("rowFrom can't be lesser that 1"));
+    }
+
+    //Check that cells aren't shifted outside the boundries
+    if (d != null && d.End.Row > rowFrom && d.End.Row + rows > ExcelPackage.MaxRows) {
+      throw (new ArgumentOutOfRangeException(
+              "Can't insert. Rows will be shifted outside the boundries of the worksheet."));
+    }
+
+    _values.Insert(rowFrom, 0, rows, 0);
+    _formulas.Insert(rowFrom, 0, rows, 0);
+    _styles.Insert(rowFrom, 0, rows, 0);
+    _types.Insert(rowFrom, 0, rows, 0);
+    _commentsStore.Insert(rowFrom, 0, rows, 0);
+    _hyperLinks.Insert(rowFrom, 0, rows, 0);
+    _flags.Insert(rowFrom, 0, rows, 0);
+
+    foreach (var f in _sharedFormulas.Values) {
+      if (f.StartRow >= rowFrom) {
+        f.StartRow += rows;
+      }
+      var a = new ExcelAddressBase(f.Address);
+      if (a._fromRow >= rowFrom) {
+        a._fromRow += rows;
+        a._toRow += rows;
+      } else if (a._toRow >= rowFrom) {
+        a._toRow += rows;
+      }
+      f.Address = ExcelCellBase.GetAddress(a._fromRow, a._fromCol, a._toRow, a._toCol);
+      f.Formula = ExcelCellBase.UpdateFormulaReferences(f.Formula, rows, 0, rowFrom, 0);
+    }
+    var cse = new CellsStoreEnumerator<object>(_formulas);
+    while (cse.Next()) {
+      if (cse.Value is string) {
+        cse.Value = ExcelCellBase.UpdateFormulaReferences(
+            cse.Value.ToString(),
+            rows,
+            0,
+            rowFrom,
+            0);
+      }
+    }
+
+    FixMergedCellsRow(rowFrom, rows, false);
+    if (copyStylesFromRow > 0) {
+      var cseS = new CellsStoreEnumerator<int>(
+          _styles,
+          copyStylesFromRow,
+          0,
+          copyStylesFromRow,
+          ExcelPackage.MaxColumns); //Fixes issue 15068 , 15090
+      while (cseS.Next()) {
+        for (var r = 0; r < rows; r++) {
+          _styles.SetValue(rowFrom + r, cseS.Column, cseS.Value);
+        }
+      }
+    }
+    foreach (var tbl in Tables) {
+      tbl.Address = tbl.Address.AddRow(rowFrom, rows);
+    }
+  }
+
+  /// <summary>
+  /// Inserts a new column into the spreadsheet.  Existing columns below the position are
+  /// shifted down.  All formula are updated to take account of the new column.
+  /// </summary>
+  /// <param name="columnFrom">The position of the new column</param>
+  /// <param name="columns">Number of columns to insert</param>
+  public void InsertColumn(int columnFrom, int columns) {
+    InsertColumn(columnFrom, columns, 0);
+  }
+
+  ///<summary>
+  /// Inserts a new column into the spreadsheet.  Existing column to the left are
+  /// shifted.  All formula are updated to take account of the new column.
+  /// </summary>
+  /// <param name="columnFrom">The position of the new column</param>
+  /// <param name="columns">Number of columns to insert.</param>
+  /// <param name="copyStylesFromColumn">Copy Styles from this column. Applied to all inserted columns</param>
+  public void InsertColumn(int columnFrom, int columns, int copyStylesFromColumn) {
+    CheckSheetType();
+    var d = Dimension;
+
+    if (columnFrom < 1) {
+      throw (new ArgumentOutOfRangeException("columnFrom can't be lesser that 1"));
+    }
+    //Check that cells aren't shifted outside the boundries
+    if (d != null
+        && d.End.Column > columnFrom
+        && d.End.Column + columns > ExcelPackage.MaxColumns) {
+      throw (new ArgumentOutOfRangeException(
+              "Can't insert. Columns will be shifted outside the boundries of the worksheet."));
+    }
+
+    _values.Insert(0, columnFrom, 0, columns);
+    _formulas.Insert(0, columnFrom, 0, columns);
+    _styles.Insert(0, columnFrom, 0, columns);
+    _types.Insert(0, columnFrom, 0, columns);
+    _commentsStore.Insert(0, columnFrom, 0, columns);
+    _hyperLinks.Insert(0, columnFrom, 0, columns);
+    _flags.Insert(0, columnFrom, 0, columns);
+
+    foreach (var f in _sharedFormulas.Values) {
+      if (f.StartCol >= columnFrom) {
+        f.StartCol += columns;
+      }
+      var a = new ExcelAddressBase(f.Address);
+      if (a._fromCol >= columnFrom) {
+        a._fromCol += columns;
+        a._toCol += columns;
+      } else if (a._toCol >= columnFrom) {
+        a._toCol += columns;
+      }
+      f.Address = ExcelCellBase.GetAddress(a._fromRow, a._fromCol, a._toRow, a._toCol);
+      f.Formula = ExcelCellBase.UpdateFormulaReferences(f.Formula, 0, columns, 0, columnFrom);
+    }
+
+    var cse = new CellsStoreEnumerator<object>(_formulas);
+    while (cse.Next()) {
+      if (cse.Value is string) {
+        cse.Value = ExcelCellBase.UpdateFormulaReferences(
+            cse.Value.ToString(),
+            0,
+            columns,
+            0,
+            columnFrom);
+      }
+    }
+
+    FixMergedCellsColumn(columnFrom, columns, false);
+
+    var csec = new CellsStoreEnumerator<object>(_values, 0, 1, 0, ExcelPackage.MaxColumns);
+    var lst = new List<ExcelColumn>();
+    foreach (var col in csec) {
+      if (col is ExcelColumn column) {
+        lst.Add(column);
+      }
+    }
+
+    for (int i = lst.Count - 1; i >= 0; i--) {
+      var c = lst[i];
+      if (c._columnMin >= columnFrom) {
+        if (c._columnMin + columns <= ExcelPackage.MaxColumns) {
+          c._columnMin += columns;
+        } else {
+          c._columnMin = ExcelPackage.MaxColumns;
+        }
+
+        if (c._columnMax + columns <= ExcelPackage.MaxColumns) {
+          c._columnMax += columns;
+        } else {
+          c._columnMax = ExcelPackage.MaxColumns;
+        }
+      } else if (c._columnMax >= columnFrom) {
+        var cc = c._columnMax - columnFrom;
+        c._columnMax = columnFrom - 1;
+        CopyColumn(c, columnFrom + columns, columnFrom + columns + cc);
+      }
+    }
+
+    if (copyStylesFromColumn > 0) {
+      for (var c = 0; c < columns; c++) {
+        var col = Column(columnFrom + c);
+        col.StyleID = Column(copyStylesFromColumn).StyleID;
+      }
+    }
+    //Adjust tables
+    foreach (var tbl in Tables) {
+      if (columnFrom > tbl.Address.Start.Column && columnFrom <= tbl.Address.End.Column) {
+        InsertTableColumns(columnFrom, columns, tbl);
+      }
+
+      tbl.Address = tbl.Address.AddColumn(columnFrom, columns);
+    }
+  }
+
+  private static void InsertTableColumns(int columnFrom, int columns, ExcelTable tbl) {
+    var node = tbl.Columns[0].TopNode.ParentNode;
+    var ix = columnFrom - tbl.Address.Start.Column - 1;
+    var insPos = node.ChildNodes[ix];
+    ix += 2;
+    for (int i = 0; i < columns; i++) {
+      var name = tbl.Columns.GetUniqueName(
+          string.Format("Column{0}", (ix++).ToString(CultureInfo.InvariantCulture)));
+      XmlElement tableColumn = (XmlElement)
+        tbl.TableXml.CreateNode(XmlNodeType.Element, "tableColumn", ExcelPackage._schemaMain);
+      tableColumn.SetAttribute(
+          "id",
+          (tbl.Columns.Count + i + 1).ToString(CultureInfo.InvariantCulture));
+      tableColumn.SetAttribute("name", name);
+      insPos = node.InsertAfter(tableColumn, insPos);
+    } //Create tbl Column
+    tbl._cols = new(tbl);
+  }
+
+  /// <summary>
+  /// Adds a value to the row of merged cells to fix for inserts or deletes
+  /// </summary>
+  /// <param name="row"></param>
+  /// <param name="rows"></param>
+  /// <param name="delete"></param>
+  private void FixMergedCellsRow(int row, int rows, bool delete) {
+    if (delete) {
+      _mergedCells._cells.Delete(row, 0, rows, 0);
+    } else {
+      _mergedCells._cells.Insert(row, 0, rows, 0);
+    }
+
+    List<int> removeIndex = [];
+    for (int i = 0; i < _mergedCells.Count; i++) {
+      if (!string.IsNullOrEmpty(_mergedCells[i])) {
+        ExcelAddressBase addr = new(_mergedCells[i]),
+            newAddr;
+        if (delete) {
+          newAddr = addr.DeleteRow(row, rows);
+          if (newAddr == null) {
+            removeIndex.Add(i);
+            continue;
+          }
+        } else {
+          newAddr = addr.AddRow(row, rows);
+          if (newAddr.Address != addr.Address) {
+            //    _mergedCells._cells.Insert(row, 0, rows, 0);
+            _mergedCells.SetIndex(newAddr, i);
+          }
+        }
+
+        if (newAddr.Address != addr.Address) {
+          _mergedCells.List[i] = newAddr._address;
+        }
+      }
+    }
+    for (int i = removeIndex.Count - 1; i >= 0; i--) {
+      _mergedCells.List.RemoveAt(removeIndex[i]);
+    }
+  }
+
+  /// <summary>
+  /// Adds a value to the row of merged cells to fix for inserts or deletes
+  /// </summary>
+  /// <param name="column"></param>
+  /// <param name="columns"></param>
+  /// <param name="delete"></param>
+  private void FixMergedCellsColumn(int column, int columns, bool delete) {
+    if (delete) {
+      _mergedCells._cells.Delete(0, column, 0, columns);
+    } else {
+      _mergedCells._cells.Insert(0, column, 0, columns);
+    }
+    List<int> removeIndex = [];
+    for (int i = 0; i < _mergedCells.Count; i++) {
+      if (!string.IsNullOrEmpty(_mergedCells[i])) {
+        ExcelAddressBase addr = new(_mergedCells[i]),
+            newAddr;
+        if (delete) {
+          newAddr = addr.DeleteColumn(column, columns);
+          if (newAddr == null) {
+            removeIndex.Add(i);
+            continue;
+          }
+        } else {
+          newAddr = addr.AddColumn(column, columns);
+          if (newAddr.Address != addr.Address) {
+            _mergedCells.SetIndex(newAddr, i);
+          }
+        }
+
+        if (newAddr.Address != addr.Address) {
+          _mergedCells.List[i] = newAddr._address;
+        }
+      }
+    }
+    for (int i = removeIndex.Count - 1; i >= 0; i--) {
+      _mergedCells.List.RemoveAt(removeIndex[i]);
+    }
+  }
+
+  /// <summary>
+  /// Delete the specified row from the worksheet.
+  /// </summary>
+  /// <param name="row">A row to be deleted</param>
+  public void DeleteRow(int row) {
+    DeleteRow(row, 1);
+  }
+
+  /// <summary>
+  /// Delete the specified row from the worksheet.
+  /// </summary>
+  /// <param name="rowFrom">The start row</param>
+  /// <param name="rows">Number of rows to delete</param>
+  public void DeleteRow(int rowFrom, int rows) {
+    CheckSheetType();
+    if (rowFrom < 1 || rowFrom + rows > ExcelPackage.MaxRows) {
+      throw (new ArgumentException(
+              "Row out of range. Spans from 1 to "
+                  + ExcelPackage.MaxRows.ToString(CultureInfo.InvariantCulture)));
+    }
+    _values.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
+    _types.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
+    _formulas.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
+    _styles.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
+    _flags.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
+    _commentsStore.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
+    _hyperLinks.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
+
+    AdjustFormulasRow(rowFrom, rows);
+    FixMergedCellsRow(rowFrom, rows, true);
+
+    foreach (var tbl in Tables) {
+      tbl.Address = tbl.Address.DeleteRow(rowFrom, rows);
+    }
+  }
+
+  /// <summary>
+  /// Delete the specified column from the worksheet.
+  /// </summary>
+  /// <param name="column">The column to be deleted</param>
+  public void DeleteColumn(int column) {
+    DeleteColumn(column, 1);
+  }
+
+  /// <summary>
+  /// Delete the specified column from the worksheet.
+  /// </summary>
+  /// <param name="columnFrom">The start column</param>
+  /// <param name="columns">Number of columns to delete</param>
+  public void DeleteColumn(int columnFrom, int columns) {
+    if (columnFrom < 1 || columnFrom + columns > ExcelPackage.MaxColumns) {
+      throw (new ArgumentException(
+              "Column out of range. Spans from 1 to "
+                  + ExcelPackage.MaxColumns.ToString(CultureInfo.InvariantCulture)));
+    }
+    var col = _values.GetValue(0, columnFrom) as ExcelColumn;
+    if (col == null) {
+      var r = 0;
+      var c = columnFrom;
+      if (_values.PrevCell(ref r, ref c)) {
+        col = _values.GetValue(0, c) as ExcelColumn;
+        if (col._columnMax >= columnFrom) {
+          col.ColumnMax = columnFrom - 1;
+        }
+      }
+    }
+
+    _values.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
+    _types.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
+    _formulas.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
+    _styles.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
+    _flags.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
+    _commentsStore.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
+    _hyperLinks.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
+
+    AdjustFormulasColumn(columnFrom, columns);
+    FixMergedCellsColumn(columnFrom, columns, true);
+
+    var csec = new CellsStoreEnumerator<object>(_values, 0, columnFrom, 0, ExcelPackage.MaxColumns);
+    foreach (var column in csec) {
+      if (column is ExcelColumn excelColumn) {
+        if (excelColumn._columnMin >= columnFrom) {
+          excelColumn._columnMin -= columns;
+          excelColumn._columnMax -= columns;
+        }
+      }
+    }
+
+    foreach (var tbl in Tables) {
+      if (columnFrom >= tbl.Address.Start.Column && columnFrom <= tbl.Address.End.Column) {
+        var node = tbl.Columns[0].TopNode.ParentNode;
+        var ix = columnFrom - tbl.Address.Start.Column;
+        for (int i = 0; i < columns; i++) {
+          if (node.ChildNodes.Count > ix) {
+            node.RemoveChild(node.ChildNodes[ix]);
+          }
+        }
+        tbl._cols = new(tbl);
+      }
+
+      tbl.Address = tbl.Address.DeleteColumn(columnFrom, columns);
+    }
+  }
+
+  internal void AdjustFormulasRow(int rowFrom, int rows) {
+    var delSf = new List<int>();
+    foreach (var sf in _sharedFormulas.Values) {
+      var a = new ExcelAddress(sf.Address).DeleteRow(rowFrom, rows);
+      if (a == null) {
+        delSf.Add(sf.Index);
+      } else {
+        sf.Address = a.Address;
+        if (sf.StartRow > rowFrom) {
+          var r = Math.Min(sf.StartRow - rowFrom, rows);
+          sf.Formula = ExcelCellBase.UpdateFormulaReferences(sf.Formula, -r, 0, rowFrom, 0);
+          sf.StartRow -= r;
+        }
+      }
+    }
+    foreach (var ix in delSf) {
+      _sharedFormulas.Remove(ix);
+    }
+    var cse = new CellsStoreEnumerator<object>(
+        _formulas,
+        1,
+        1,
+        ExcelPackage.MaxRows,
+        ExcelPackage.MaxColumns);
+    while (cse.Next()) {
+      if (cse.Value is string) {
+        cse.Value = ExcelCellBase.UpdateFormulaReferences(
+            cse.Value.ToString(),
+            -rows,
+            0,
+            rowFrom,
+            0);
+      }
+    }
+  }
+
+  internal void AdjustFormulasColumn(int columnFrom, int columns) {
+    var delSf = new List<int>();
+    foreach (var sf in _sharedFormulas.Values) {
+      var a = new ExcelAddress(sf.Address).DeleteColumn(columnFrom, columns);
+      if (a == null) {
+        delSf.Add(sf.Index);
+      } else {
+        sf.Address = a.Address;
+        if (sf.StartCol > columnFrom) {
+          var c = Math.Min(sf.StartCol - columnFrom, columns);
+          sf.Formula = ExcelCellBase.UpdateFormulaReferences(sf.Formula, 0, -c, 0, 1);
+          sf.StartCol -= c;
+        }
+      }
+    }
+    foreach (var ix in delSf) {
+      _sharedFormulas.Remove(ix);
+    }
+    var cse = new CellsStoreEnumerator<object>(
+        _formulas,
+        1,
+        1,
+        ExcelPackage.MaxRows,
+        ExcelPackage.MaxColumns);
+    while (cse.Next()) {
+      if (cse.Value is string) {
+        cse.Value = ExcelCellBase.UpdateFormulaReferences(
+            cse.Value.ToString(),
+            0,
+            -columns,
+            0,
+            columnFrom);
+      }
+    }
+  }
+
+  /// <summary>
+  /// Deletes the specified row from the worksheet.
+  /// </summary>
+  /// <param name="rowFrom">The number of the start row to be deleted</param>
+  /// <param name="rows">Number of rows to delete</param>
+  /// <param name="shiftOtherRowsUp">Not used. Rows are always shifted</param>
+  public void DeleteRow(int rowFrom, int rows, bool shiftOtherRowsUp) {
+    DeleteRow(rowFrom, rows);
+  }
+
+  /// <summary>
+  /// Get the cell value from thw worksheet
+  /// </summary>
+  /// <param name="row">The row number</param>
+  /// <param name="column">The row number</param>
+  /// <returns>The value</returns>
+  public object GetValue(int row, int column) {
+    CheckSheetType();
+    var v = _values.GetValue(row, column);
+    if (v != null) {
+      if (_flags.GetFlagValue(row, column, CellFlags.RichText)) {
+        return Cells[row, column].RichText.Text;
+      }
+      return v;
+    }
+    return null;
+  }
+
+  /// <summary>
+  /// Get a strongly typed cell value from the worksheet
+  /// </summary>
+  /// <typeparam name="T">The type</typeparam>
+  /// <param name="row">The row number</param>
+  /// <param name="column">The row number</param>
+  /// <returns>The value. If the value can't be converted to the specified type, the default value will be returned</returns>
+  public T GetValue<T>(int row, int column) {
+    CheckSheetType();
+    //ulong cellID=ExcelCellBase.GetCellID(SheetID, Row, Column);
+    var v = _values.GetValue(row, column);
+    if (v == null) {
+      return default(T);
+    }
+
+    //var cell=((ExcelCell)_cells[cellID]);
+    if (_flags.GetFlagValue(row, column, CellFlags.RichText)) {
+      return (T)(object)Cells[row, column].RichText.Text;
+    }
+    return GetTypedValue<T>(v);
+  }
+
+  //Thanks to Michael Tran for parts of this method
+  internal T GetTypedValue<T>(object v) {
+    if (v == null) {
+      return default(T);
+    }
+    Type fromType = v.GetType();
+    Type toType = typeof(T);
+    if (fromType == toType) {
+      return (T)v;
+    }
+    var cnv = TypeDescriptor.GetConverter(fromType);
+    if (toType
+        == typeof(DateTime)) //Handle dates
+    {
+      if (fromType == typeof(TimeSpan)) {
+        return ((T)(object)(new DateTime(((TimeSpan)v).Ticks)));
+      }
+      if (fromType == typeof(string)) {
+        if (DateTime.TryParse(v.ToString(), out var dt)) {
+          return (T)(object)(dt);
+        }
+        return default(T);
+      }
+      if (cnv.CanConvertTo(typeof(double))) {
+        return (T)(object)(DateTime.FromOADate((double)cnv.ConvertTo(v, typeof(double))));
+      }
+      return default(T);
+    }
+    if (toType
+        == typeof(TimeSpan)) //Handle timespan
+    {
+      if (fromType == typeof(DateTime)) {
+        return ((T)(object)(new TimeSpan(((DateTime)v).Ticks)));
+      }
+      if (fromType == typeof(string)) {
+        if (TimeSpan.TryParse(v.ToString(), out var ts)) {
+          return (T)(object)(ts);
+        }
+        return default(T);
+      }
+      if (cnv.CanConvertTo(typeof(double))) {
+        return (T)
+          (object)(new TimeSpan(
+              DateTime.FromOADate((double)cnv.ConvertTo(v, typeof(double))).Ticks));
+      }
+      try {
+        // Issue 14682 -- "GetValue<decimal>() won't convert strings"
+        // As suggested, after all special cases, all .NET to do it's
+        // preferred conversion rather than simply returning the default
+        return (T)Convert.ChangeType(v, typeof(T));
+      } catch (Exception) {
+        // This was the previous behaviour -- no conversion is available.
+        return default(T);
+      }
+    }
+    if (cnv.CanConvertTo(toType)) {
+      return (T)cnv.ConvertTo(v, typeof(T));
+    }
+    if (toType.IsGenericType && toType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) {
+      toType = Nullable.GetUnderlyingType(toType);
+      if (cnv.CanConvertTo(toType)) {
+        return (T)cnv.ConvertTo(v, typeof(T));
+      }
+    }
+
+    if (fromType == typeof(double) && toType == typeof(decimal)) {
+      return (T)(object)Convert.ToDecimal(v);
+    }
+    if (fromType == typeof(decimal) && toType == typeof(double)) {
+      return (T)(object)Convert.ToDouble(v);
+    }
+    return default(T);
+  }
+
+  /// <summary>
+  /// Set the value of a cell
+  /// </summary>
+  /// <param name="row">The row number</param>
+  /// <param name="column">The column number</param>
+  /// <param name="value">The value</param>
+  public void SetValue(int row, int column, object value) {
+    CheckSheetType();
+    if (row < 1 || column < 1 || row > ExcelPackage.MaxRows && column > ExcelPackage.MaxColumns) {
+      throw new ArgumentOutOfRangeException("Row or Column out of range");
+    }
+    _values.SetValue(row, column, value);
+  }
+
+  /// <summary>
+  /// Set the value of a cell
+  /// </summary>
+  /// <param name="address">The Excel address</param>
+  /// <param name="value">The value</param>
+  public void SetValue(string address, object value) {
+    CheckSheetType();
+    ExcelCellBase.GetRowCol(address, out var row, out var col, true);
+    if (row < 1 || col < 1 || row > ExcelPackage.MaxRows && col > ExcelPackage.MaxColumns) {
+      throw new ArgumentOutOfRangeException("Address is invalid or out of range");
+    }
+    _values.SetValue(row, col, value);
+  }
+
+  /// <summary>
+  /// Get MergeCell Index No
+  /// </summary>
+  /// <param name="row"></param>
+  /// <param name="column"></param>
+  /// <returns></returns>
+  public int GetMergeCellId(int row, int column) {
+    for (int i = 0; i < _mergedCells.Count; i++) {
+      if (!string.IsNullOrEmpty(_mergedCells[i])) {
+        ExcelRange range = Cells[_mergedCells[i]];
+
+        if (range.Start.Row <= row && row <= range.End.Row) {
+          if (range.Start.Column <= column && column <= range.End.Column) {
+            return i + 1;
+          }
+        }
+      }
+    }
+    return 0;
+  }
+
+  internal void Save() {
+    DeletePrinterSettings();
+    if (!(this is ExcelChartsheet)) {
+      var d = Dimension;
+      if (d == null) {
+        DeleteAllNode("d:dimension/@ref");
+      } else {
+        SetXmlNodeString("d:dimension/@ref", d.Address);
+      }
+      SaveTables();
+      SavePivotTables();
+    }
+  }
+
+  internal void SaveHandler(StreamWriter streamWriter) {
+    //Create the nodes if they do not exist.
+    if (this is ExcelChartsheet) {
+      streamWriter.Write(WorksheetXml.OuterXml);
+    } else {
+      CreateNode("d:cols");
+      CreateNode("d:sheetData");
+      CreateNode("d:mergeCells");
+      CreateNode("d:hyperlinks");
+      CreateNode("d:rowBreaks");
+      CreateNode("d:colBreaks");
+
+      //StreamWriter sw=new StreamWriter(Part.GetStream(FileMode.Create, FileAccess.Write));
+      var xml = WorksheetXml.OuterXml;
+      int colStart = 0,
+          colEnd = 0;
+      GetBlockPos(xml, "cols", ref colStart, ref colEnd);
+
+      streamWriter.Write(xml.Substring(0, colStart));
+      UpdateColumnData(streamWriter);
+
+      int cellStart = colEnd,
+          cellEnd = colEnd;
+      GetBlockPos(xml, "sheetData", ref cellStart, ref cellEnd);
+
+      streamWriter.Write(xml.Substring(colEnd, cellStart - colEnd));
+      UpdateRowCellData(streamWriter);
+
+      int mergeStart = cellEnd,
+          mergeEnd = cellEnd;
+
+      GetBlockPos(xml, "mergeCells", ref mergeStart, ref mergeEnd);
+      streamWriter.Write(xml.Substring(cellEnd, mergeStart - cellEnd));
+
+      CleanupMergedCells(_mergedCells);
+      if (_mergedCells.Count > 0) {
+        UpdateMergedCells(streamWriter);
+      }
+
+      int hyperStart = mergeEnd,
+          hyperEnd = mergeEnd;
+      GetBlockPos(xml, "hyperlinks", ref hyperStart, ref hyperEnd);
+      streamWriter.Write(xml.Substring(mergeEnd, hyperStart - mergeEnd));
+      UpdateHyperLinks(streamWriter);
+
+      int rowBreakStart = hyperEnd,
+          rowBreakEnd = hyperEnd;
+      GetBlockPos(xml, "rowBreaks", ref rowBreakStart, ref rowBreakEnd);
+      streamWriter.Write(xml.Substring(hyperEnd, rowBreakStart - hyperEnd));
+      UpdateRowBreaks(streamWriter);
+
+      int colBreakStart = rowBreakEnd,
+          colBreakEnd = rowBreakEnd;
+      GetBlockPos(xml, "colBreaks", ref colBreakStart, ref colBreakEnd);
+      streamWriter.Write(xml.Substring(rowBreakEnd, colBreakStart - rowBreakEnd));
+      UpdateColBreaks(streamWriter);
+      streamWriter.Write(xml.Substring(colBreakEnd, xml.Length - colBreakEnd));
+    }
+  }
+
+  /// <summary>
+  /// Delete the printersettings relationship and part.
+  /// </summary>
+  private void DeletePrinterSettings() {
+    //Delete the relationship from the pageSetup tag
+    XmlAttribute attr = (XmlAttribute)
+      WorksheetXml.SelectSingleNode("//d:pageSetup/@r:id", NameSpaceManager);
+    if (attr != null) {
+      string relId = attr.Value;
+      //First delete the attribute from the XML
+      attr.OwnerElement.Attributes.Remove(attr);
+      if (Part.RelationshipExists(relId)) {
+        var rel = Part.GetRelationship(relId);
+        Uri printerSettingsUri = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri);
+        Part.DeleteRelationship(rel.Id);
+
+        //Delete the part from the package
+        if (_package.Package.PartExists(printerSettingsUri)) {
+          _package.Package.DeletePart(printerSettingsUri);
+        }
+      }
+    }
+  }
+
+  /// <summary>
+  /// Save all table data
+  /// </summary>
+  private void SaveTables() {
+    foreach (var tbl in Tables) {
+      if (tbl.ShowHeader || tbl.ShowTotal) {
+        int colNum = tbl.Address._fromCol;
+        var colVal = new HashSet<string>();
+        foreach (var col in tbl.Columns) {
+          string n = col.Name.ToLower(CultureInfo.InvariantCulture);
+          if (tbl.ShowHeader) {
+            n = tbl.WorkSheet.GetValue<string>(
+                tbl.Address._fromRow,
+                tbl.Address._fromCol + col.Position);
+            if (string.IsNullOrEmpty(n)) {
+              n = col.Name.ToLower(CultureInfo.InvariantCulture);
+            } else {
+              col.Name = n;
+            }
+          } else {
+            n = col.Name.ToLower(CultureInfo.InvariantCulture);
+          }
+
+          if (colVal.Contains(n)) {
+            throw (new InvalidDataException(
+                    string.Format(
+                        "Table {0} Column {1} does not have a unique name.",
+                        tbl.Name,
+                        col.Name)));
+          }
+          colVal.Add(n);
+          col.Name = ConvertUtil.ExcelEncodeString(col.Name);
+          if (tbl.ShowHeader) {
+            _values.SetValue(tbl.Address._fromRow, colNum, col.Name);
+          }
+          if (tbl.ShowTotal) {
+            SetTableTotalFunction(tbl, col, colNum);
+          }
+          if (!string.IsNullOrEmpty(col.CalculatedColumnFormula)) {
+            int fromRow = tbl.ShowHeader ? tbl.Address._fromRow + 1 : tbl.Address._fromRow;
+            int toRow = tbl.ShowTotal ? tbl.Address._toRow - 1 : tbl.Address._toRow;
+            for (int row = fromRow; row <= toRow; row++) {
+              //Cell(row, colNum).Formula = col.CalculatedColumnFormula;
+              SetFormula(row, colNum, col.CalculatedColumnFormula);
+            }
+          }
+          colNum++;
+        }
+      }
+    }
+  }
+
+  internal void SetTableTotalFunction(ExcelTable tbl, ExcelTableColumn col, int colNum = -1) {
+    if (tbl.ShowTotal == false) {
+      return;
+    }
+    if (colNum == -1) {
+      for (int i = 0; i < tbl.Columns.Count; i++) {
+        if (tbl.Columns[i].Name == col.Name) {
+          colNum = tbl.Address._fromCol + i;
+        }
+      }
+    }
+    if (col.TotalsRowFunction == RowFunctions.Custom) {
+      SetFormula(tbl.Address._toRow, colNum, col.TotalsRowFormula);
+    } else if (col.TotalsRowFunction != RowFunctions.None) {
+      switch (col.TotalsRowFunction) {
+        case RowFunctions.Average:
+          SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "101"));
+          break;
+        case RowFunctions.Count:
+          SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "102"));
+          break;
+        case RowFunctions.CountNums:
+          SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "103"));
+          break;
+        case RowFunctions.Max:
+          SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "104"));
+          break;
+        case RowFunctions.Min:
+          SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "105"));
+          break;
+        case RowFunctions.StdDev:
+          SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "107"));
+          break;
+        case RowFunctions.Var:
+          SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "110"));
+          break;
+        case RowFunctions.Sum:
+          SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "109"));
+          break;
+        default:
+          throw (new("Unknown RowFunction enum"));
+      }
+    } else {
+      _values.SetValue(tbl.Address._toRow, colNum, col.TotalsRowLabel);
+    }
+  }
+
+  internal void SetFormula(int row, int col, object value) {
+    _formulas.SetValue(row, col, value);
+    if (!_values.Exists(row, col)) {
+      _values.SetValue(row, col, null);
+    }
+  }
+
+  internal void SetStyle(int row, int col, int value) {
+    _styles.SetValue(row, col, value);
+    if (!_values.Exists(row, col)) {
+      _values.SetValue(row, col, null);
+    }
+  }
+
+  private void SavePivotTables() {
+    foreach (var pt in PivotTables) {
+      if (pt.DataFields.Count > 1) {
+        XmlElement parentNode;
+        if (pt.DataOnRows) {
+          parentNode =
+              pt.PivotTableXml.SelectSingleNode("//d:rowFields", pt.NameSpaceManager) as XmlElement;
+          if (parentNode == null) {
+            pt.CreateNode("d:rowFields");
+            parentNode =
+                pt.PivotTableXml.SelectSingleNode("//d:rowFields", pt.NameSpaceManager)
+                    as XmlElement;
+          }
+        } else {
+          parentNode =
+              pt.PivotTableXml.SelectSingleNode("//d:colFields", pt.NameSpaceManager) as XmlElement;
+          if (parentNode == null) {
+            pt.CreateNode("d:colFields");
+            parentNode =
+                pt.PivotTableXml.SelectSingleNode("//d:colFields", pt.NameSpaceManager)
+                    as XmlElement;
+          }
+        }
+
+        if (parentNode.SelectSingleNode("d:field[@ x= \"-2\"]", pt.NameSpaceManager) == null) {
+          XmlElement fieldNode = pt.PivotTableXml.CreateElement("field", ExcelPackage._schemaMain);
+          fieldNode.SetAttribute("x", "-2");
+          parentNode.AppendChild(fieldNode);
+        }
+      }
+      var ws = Workbook.Worksheets[pt.CacheDefinition.SourceRange.WorkSheet];
+      var t = ws.Tables.GetFromRange(pt.CacheDefinition.SourceRange);
+      var fields = pt.CacheDefinition.CacheDefinitionXml.SelectNodes(
+          "d:pivotCacheDefinition/d:cacheFields/d:cacheField",
+          NameSpaceManager);
+      int ix = 0;
+      if (fields != null) {
+        var flds = new HashSet<string>();
+        foreach (XmlElement node in fields) {
+          if (ix >= pt.CacheDefinition.SourceRange.Columns) {
+            break;
+          }
+          var fldName = node.GetAttribute("name"); //Fixes issue 15295 dup name error
+          if (string.IsNullOrEmpty(fldName)) {
+            fldName =
+                (t == null
+                    ? pt.CacheDefinition.SourceRange.Offset(0, ix++, 1, 1).Value.ToString()
+                    : t.Columns[ix++].Name);
+          }
+          if (flds.Contains(fldName)) {
+            fldName = GetNewName(flds, fldName);
+          }
+          flds.Add(fldName);
+          node.SetAttribute("name", fldName);
+        }
+        foreach (var df in pt.DataFields) {
+          if (string.IsNullOrEmpty(df.Name)) {
+            string name;
+            if (df.Function == DataFieldFunctions.None) {
+              name = df.Field.Name; //Name must be set or Excel will crash on rename.
+            } else {
+              name = df.Function + " of " + df.Field.Name; //Name must be set or Excel will crash on rename.
+            }
+            //Make sure name is unique
+            var newName = name;
+            var i = 2;
+            while (pt.DataFields.ExistsDfName(newName, df)) {
+              newName = name + (i++).ToString(CultureInfo.InvariantCulture);
+            }
+            df.Name = newName;
+          }
+        }
+      }
+    }
+  }
+
+  private string GetNewName(HashSet<string> flds, string fldName) {
+    int ix = 2;
+    while (flds.Contains(fldName + ix.ToString(CultureInfo.InvariantCulture))) {
+      ix++;
+    }
+    return fldName + ix.ToString(CultureInfo.InvariantCulture);
+  }
+
+  private static string GetTotalFunction(ExcelTableColumn col, string functionNum) {
+    return string.Format("SUBTOTAL({0},{1}[{2}])", functionNum, col._tbl.Name, col.Name);
+  }
+
+  private void CleanupMergedCells(MergeCellsCollection mergedCells) {
+    int i = 0;
+    while (i < mergedCells.List.Count) {
+      if (mergedCells[i] == null) {
+        mergedCells.List.RemoveAt(i);
+      } else {
+        i++;
+      }
+    }
+  }
+
+  private void UpdateColBreaks(StreamWriter sw) {
+    StringBuilder breaks = new StringBuilder();
+    int count = 0;
+    var cse = new CellsStoreEnumerator<object>(_values, 0, 0, 0, ExcelPackage.MaxColumns);
+    while (cse.Next()) {
+      var col = cse.Value as ExcelColumn;
+      if (col != null && col.PageBreak) {
+        breaks.AppendFormat("<brk id=\"{0}\" max=\"16383\" man=\"1\" />", cse.Column);
+        count++;
+      }
+    }
+    if (count > 0) {
+      sw.Write("<colBreaks count=\"{0}\" manualBreakCount=\"{0}\">{1}</colBreaks>", count, breaks);
+    }
+  }
+
+  private void UpdateRowBreaks(StreamWriter sw) {
+    StringBuilder breaks = new StringBuilder();
+    int count = 0;
+    var cse = new CellsStoreEnumerator<object>(_values, 0, 0, ExcelPackage.MaxRows, 0);
+    //foreach(ExcelRow row in _rows)
+    while (cse.Next()) {
+      var row = cse.Value as RowInternal;
+      if (row != null && row.PageBreak) {
+        breaks.AppendFormat("<brk id=\"{0}\" max=\"1048575\" man=\"1\" />", cse.Row);
+        count++;
+      }
+    }
+    if (count > 0) {
+      sw.Write("<rowBreaks count=\"{0}\" manualBreakCount=\"{0}\">{1}</rowBreaks>", count, breaks);
+    }
+  }
+
+  /// <summary>
+  /// Inserts the cols collection into the XML document
+  /// </summary>
+  private void UpdateColumnData(StreamWriter sw) {
+    var cse = new CellsStoreEnumerator<object>(_values, 0, 1, 0, ExcelPackage.MaxColumns);
+    bool first = true;
+    while (cse.Next()) {
+      if (first) {
+        sw.Write("<cols>");
+        first = false;
+      }
+      var col = cse.Value as ExcelColumn;
+      ExcelStyleCollection<ExcelXfs> cellXfs = _workbook.Styles.CellXfs;
+
+      sw.Write("<col min=\"{0}\" max=\"{1}\"", col.ColumnMin, col.ColumnMax);
+      if (col.Hidden) {
+        //sbXml.Append(" width=\"0\" hidden=\"1\" customWidth=\"1\"");
+        sw.Write(" hidden=\"1\"");
+      } else if (col.BestFit) {
+        sw.Write(" bestFit=\"1\"");
+      }
+      sw.Write(
+          string.Format(
+              CultureInfo.InvariantCulture,
+              " width=\"{0}\" customWidth=\"1\"",
+              col.Width));
+      if (col.OutlineLevel > 0) {
+        sw.Write(" outlineLevel=\"{0}\" ", col.OutlineLevel);
+        if (col.Collapsed) {
+          if (col.Hidden) {
+            sw.Write(" collapsed=\"1\"");
+          } else {
+            sw.Write(" collapsed=\"1\" hidden=\"1\""); //Always hidden
+          }
+        }
+      }
+      if (col.Phonetic) {
+        sw.Write(" phonetic=\"1\"");
+      }
+
+      var styleId = col.StyleID >= 0 ? cellXfs[col.StyleID].newID : col.StyleID;
+      if (styleId > 0) {
+        sw.Write(" style=\"{0}\"", styleId);
+      }
+      sw.Write(" />");
+    }
+    if (!first) {
+      sw.Write("</cols>");
+    }
+  }
+
+  /// <summary>
+  /// Insert row and cells into the XML document
+  /// </summary>
+  private void UpdateRowCellData(StreamWriter sw) {
+    ExcelStyleCollection<ExcelXfs> cellXfs = _workbook.Styles.CellXfs;
+
+    int row = -1;
+
+    var ss = _workbook._sharedStrings;
+    var styles = _workbook.Styles;
+    var cache = new StringBuilder();
+    cache.Append("<sheetData>");
+
+    //Set a value for cells with style and no value set.
+    var cseStyle = new CellsStoreEnumerator<int>(
+        _styles,
+        0,
+        0,
+        ExcelPackage.MaxRows,
+        ExcelPackage.MaxColumns);
+    foreach (var s in cseStyle) {
+      if (!_values.Exists(cseStyle.Row, cseStyle.Column)) {
+        _values.SetValue(cseStyle.Row, cseStyle.Column, null);
+      }
+    }
+
+    var cse = new CellsStoreEnumerator<object>(
+        _values,
+        1,
+        0,
+        ExcelPackage.MaxRows,
+        ExcelPackage.MaxColumns);
+    //foreach (IRangeID r in _cells)
+    while (cse.Next()) {
+      if (cse.Column > 0) {
+        int styleId = cellXfs[styles.GetStyleId(this, cse.Row, cse.Column)].newID;
+        //Add the row element if it's a new row
+        if (cse.Row != row) {
+          WriteRow(cache, cellXfs, row, cse.Row);
+          row = cse.Row;
+        }
+        object v = cse.Value;
+        object formula = _formulas.GetValue(cse.Row, cse.Column);
+        if (formula is int sfId) {
+          var f = _sharedFormulas[sfId];
+          if (f.Address.IndexOf(':') > 0) {
+            if (f.StartCol == cse.Column && f.StartRow == cse.Row) {
+              if (f.IsArray) {
+                cache.AppendFormat(
+                    "<c r=\"{0}\" s=\"{1}\"{5}><f ref=\"{2}\" t=\"array\">{3}</f>{4}</c>",
+                    cse.CellAddress,
+                    styleId < 0 ? 0 : styleId,
+                    f.Address,
+                    SecurityElement.Escape(f.Formula),
+                    GetFormulaValue(v),
+                    GetCellType(v, true));
+              } else {
+                cache.AppendFormat(
+                    "<c r=\"{0}\" s=\"{1}\"{6}><f ref=\"{2}\" t=\"shared\"  si=\"{3}\">{4}</f>{5}</c>",
+                    cse.CellAddress,
+                    styleId < 0 ? 0 : styleId,
+                    f.Address,
+                    sfId,
+                    SecurityElement.Escape(f.Formula),
+                    GetFormulaValue(v),
+                    GetCellType(v, true));
+              }
+            } else if (f.IsArray) {
+              cache.AppendFormat(
+                  "<c r=\"{0}\" s=\"{1}\" />",
+                  cse.CellAddress,
+                  styleId < 0 ? 0 : styleId);
+            } else {
+              cache.AppendFormat(
+                  "<c r=\"{0}\" s=\"{1}\"{4}><f t=\"shared\" si=\"{2}\" />{3}</c>",
+                  cse.CellAddress,
+                  styleId < 0 ? 0 : styleId,
+                  sfId,
+                  GetFormulaValue(v),
+                  GetCellType(v, true));
+            }
+          } else {
+            // We can also have a single cell array formula
+            if (f.IsArray) {
+              cache.AppendFormat(
+                  "<c r=\"{0}\" s=\"{1}\"{5}><f ref=\"{2}\" t=\"array\">{3}</f>{4}</c>",
+                  cse.CellAddress,
+                  styleId < 0 ? 0 : styleId,
+                  string.Format("{0}:{1}", f.Address, f.Address),
+                  SecurityElement.Escape(f.Formula),
+                  GetFormulaValue(v),
+                  GetCellType(v, true));
+            } else {
+              cache.AppendFormat("<c r=\"{0}\" s=\"{1}\">", f.Address, styleId < 0 ? 0 : styleId);
+              cache.AppendFormat(
+                  "<f>{0}</f>{1}</c>",
+                  SecurityElement.Escape(f.Formula),
+                  GetFormulaValue(v));
+            }
+          }
+        } else if (formula != null && formula.ToString() != "") {
+          cache.AppendFormat(
+              "<c r=\"{0}\" s=\"{1}\"{2}>",
+              cse.CellAddress,
+              styleId < 0 ? 0 : styleId,
+              GetCellType(v, true));
+          cache.AppendFormat(
+              "<f>{0}</f>{1}</c>",
+              SecurityElement.Escape(formula.ToString()),
+              GetFormulaValue(v));
+        } else {
+          if (v == null && styleId > 0) {
+            cache.AppendFormat(
+                "<c r=\"{0}\" s=\"{1}\" />",
+                cse.CellAddress,
+                styleId < 0 ? 0 : styleId);
+          } else if (v != null) {
+            if ((v.GetType().IsPrimitive
+                        || v is double
+                        || v is decimal
+                        || v is DateTime
+                        || v is TimeSpan)) {
+              //string sv = GetValueForXml(v);
+              cache.AppendFormat(
+                  "<c r=\"{0}\" s=\"{1}\" {2}>",
+                  cse.CellAddress,
+                  styleId < 0 ? 0 : styleId,
+                  GetCellType(v));
+              cache.AppendFormat("{0}</c>", GetFormulaValue(v));
+            } else {
+              int ix;
+              if (!ss.ContainsKey(v.ToString())) {
+                ix = ss.Count;
+                ss.Add(
+                    v.ToString(),
+                    new() {
+                      isRichText = _flags.GetFlagValue(cse.Row, cse.Column, CellFlags.RichText),
+                      pos = ix,
+                    });
+              } else {
+                ix = ss[v.ToString()].pos;
+              }
+              cache.AppendFormat(
+                  "<c r=\"{0}\" s=\"{1}\" t=\"s\">",
+                  cse.CellAddress,
+                  styleId < 0 ? 0 : styleId);
+              cache.AppendFormat("<v>{0}</v></c>", ix);
+            }
+          }
+        }
+      } else //ExcelRow
+      {
+        WriteRow(cache, cellXfs, row, cse.Row);
+        row = cse.Row;
+      }
+      if (cache.Length > 0x600000) {
+        sw.Write(cache.ToString());
+        cache = new();
+      }
+    }
+
+    if (row != -1) {
+      cache.Append("</row>");
+    }
+    cache.Append("</sheetData>");
+    sw.Write(cache.ToString());
+    sw.Flush();
+  }
+
+  private object GetFormulaValue(object v) {
+    if (v != null && v.ToString() != "") {
+      return "<v>" + SecurityElement.Escape(GetValueForXml(v)) + "</v>"; //Fixes issue 15071
+    }
+    return "";
+  }
+
+  private string GetCellType(object v, bool allowStr = false) {
+    if (v is bool) {
+      return " t=\"b\"";
+    }
+    if ((v is double d && double.IsInfinity(d)) || v is ExcelErrorValue) {
+      return " t=\"e\"";
+    }
+    if (allowStr
+        && v != null
+        && !(v.GetType().IsPrimitive
+                || v is double
+                || v is decimal
+                || v is DateTime
+                || v is TimeSpan)) {
+      return " t=\"str\"";
+    }
+    return "";
+  }
+
+  private string GetValueForXml(object v) {
+    string s;
+    try {
+      if (v is DateTime time) {
+        double sdv = time.ToOADate();
+
+        if (Workbook.Date1904) {
+          sdv -= ExcelWorkbook._date1904Offset;
+        }
+
+        s = sdv.ToString(CultureInfo.InvariantCulture);
+      } else if (v is TimeSpan span) {
+        s = new DateTime(span.Ticks).ToOADate().ToString(CultureInfo.InvariantCulture);
+        ;
+      } else if (v.GetType().IsPrimitive || v is double || v is decimal) {
+        if (v is double d && double.IsNaN(d)) {
+          s = "";
+        } else if (v is double d1 && double.IsInfinity(d1)) {
+          s = "#NUM!";
+        } else {
+          s = Convert
+              .ToDouble(v, CultureInfo.InvariantCulture)
+              .ToString("R15", CultureInfo.InvariantCulture);
+        }
+      } else {
+        s = v.ToString();
+      }
+    } catch {
+      s = "0";
+    }
+    return s;
+  }
+
+  private void WriteRow(
+      StringBuilder cache,
+      ExcelStyleCollection<ExcelXfs> cellXfs,
+      int prevRow,
+      int row) {
+    if (prevRow != -1) {
+      cache.Append("</row>");
+    }
+    //ulong rowID = ExcelRow.GetRowID(SheetID, row);
+    cache.AppendFormat("<row r=\"{0}\" ", row);
+    RowInternal currRow = _values.GetValue(row, 0) as RowInternal;
+    if (currRow != null) {
+      if (currRow.Hidden) {
+        cache.Append("ht=\"0\" hidden=\"1\" ");
+      } else if (currRow.Height != DefaultRowHeight && currRow.Height >= 0) {
+        cache.AppendFormat(CultureInfo.InvariantCulture, "ht=\"{0}\" ", currRow.Height);
+        if (currRow.CustomHeight) {
+          cache.Append("customHeight=\"1\" ");
+        }
+      }
+
+      if (currRow.OutlineLevel > 0) {
+        cache.AppendFormat("outlineLevel =\"{0}\" ", currRow.OutlineLevel);
+        if (currRow.Collapsed) {
+          if (currRow.Hidden) {
+            cache.Append(" collapsed=\"1\" ");
+          } else {
+            cache.Append(" collapsed=\"1\" hidden=\"1\" "); //Always hidden
+          }
+        }
+      }
+      if (currRow.Phonetic) {
+        cache.Append("ph=\"1\" ");
+      }
+    }
+    var s = _styles.GetValue(row, 0);
+    if (s > 0) {
+      cache.AppendFormat("s=\"{0}\" customFormat=\"1\"", cellXfs[s].newID);
+    }
+    cache.Append(">");
+  }
+
+  /// <summary>
+  /// Update xml with hyperlinks
+  /// </summary>
+  /// <param name="sw">The stream</param>
+  private void UpdateHyperLinks(StreamWriter sw) {
+    Dictionary<string, string> hyps = new Dictionary<string, string>();
+    var cse = new CellsStoreEnumerator<Uri>(_hyperLinks);
+    bool first = true;
+    //foreach (ulong cell in _hyperLinks)
+    while (cse.Next()) {
+      if (first) {
+        sw.Write("<hyperlinks>");
+        first = false;
+      }
+      //int row, col;
+      var uri = _hyperLinks.GetValue(cse.Row, cse.Column);
+      //ExcelCell cell = _cells[cellId] as ExcelCell;
+      if (uri is ExcelHyperLink link && !string.IsNullOrEmpty(link.ReferenceAddress)) {
+        sw.Write(
+            "<hyperlink ref=\"{0}\" location=\"{1}\" {2}{3}/>",
+            Cells[cse.Row, cse.Column, cse.Row + link.RowSpann, cse.Column + link.ColSpann].Address,
+            ExcelCellBase.GetFullAddress(
+                SecurityElement.Escape(Name),
+                SecurityElement.Escape(link.ReferenceAddress)),
+            string.IsNullOrEmpty(link.Display)
+                ? ""
+                : "display=\"" + SecurityElement.Escape(link.Display) + "\" ",
+            string.IsNullOrEmpty(link.ToolTip)
+                ? ""
+                : "tooltip=\"" + SecurityElement.Escape(link.ToolTip) + "\" ");
+      } else if (uri != null) {
+        Uri hyp;
+        if (uri is ExcelHyperLink hyperLink) {
+          hyp = hyperLink.OriginalUri;
+        } else {
+          hyp = uri;
+        }
+        if (!hyps.ContainsKey(hyp.OriginalString)) {
+          var relationship = Part.CreateRelationship(
+              hyp,
+              TargetMode.External,
+              ExcelPackage._schemaHyperlink);
+          if (uri is ExcelHyperLink hl) {
+            sw.Write(
+                "<hyperlink ref=\"{0}\" {2}{3}r:id=\"{1}\" />",
+                ExcelCellBase.GetAddress(cse.Row, cse.Column),
+                relationship.Id,
+                string.IsNullOrEmpty(hl.Display)
+                    ? ""
+                    : "display=\"" + SecurityElement.Escape(hl.Display) + "\" ",
+                string.IsNullOrEmpty(hl.ToolTip)
+                    ? ""
+                    : "tooltip=\"" + SecurityElement.Escape(hl.ToolTip) + "\" ");
+          } else {
+            sw.Write(
+                "<hyperlink ref=\"{0}\" r:id=\"{1}\" />",
+                ExcelCellBase.GetAddress(cse.Row, cse.Column),
+                relationship.Id);
+          }
+        }
+      }
+    }
+    if (!first) {
+      sw.Write("</hyperlinks>");
+    }
+  }
+
+  /// <summary>
+  /// Dimension address for the worksheet.
+  /// Top left cell to Bottom right.
+  /// If the worksheet has no cells, null is returned
+  /// </summary>
+  public ExcelAddressBase Dimension {
+    get {
+      CheckSheetType();
+      if (_values.GetDimension(out var fromRow, out var fromCol, out var toRow, out var toCol)) {
+        var addr = new ExcelAddressBase(fromRow, fromCol, toRow, toCol);
+        addr._ws = Name;
+        return addr;
+      }
+      return null;
+    }
+  }
+
+  private ExcelSheetProtection _protection;
+
+  /// <summary>
+  /// Access to sheet protection properties
+  /// </summary>
+  public ExcelSheetProtection Protection {
+    get {
+      if (_protection == null) {
+        _protection = new(NameSpaceManager, TopNode);
+      }
+      return _protection;
+    }
+  }
+
+  private ExcelProtectedRangeCollection _protectedRanges;
+
+  public ExcelProtectedRangeCollection ProtectedRanges {
+    get {
+      if (_protectedRanges == null) {
+        _protectedRanges = new(NameSpaceManager, TopNode);
+      }
+      return _protectedRanges;
+    }
+  }
+
+  private ExcelTableCollection _tables;
+
+  /// <summary>
+  /// Tables defined in the worksheet.
+  /// </summary>
+  public ExcelTableCollection Tables {
+    get {
+      CheckSheetType();
+      if (Workbook._nextTableID == int.MinValue) {
+        Workbook.ReadAllTables();
+      }
+      if (_tables == null) {
+        _tables = new(this);
+      }
+      return _tables;
+    }
+  }
+
+  private ExcelPivotTableCollection _pivotTables;
+
+  /// <summary>
+  /// Pivottables defined in the worksheet.
+  /// </summary>
+  public ExcelPivotTableCollection PivotTables {
+    get {
+      CheckSheetType();
+      if (_pivotTables == null) {
+        if (Workbook._nextPivotTableID == int.MinValue) {
+          Workbook.ReadAllTables();
+        }
+        _pivotTables = new(this);
+      }
+      return _pivotTables;
+    }
+  }
+
+  private ExcelConditionalFormattingCollection _conditionalFormatting;
+
+  /// <summary>
+  /// ConditionalFormatting defined in the worksheet. Use the Add methods to create ConditionalFormatting and add them to the worksheet. Then
+  /// set the properties on the instance returned.
+  /// </summary>
+  /// <seealso cref="ExcelConditionalFormattingCollection"/>
+  public ExcelConditionalFormattingCollection ConditionalFormatting {
+    get {
+      CheckSheetType();
+      if (_conditionalFormatting == null) {
+        _conditionalFormatting = new(this);
+      }
+      return _conditionalFormatting;
+    }
+  }
+
+  private ExcelDataValidationCollection _dataValidation;
+
+  /// <summary>
+  /// DataValidation defined in the worksheet. Use the Add methods to create DataValidations and add them to the worksheet. Then
+  /// set the properties on the instance returned.
+  /// </summary>
+  /// <seealso cref="ExcelDataValidationCollection"/>
+  public ExcelDataValidationCollection DataValidations {
+    get {
+      CheckSheetType();
+      if (_dataValidation == null) {
+        _dataValidation = new(this);
+      }
+      return _dataValidation;
+    }
+  }
+
+  /// <summary>
+  /// Returns the style ID given a style name.
+  /// The style ID will be created if not found, but only if the style name exists!
+  /// </summary>
+  /// <param name="styleName"></param>
+  /// <returns></returns>
+  internal int GetStyleId(string styleName) {
+    ExcelNamedStyleXml namedStyle = null;
+    Workbook.Styles.NamedStyles.FindById(styleName, ref namedStyle);
+    if (namedStyle.XfId == int.MinValue) {
+      namedStyle.XfId = Workbook.Styles.CellXfs.FindIndexById(namedStyle.Style.Id);
+    }
+    return namedStyle.XfId;
+  }
+
+  /// <summary>
+  /// The workbook object
+  /// </summary>
+  public ExcelWorkbook Workbook => _workbook;
+
+  /// <summary>
+  /// Get the next ID from a shared formula or an Array formula
+  /// Sharedforumlas will have an id from 0-x. Array formula ids start from 0x4000001-.
+  /// </summary>
+  /// <param name="isArray">If the formula is an array formula</param>
+  /// <returns></returns>
+  internal int GetMaxShareFunctionIndex(bool isArray) {
+    int i = _sharedFormulas.Count + 1;
+    if (isArray) {
+      i |= 0x40000000;
+    }
+
+    while (_sharedFormulas.ContainsKey(i)) {
+      i++;
+    }
+    return i;
+  }
+
+  internal void UpdateCellsWithDate1904Setting() {
+    var cse = new CellsStoreEnumerator<object>(_values);
+    var offset = Workbook.Date1904 ? -ExcelWorkbook._date1904Offset : ExcelWorkbook._date1904Offset;
+    while (cse.MoveNext()) {
+      if (cse.Value is DateTime time) {
+        try {
+          double sdv = time.ToOADate();
+          sdv += offset;
+
+          cse.Value = DateTime.FromOADate(sdv);
+        } catch {}
+      }
+    }
+  }
+
+  public string GetFormula(int row, int col) {
+    var v = _formulas.GetValue(row, col);
+    if (v is int i) {
+      return _sharedFormulas[i].GetFormula(row, col, Name);
+    }
+    if (v != null) {
+      return v.ToString();
+    }
+    return "";
+  }
+
+  public string GetFormulaR1C1(int row, int col) {
+    var v = _formulas.GetValue(row, col);
+    if (v is int i) {
+      var sf = _sharedFormulas[i];
+      return ExcelCellBase.TranslateToR1C1(
+          Formulas.RemoveDummyFunction(sf.Formula),
+          sf.StartRow,
+          sf.StartCol);
+    }
+    if (v != null) {
+      return ExcelCellBase.TranslateToR1C1(Formulas.RemoveDummyFunction(v.ToString()), row, col);
+    }
+    return "";
+  }
+
+  public string GetFormulaR1C1_V1(int row, int col) {
+    var v = _formulas.GetValue(row, col);
+    if (v is int i) {
+      var sf = _sharedFormulas[i];
+      return ExcelCellBase.TranslateToR1C1_V1(
+          Formulas.RemoveDummyFunction(sf.Formula),
+          sf.StartRow,
+          sf.StartCol);
+    }
+    if (v != null) {
+      return ExcelCellBase.TranslateToR1C1_V1(Formulas.RemoveDummyFunction(v.ToString()), row, col);
+    }
+    return "";
+  }
+
+  public bool IsArrayFormula(int row, int col) =>
+    _flags.GetFlagValue(row, col, CellFlags.ArrayFormula);
+
+  public string GetArrayFormulaAddress(int row, int col) {
+    var v = _formulas.GetValue(row, col);
+    if ((v is int i) && (_sharedFormulas[i].IsArray)) {
+      return _sharedFormulas[i].Address;
+    }
+    return "";
+  }
+
+  public int GetStyleId(int row, int col) {
+    int styleId = 0;
+    if (!_styles.Exists(row, col, ref styleId) && !_styles.Exists(row, 0, ref styleId)) {
+      styleId = _styles.GetValue(0, col);
+    }
+    return styleId;
+  }
+
+  /// <summary>
+  /// Get the ExcelColumn for column (span ColumnMin and ColumnMax)
+  /// </summary>
+  /// <param name="column"></param>
+  /// <returns></returns>
+  internal ExcelColumn GetColumn(int column) {
+    var c = _values.GetValue(0, column) as ExcelColumn;
+    if (c == null) {
+      int row = 0,
+          col = column;
+      if (_values.PrevCell(ref row, ref col)) {
+        c = _values.GetValue(0, col) as ExcelColumn;
+        if (c != null && c.ColumnMax >= column) {
+          return c;
+        }
+        return null;
+      }
+    }
+    return c;
+  }
+
+  public bool Equals(ExcelWorksheet x, ExcelWorksheet y) {
+    return x.Name == y.Name
+        && x.SheetID == y.SheetID
+        && x.WorksheetXml.OuterXml == y.WorksheetXml.OuterXml;
+  }
+
+  public int GetHashCode(ExcelWorksheet obj) {
+    return obj.WorksheetXml.OuterXml.GetHashCode();
+  }
+}
diff --git a/AppsheetEpplus/ExcelWorksheetView.cs b/AppsheetEpplus/ExcelWorksheetView.cs
new file mode 100644
index 0000000..9dde8f6
--- /dev/null
+++ b/AppsheetEpplus/ExcelWorksheetView.cs
@@ -0,0 +1,396 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan K�llman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan K�llman		    Initial Release		       2009-10-01
+ * Jan K�llman		    License changed GPL-->LGPL 2011-12-27
+ *******************************************************************************/
+
+using System;
+using System.Collections.Immutable;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Represents the different view states of the worksheet
+/// </summary>
+public class ExcelWorksheetView : XmlHelper {
+  /// <summary>
+  /// The worksheet panes after a freeze or split.
+  /// </summary>
+  public class ExcelWorksheetPanes : XmlHelper {
+    private XmlElement _selectionNode;
+
+    internal ExcelWorksheetPanes(XmlNamespaceManager ns, XmlNode topNode)
+        : base(ns, topNode) {
+      if (topNode.Name == "selection") {
+        _selectionNode = topNode as XmlElement;
+      }
+    }
+
+    private const string _activeCellPath = "@activeCell";
+
+    /// <summary>
+    /// Set the active cell. Must be set within the SelectedRange.
+    /// </summary>
+    public string ActiveCell {
+      get {
+        string address = GetXmlNodeString(_activeCellPath);
+        if (address == "") {
+          return "A1";
+        }
+        return address;
+      }
+      set {
+        int toCol,
+            toRow;
+        if (_selectionNode == null) {
+          CreateSelectionElement();
+        }
+        ExcelCellBase.GetRowColFromAddress(
+            value,
+            out var fromRow,
+            out var fromCol,
+            out toRow,
+            out toCol);
+        SetXmlNodeString(_activeCellPath, value);
+        if (((XmlElement)TopNode).GetAttribute("sqref") == "") {
+          SelectedRange = ExcelCellBase.GetAddress(fromRow, fromCol);
+        }
+        //TODO:Add fix for out of range here
+      }
+    }
+
+    private void CreateSelectionElement() {
+      _selectionNode = TopNode.OwnerDocument.CreateElement("selection", ExcelPackage._schemaMain);
+      TopNode.AppendChild(_selectionNode);
+      TopNode = _selectionNode;
+    }
+
+    private const string _selectionRangePath = "@sqref";
+
+    /// <summary>
+    /// Selected Cells.Used in combination with ActiveCell
+    /// </summary>
+    public string SelectedRange {
+      get {
+        string address = GetXmlNodeString(_selectionRangePath);
+        if (address == "") {
+          return "A1";
+        }
+        return address;
+      }
+      set {
+        int toCol,
+            toRow;
+        if (_selectionNode == null) {
+          CreateSelectionElement();
+        }
+        ExcelCellBase.GetRowColFromAddress(
+            value,
+            out var fromRow,
+            out var fromCol,
+            out toRow,
+            out toCol);
+        SetXmlNodeString(_selectionRangePath, value);
+        if (((XmlElement)TopNode).GetAttribute("activeCell") == "") {
+          ActiveCell = ExcelCellBase.GetAddress(fromRow, fromCol);
+        }
+        //TODO:Add fix for out of range here
+      }
+    }
+  }
+
+  private readonly ExcelWorksheet _worksheet;
+
+  protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
+    "sheetViews",
+    "sheetView",
+    "pane",
+    "selection",
+  ];
+
+  /// <summary>
+  /// Creates a new ExcelWorksheetView which provides access to all the view states of the worksheet.
+  /// </summary>
+  /// <param name="ns"></param>
+  /// <param name="node"></param>
+  /// <param name="xlWorksheet"></param>
+  internal ExcelWorksheetView(XmlNamespaceManager ns, XmlNode node, ExcelWorksheet xlWorksheet)
+      : base(ns, node) {
+    _worksheet = xlWorksheet;
+    Panes = LoadPanes();
+  }
+
+  private ExcelWorksheetPanes[] LoadPanes() {
+    XmlNodeList nodes = TopNode.SelectNodes("//d:selection", NameSpaceManager);
+    if (nodes.Count == 0) {
+      return [new ExcelWorksheetPanes(NameSpaceManager, TopNode)];
+    }
+    ExcelWorksheetPanes[] panes = new ExcelWorksheetPanes[nodes.Count];
+    int i = 0;
+    foreach (XmlElement elem in nodes) {
+      panes[i++] = new(NameSpaceManager, elem);
+    }
+    return panes;
+  }
+
+  /// <summary>
+  /// Returns a reference to the sheetView element
+  /// </summary>
+  protected internal XmlElement SheetViewElement => (XmlElement)TopNode;
+
+  /// <summary>
+  /// The active cell.
+  /// </summary>
+  public string ActiveCell {
+    get => Panes[Panes.GetUpperBound(0)].ActiveCell;
+    set => Panes[Panes.GetUpperBound(0)].ActiveCell = value;
+  }
+
+  /// <summary>
+  /// Selected Cells in the worksheet.Used in combination with ActiveCell
+  /// </summary>
+  public string SelectedRange {
+    get => Panes[Panes.GetUpperBound(0)].SelectedRange;
+    set => Panes[Panes.GetUpperBound(0)].SelectedRange = value;
+  }
+
+  /// <summary>
+  /// Indicates if the worksheet is selected within the workbook
+  /// </summary>
+  public bool TabSelected {
+    get => GetXmlNodeBool("@tabSelected");
+    set {
+      if (value) {
+        //    // ensure no other worksheet has its tabSelected attribute set to 1
+        foreach (ExcelWorksheet sheet in _worksheet.Workbook.Worksheets) {
+          sheet.View.TabSelected = false;
+        }
+
+        SheetViewElement.SetAttribute("tabSelected", "1");
+        XmlElement bookView =
+            _worksheet.Workbook.WorkbookXml.SelectSingleNode(
+                "//d:workbookView",
+                _worksheet.NameSpaceManager) as XmlElement;
+        if (bookView != null) {
+          bookView.SetAttribute("activeTab", (_worksheet.PositionID - 1).ToString());
+        }
+      } else {
+        SetXmlNodeString("@tabSelected", "0");
+      }
+    }
+  }
+
+  /// <summary>
+  /// Sets the view mode of the worksheet to pagelayout
+  /// </summary>
+  public bool PageLayoutView {
+    get => GetXmlNodeString("@view") == "pageLayout";
+    set {
+      if (value) {
+        SetXmlNodeString("@view", "pageLayout");
+      } else {
+        SheetViewElement.RemoveAttribute("view");
+      }
+    }
+  }
+
+  /// <summary>
+  /// Sets the view mode of the worksheet to pagebreak
+  /// </summary>
+  public bool PageBreakView {
+    get => GetXmlNodeString("@view") == "pageBreakPreview";
+    set {
+      if (value) {
+        SetXmlNodeString("@view", "pageBreakPreview");
+      } else {
+        SheetViewElement.RemoveAttribute("view");
+      }
+    }
+  }
+
+  /// <summary>
+  /// Show gridlines in the worksheet
+  /// </summary>
+  public bool ShowGridLines {
+    get => GetXmlNodeBool("@showGridLines");
+    set => SetXmlNodeString("@showGridLines", value ? "1" : "0");
+  }
+
+  /// <summary>
+  /// Show the Column/Row headers (containg column letters and row numbers)
+  /// </summary>
+  public bool ShowHeaders {
+    get => GetXmlNodeBool("@showRowColHeaders");
+    set => SetXmlNodeString("@showRowColHeaders", value ? "1" : "0");
+  }
+
+  /// <summary>
+  /// Window zoom magnification for current view representing percent values.
+  /// </summary>
+  public int ZoomScale {
+    get => GetXmlNodeInt("@zoomScale");
+    set {
+      if (value < 10 || value > 400) {
+        throw new ArgumentOutOfRangeException("Zoome scale out of range (10-400)");
+      }
+      SetXmlNodeString("@zoomScale", value.ToString());
+    }
+  }
+
+  /// <summary>
+  /// Flag indicating whether the sheet is in 'right to left' display mode. When in this mode,Column A is on the far right, Column B ;is one column left of Column A, and so on. Also,information in cells is displayed in the Right to Left format.
+  /// </summary>
+  public bool RightToLeft {
+    get => GetXmlNodeBool("@rightToLeft");
+    set => SetXmlNodeString("@rightToLeft", value ? "1" : "0");
+  }
+
+  internal bool WindowProtection {
+    get => GetXmlNodeBool("@windowProtection", false);
+    set => SetXmlNodeBool("@windowProtection", value, false);
+  }
+
+  /// <summary>
+  /// Reference to the panes
+  /// </summary>
+  public ExcelWorksheetPanes[] Panes { get; internal set; }
+
+  private readonly string _paneNodePath = "d:pane";
+  private readonly string _selectionNodePath = "d:selection";
+
+  /// <summary>
+  /// Freeze the columns/rows to left and above the cell
+  /// </summary>
+  /// <param name="row"></param>
+  /// <param name="column"></param>
+  public void FreezePanes(int row, int column) {
+    //TODO:fix this method to handle splits as well.
+    if (row == 1 && column == 1) {
+      UnFreezePanes();
+    }
+    string sqRef = SelectedRange,
+        activeCell = ActiveCell;
+
+    XmlElement paneNode = TopNode.SelectSingleNode(_paneNodePath, NameSpaceManager) as XmlElement;
+    if (paneNode == null) {
+      CreateNode(_paneNodePath);
+      paneNode = TopNode.SelectSingleNode(_paneNodePath, NameSpaceManager) as XmlElement;
+    }
+    paneNode.RemoveAll(); //Clear all attributes
+    if (column > 1) {
+      paneNode.SetAttribute("xSplit", (column - 1).ToString());
+    }
+    if (row > 1) {
+      paneNode.SetAttribute("ySplit", (row - 1).ToString());
+    }
+    paneNode.SetAttribute("topLeftCell", ExcelCellBase.GetAddress(row, column));
+    paneNode.SetAttribute("state", "frozen");
+
+    RemoveSelection();
+
+    if (row > 1 && column == 1) {
+      paneNode.SetAttribute("activePane", "bottomLeft");
+      XmlElement sel = TopNode.OwnerDocument.CreateElement("selection", ExcelPackage._schemaMain);
+      sel.SetAttribute("pane", "bottomLeft");
+      if (activeCell != "") {
+        sel.SetAttribute("activeCell", activeCell);
+      }
+      if (sqRef != "") {
+        sel.SetAttribute("sqref", sqRef);
+      }
+      sel.SetAttribute("sqref", sqRef);
+      TopNode.InsertAfter(sel, paneNode);
+    } else if (column > 1 && row == 1) {
+      paneNode.SetAttribute("activePane", "topRight");
+      XmlElement sel = TopNode.OwnerDocument.CreateElement("selection", ExcelPackage._schemaMain);
+      sel.SetAttribute("pane", "topRight");
+      if (activeCell != "") {
+        sel.SetAttribute("activeCell", activeCell);
+      }
+      if (sqRef != "") {
+        sel.SetAttribute("sqref", sqRef);
+      }
+      TopNode.InsertAfter(sel, paneNode);
+    } else {
+      paneNode.SetAttribute("activePane", "bottomRight");
+      XmlElement sel1 = TopNode.OwnerDocument.CreateElement("selection", ExcelPackage._schemaMain);
+      sel1.SetAttribute("pane", "topRight");
+      string cell = ExcelCellBase.GetAddress(1, column);
+      sel1.SetAttribute("activeCell", cell);
+      sel1.SetAttribute("sqref", cell);
+      paneNode.ParentNode.InsertAfter(sel1, paneNode);
+
+      XmlElement sel2 = TopNode.OwnerDocument.CreateElement("selection", ExcelPackage._schemaMain);
+      cell = ExcelCellBase.GetAddress(row, 1);
+      sel2.SetAttribute("pane", "bottomLeft");
+      sel2.SetAttribute("activeCell", cell);
+      sel2.SetAttribute("sqref", cell);
+      sel1.ParentNode.InsertAfter(sel2, sel1);
+
+      XmlElement sel3 = TopNode.OwnerDocument.CreateElement("selection", ExcelPackage._schemaMain);
+      sel3.SetAttribute("pane", "bottomRight");
+      if (activeCell != "") {
+        sel3.SetAttribute("activeCell", activeCell);
+      }
+      if (sqRef != "") {
+        sel3.SetAttribute("sqref", sqRef);
+      }
+      sel2.ParentNode.InsertAfter(sel3, sel2);
+    }
+    Panes = LoadPanes();
+  }
+
+  private void RemoveSelection() {
+    //Find selection nodes and remove them
+    XmlNodeList selections = TopNode.SelectNodes(_selectionNodePath, NameSpaceManager);
+    foreach (XmlNode sel in selections) {
+      sel.ParentNode.RemoveChild(sel);
+    }
+  }
+
+  /// <summary>
+  /// Unlock all rows and columns to scroll freely
+  /// /// </summary>
+  public void UnFreezePanes() {
+    string sqRef = SelectedRange,
+        activeCell = ActiveCell;
+
+    XmlElement paneNode = TopNode.SelectSingleNode(_paneNodePath, NameSpaceManager) as XmlElement;
+    if (paneNode != null) {
+      paneNode.ParentNode.RemoveChild(paneNode);
+    }
+    RemoveSelection();
+
+    Panes = LoadPanes();
+
+    SelectedRange = sqRef;
+    ActiveCell = activeCell;
+  }
+}
diff --git a/AppsheetEpplus/ExcelWorksheets.cs b/AppsheetEpplus/ExcelWorksheets.cs
new file mode 100644
index 0000000..bb4e672
--- /dev/null
+++ b/AppsheetEpplus/ExcelWorksheets.cs
@@ -0,0 +1,335 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		    Initial Release		       2009-10-01
+ * Jan Källman		    License changed GPL-->LGPL 2011-12-27
+ *******************************************************************************/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// The collection of worksheets for the workbook
+/// </summary>
+public class ExcelWorksheets : XmlHelper, IEnumerable<ExcelWorksheet> {
+  private readonly ExcelPackage _pck;
+  private readonly ExcelWorkbook _workbook;
+  private Dictionary<int, ExcelWorksheet> _worksheets = new();
+  private readonly XmlNamespaceManager _namespaceManager;
+
+  internal ExcelWorksheets(
+      ExcelPackage pck,
+      ExcelWorkbook workbook,
+      XmlNamespaceManager nsm,
+      XmlNode topNode)
+      : base(nsm, topNode) {
+    _pck = pck;
+    _workbook = workbook;
+    _namespaceManager = nsm;
+    int positionId = 1;
+
+    foreach (XmlNode sheetNode in topNode.ChildNodes) {
+      if (sheetNode.NodeType == XmlNodeType.Element) {
+        string name = sheetNode.Attributes["name"].Value;
+        //Get the relationship id
+        string relId = sheetNode.Attributes["r:id"].Value;
+        int sheetId = Convert.ToInt32(sheetNode.Attributes["sheetId"].Value);
+
+        //Hidden property
+        eWorkSheetHidden hidden = eWorkSheetHidden.Visible;
+        XmlNode attr = sheetNode.Attributes["state"];
+        if (attr != null) {
+          hidden = TranslateHidden(attr.Value);
+        }
+
+        var sheetRelation = _workbook.Part.GetRelationship(relId);
+        Uri uriWorksheet = UriHelper.ResolvePartUri(
+            ExcelWorkbook.WorkbookUri,
+            sheetRelation.TargetUri);
+
+        //add the worksheet
+        if (sheetRelation.RelationshipType.EndsWith("chartsheet")) {
+          _worksheets.Add(
+              positionId,
+              new ExcelChartsheet(
+                  _namespaceManager,
+                  pck,
+                  _workbook,
+                  uriWorksheet,
+                  name,
+                  sheetId,
+                  positionId,
+                  hidden));
+        } else {
+          _worksheets.Add(
+              positionId,
+              new(
+                  _namespaceManager,
+                  pck,
+                  _workbook,
+                  uriWorksheet,
+                  name,
+                  sheetId,
+                  positionId,
+                  hidden));
+        }
+        positionId++;
+      }
+    }
+  }
+
+  private eWorkSheetHidden TranslateHidden(string value) {
+    switch (value) {
+      case "hidden":
+        return eWorkSheetHidden.Hidden;
+      case "veryHidden":
+        return eWorkSheetHidden.VeryHidden;
+      default:
+        return eWorkSheetHidden.Visible;
+    }
+  }
+
+  /// <summary>
+  /// Returns the number of worksheets in the workbook
+  /// </summary>
+  public int Count => (_worksheets.Count);
+
+  private const string _errDupWorksheet =
+      "A worksheet with this name already exists in the workbook";
+  internal const string _worksheetContentType =
+      "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml";
+
+  /// <summary>
+  /// Foreach support
+  /// </summary>
+  /// <returns>An enumerator</returns>
+  public IEnumerator<ExcelWorksheet> GetEnumerator() {
+    return (_worksheets.Values.GetEnumerator());
+  }
+
+  IEnumerator IEnumerable.GetEnumerator() {
+    return (_worksheets.Values.GetEnumerator());
+  }
+
+  /// <summary>
+  /// Adds a new blank worksheet.
+  /// </summary>
+  /// <param name="name">The name of the workbook</param>
+  public ExcelWorksheet Add(string name) {
+    name = ValidateFixSheetName(name);
+    if (GetByName(name) != null) {
+      throw (new InvalidOperationException(_errDupWorksheet + " : " + name));
+    }
+    GetSheetUri(ref name, out var sheetId, out var uriWorksheet, false);
+
+    // Create the new worksheet
+    var rel = _pck.CreateXmlDocument(
+        uriWorksheet,
+        _worksheetContentType,
+        ExcelPackage._schemaRelationships + "/worksheet",
+        CreateNewWorksheet(false));
+
+    // Add worksheet to the workbook
+    XmlElement worksheetNode = _workbook.WorkbookXml.CreateElement(
+        "sheet",
+        ExcelPackage._schemaMain);
+    worksheetNode.SetAttribute("name", name);
+    worksheetNode.SetAttribute("sheetId", sheetId.ToString());
+    worksheetNode.SetAttribute("id", ExcelPackage._schemaRelationships, rel.Id);
+    TopNode.AppendChild(worksheetNode);
+
+    int positionId = _worksheets.Count + 1;
+
+    ExcelWorksheet worksheet = new(
+        _namespaceManager,
+        _pck,
+        _workbook,
+        uriWorksheet,
+        name,
+        sheetId,
+        positionId,
+        eWorkSheetHidden.Visible);
+
+    _worksheets.Add(positionId, worksheet);
+    return worksheet;
+  }
+
+  private void GetSheetUri(ref string name, out int sheetId, out Uri uriWorksheet, bool isChart) {
+    name = ValidateFixSheetName(name);
+
+    //First find maximum existing sheetID
+    sheetId = 0;
+    foreach (var ws in this) {
+      if (ws.SheetID > sheetId) {
+        sheetId = ws.SheetID;
+      }
+    }
+    // we now have the max existing values, so add one
+    sheetId++;
+
+    // add the new worksheet to the package
+    if (isChart) {
+      uriWorksheet = new("/xl/chartsheets/chartsheet" + sheetId + ".xml", UriKind.Relative);
+    } else {
+      uriWorksheet = new("/xl/worksheets/sheet" + sheetId + ".xml", UriKind.Relative);
+    }
+  }
+
+  internal string ValidateFixSheetName(string name) {
+    //remove invalid characters
+    if (ValidateName(name)) {
+      if (name.IndexOf(':') > -1) {
+        name = name.Replace(":", " ");
+      }
+      if (name.IndexOf('/') > -1) {
+        name = name.Replace("/", " ");
+      }
+      if (name.IndexOf('\\') > -1) {
+        name = name.Replace("\\", " ");
+      }
+      if (name.IndexOf('?') > -1) {
+        name = name.Replace("?", " ");
+      }
+      if (name.IndexOf('[') > -1) {
+        name = name.Replace("[", " ");
+      }
+      if (name.IndexOf(']') > -1) {
+        name = name.Replace("]", " ");
+      }
+    }
+
+    if (name.Trim() == "") {
+      throw new ArgumentException("The worksheet can not have an empty name");
+    }
+    if (name.Length > 31) {
+      name = name.Substring(0, 31); //A sheet can have max 31 char's
+    }
+    return name;
+  }
+
+  /// <summary>
+  /// Validate the sheetname
+  /// </summary>
+  /// <param name="name">The Name</param>
+  /// <returns>True if valid</returns>
+  private bool ValidateName(string name) {
+    return Regex.IsMatch(name, @":|\?|/|\\|\[|\]");
+  }
+
+  /// <summary>
+  /// Creates the XML document representing a new empty worksheet
+  /// </summary>
+  /// <returns></returns>
+  internal XmlDocument CreateNewWorksheet(bool isChart) {
+    XmlDocument xmlDoc = new XmlDocument();
+    XmlElement elemWs = xmlDoc.CreateElement(
+        isChart ? "chartsheet" : "worksheet",
+        ExcelPackage._schemaMain);
+    elemWs.SetAttribute("xmlns:r", ExcelPackage._schemaRelationships);
+    xmlDoc.AppendChild(elemWs);
+
+    if (isChart) {
+      XmlElement elemSheetPr = xmlDoc.CreateElement("sheetPr", ExcelPackage._schemaMain);
+      elemWs.AppendChild(elemSheetPr);
+
+      XmlElement elemSheetViews = xmlDoc.CreateElement("sheetViews", ExcelPackage._schemaMain);
+      elemWs.AppendChild(elemSheetViews);
+
+      XmlElement elemSheetView = xmlDoc.CreateElement("sheetView", ExcelPackage._schemaMain);
+      elemSheetView.SetAttribute("workbookViewId", "0");
+      elemSheetView.SetAttribute("zoomToFit", "1");
+
+      elemSheetViews.AppendChild(elemSheetView);
+    } else {
+      XmlElement elemSheetViews = xmlDoc.CreateElement("sheetViews", ExcelPackage._schemaMain);
+      elemWs.AppendChild(elemSheetViews);
+
+      XmlElement elemSheetView = xmlDoc.CreateElement("sheetView", ExcelPackage._schemaMain);
+      elemSheetView.SetAttribute("workbookViewId", "0");
+      elemSheetViews.AppendChild(elemSheetView);
+
+      XmlElement elemSheetFormatPr = xmlDoc.CreateElement(
+          "sheetFormatPr",
+          ExcelPackage._schemaMain);
+      elemSheetFormatPr.SetAttribute("defaultRowHeight", "15");
+      elemWs.AppendChild(elemSheetFormatPr);
+
+      XmlElement elemSheetData = xmlDoc.CreateElement("sheetData", ExcelPackage._schemaMain);
+      elemWs.AppendChild(elemSheetData);
+    }
+    return xmlDoc;
+  }
+
+  /// <summary>
+  /// Returns the worksheet at the specified position.
+  /// </summary>
+  /// <param name="positionId">The position of the worksheet. 1-base</param>
+  /// <returns></returns>
+  public ExcelWorksheet this[int positionId] {
+    get {
+      if (_worksheets.ContainsKey(positionId)) {
+        return _worksheets[positionId];
+      }
+      throw (new IndexOutOfRangeException("Worksheet position out of range."));
+    }
+  }
+
+  /// <summary>
+  /// Returns the worksheet matching the specified name
+  /// </summary>
+  /// <param name="name">The name of the worksheet</param>
+  /// <returns></returns>
+  public ExcelWorksheet this[string name] => GetByName(name);
+
+  internal ExcelWorksheet GetBySheetId(int localSheetId) {
+    foreach (ExcelWorksheet ws in this) {
+      if (ws.SheetID == localSheetId) {
+        return ws;
+      }
+    }
+    return null;
+  }
+
+  private ExcelWorksheet GetByName(string name) {
+    if (string.IsNullOrEmpty(name)) {
+      return null;
+    }
+    ExcelWorksheet xlWorksheet = null;
+    foreach (ExcelWorksheet worksheet in _worksheets.Values) {
+      if (worksheet.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)) {
+        xlWorksheet = worksheet;
+      }
+    }
+    return (xlWorksheet);
+  }
+} // end class Worksheets
diff --git a/AppsheetEpplus/FormulaParsing/CalculateExtentions.cs b/AppsheetEpplus/FormulaParsing/CalculateExtentions.cs
new file mode 100644
index 0000000..0d6c5b0
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/CalculateExtentions.cs
@@ -0,0 +1,156 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman                      Added                       2012-03-04
+ *******************************************************************************/
+
+using System;
+
+namespace AppsheetEpplus;
+
+public static class CalculationExtension {
+  public static void Calculate(this ExcelWorkbook workbook) {
+    Calculate(
+        workbook,
+        new() {
+          AllowCirculareReferences = false,
+        });
+  }
+
+  public static void Calculate(this ExcelWorkbook workbook, ExcelCalculationOption options) {
+    Init(workbook);
+
+    var dc = DependencyChainFactory.Create(workbook, options);
+    workbook.FormulaParser.InitNewCalc();
+    CalcChain(workbook, workbook.FormulaParser, dc);
+  }
+
+  public static void Calculate(this ExcelWorksheet worksheet) {
+    Calculate(worksheet, new ExcelCalculationOption());
+  }
+
+  public static void Calculate(this ExcelWorksheet worksheet, ExcelCalculationOption options) {
+    Init(worksheet.Workbook);
+    //worksheet.Workbook._formulaParser = null; TODO:Cant reset. Don't work with userdefined or overrided worksheet functions
+    var dc = DependencyChainFactory.Create(worksheet, options);
+
+    // Display Calc Chain to determine why formula calculation is taking so long.
+    // Uncomment the following line to display the Calc Chain.
+    // DisplayCalcChain(worksheet, dc);
+
+    var parser = worksheet.Workbook.FormulaParser;
+    parser.InitNewCalc();
+    CalcChain(worksheet.Workbook, parser, dc);
+  }
+
+  public static void Calculate(this ExcelRangeBase range) {
+    Calculate(range, new());
+  }
+
+  public static void Calculate(this ExcelRangeBase range, ExcelCalculationOption options) {
+    Init(range._workbook);
+    var parser = range._workbook.FormulaParser;
+    parser.InitNewCalc();
+    var dc = DependencyChainFactory.Create(range, options);
+    CalcChain(range._workbook, parser, dc);
+  }
+
+  public static object Calculate(this ExcelWorksheet worksheet, string formula) {
+    return Calculate(worksheet, formula, new());
+  }
+
+  public static object Calculate(
+      this ExcelWorksheet worksheet,
+      string formula,
+      ExcelCalculationOption options) {
+    try {
+      worksheet.CheckSheetType();
+      if (string.IsNullOrEmpty(formula.Trim())) {
+        return null;
+      }
+      Init(worksheet.Workbook);
+      var parser = worksheet.Workbook.FormulaParser;
+      parser.InitNewCalc();
+      if (formula[0] == '=') {
+        formula = formula.Substring(1); //Remove any starting equal sign
+      }
+      var dc = DependencyChainFactory.Create(worksheet, formula, options);
+      var f = dc.list[0];
+      dc.CalcOrder.RemoveAt(dc.CalcOrder.Count - 1);
+
+      CalcChain(worksheet.Workbook, parser, dc);
+
+      return parser.ParseCell(f.Tokens, worksheet.Name, -1, -1);
+    } catch (Exception ex) {
+      return new ExcelErrorValueException(ex.Message, ExcelErrorValue.Create(eErrorType.Value));
+    }
+  }
+
+  private static void CalcChain(ExcelWorkbook wb, FormulaParser parser, DependencyChain dc) {
+    foreach (var ix in dc.CalcOrder) {
+      var item = dc.list[ix];
+      try {
+        var ws = wb.Worksheets.GetBySheetId(item.SheetID);
+        var v = parser.ParseCell(item.Tokens, ws == null ? "" : ws.Name, item.Row, item.Column);
+        SetValue(wb, item, v);
+      } catch (FunctionException) {
+        // Excel function is not supported by EPPlus
+        throw;
+      } catch (FormatException) {
+        throw;
+      } catch (Exception) {
+        var error = ExcelErrorValue.Parse(ExcelErrorValue.Values.Value);
+        SetValue(wb, item, error);
+      }
+    }
+  }
+
+  private static void Init(ExcelWorkbook workbook) {
+    workbook._formulaTokens = new();
+    ;
+    foreach (var ws in workbook.Worksheets) {
+      if (!(ws is ExcelChartsheet)) {
+        ws._formulaTokens = new();
+      }
+    }
+  }
+
+  private static void SetValue(ExcelWorkbook workbook, FormulaCell item, object v) {
+    if (item.Column == 0) {
+      if (item.SheetID <= 0) {
+        workbook.Names[item.Row].NameValue = v;
+      } else {
+        var sh = workbook.Worksheets.GetBySheetId(item.SheetID);
+        sh.Names[item.Row].NameValue = v;
+      }
+    } else {
+      var sheet = workbook.Worksheets.GetBySheetId(item.SheetID);
+      sheet._values.SetValue(item.Row, item.Column, v);
+    }
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/DependencyChain/DependencyChain.cs b/AppsheetEpplus/FormulaParsing/DependencyChain/DependencyChain.cs
new file mode 100644
index 0000000..14545d8
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/DependencyChain/DependencyChain.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+internal class DependencyChain {
+  internal List<FormulaCell> list = new();
+  internal Dictionary<ulong, int> index = new();
+  internal List<int> CalcOrder = new();
+
+  internal void Add(FormulaCell f) {
+    list.Add(f);
+    f.Index = list.Count - 1;
+    index.Add(ExcelCellBase.GetCellId(f.SheetID, f.Row, f.Column), f.Index);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/DependencyChain/DependenyChainFactory.cs b/AppsheetEpplus/FormulaParsing/DependencyChain/DependenyChainFactory.cs
new file mode 100644
index 0000000..6deb844
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/DependencyChain/DependenyChainFactory.cs
@@ -0,0 +1,371 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman                      Added                       2012-03-04
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+internal static class DependencyChainFactory {
+  internal static DependencyChain Create(ExcelWorkbook wb, ExcelCalculationOption options) {
+    var depChain = new DependencyChain();
+    foreach (var ws in wb.Worksheets) {
+      if (!(ws is ExcelChartsheet)) {
+        GetChain(depChain, wb.FormulaParser.Lexer, ws.Cells, options);
+        GetWorksheetNames(ws, depChain, options);
+      }
+    }
+    foreach (var name in wb.Names) {
+      if (name.NameValue == null) {
+        GetChain(depChain, wb.FormulaParser.Lexer, name, options);
+      }
+    }
+    return depChain;
+  }
+
+  internal static DependencyChain Create(ExcelWorksheet ws, ExcelCalculationOption options) {
+    ws.CheckSheetType();
+    var depChain = new DependencyChain();
+
+    GetChain(depChain, ws.Workbook.FormulaParser.Lexer, ws.Cells, options);
+
+    GetWorksheetNames(ws, depChain, options);
+
+    return depChain;
+  }
+
+  internal static DependencyChain Create(
+      ExcelWorksheet ws,
+      string formula,
+      ExcelCalculationOption options) {
+    ws.CheckSheetType();
+    var depChain = new DependencyChain();
+
+    GetChain(depChain, ws.Workbook.FormulaParser.Lexer, ws, formula, options);
+
+    return depChain;
+  }
+
+  private static void GetWorksheetNames(
+      ExcelWorksheet ws,
+      DependencyChain depChain,
+      ExcelCalculationOption options) {
+    foreach (var name in ws.Names) {
+      if (!string.IsNullOrEmpty(name.NameFormula)) {
+        GetChain(depChain, ws.Workbook.FormulaParser.Lexer, name, options);
+      }
+    }
+  }
+
+  internal static DependencyChain Create(ExcelRangeBase range, ExcelCalculationOption options) {
+    var depChain = new DependencyChain();
+
+    GetChain(depChain, range.Worksheet.Workbook.FormulaParser.Lexer, range, options);
+
+    return depChain;
+  }
+
+  private static void GetChain(
+      DependencyChain depChain,
+      ILexer lexer,
+      ExcelNamedRange name,
+      ExcelCalculationOption options) {
+    var ws = name.Worksheet;
+    var id = ExcelCellBase.GetCellId(ws?.SheetID ?? 0, name.Index, 0);
+    if (!depChain.index.ContainsKey(id)) {
+      var f = new FormulaCell {
+        SheetID = ws?.SheetID ?? 0,
+        Row = name.Index,
+        Column = 0,
+        Formula = name.NameFormula,
+      };
+      if (!string.IsNullOrEmpty(f.Formula)) {
+        f.Tokens = lexer.Tokenize(f.Formula, ws?.Name).ToList();
+        if (ws == null) {
+          name._workbook._formulaTokens.SetValue(name.Index, 0, f.Tokens);
+        } else {
+          ws._formulaTokens.SetValue(name.Index, 0, f.Tokens);
+        }
+        depChain.Add(f);
+        FollowChain(depChain, lexer, name._workbook, ws, f, options);
+      }
+    }
+  }
+
+  private static void GetChain(
+      DependencyChain depChain,
+      ILexer lexer,
+      ExcelWorksheet ws,
+      string formula,
+      ExcelCalculationOption options) {
+    var f = new FormulaCell {
+      SheetID = ws.SheetID,
+      Row = -1,
+      Column = -1,
+    };
+    f.Formula = formula;
+    if (!string.IsNullOrEmpty(f.Formula)) {
+      f.Tokens = lexer.Tokenize(f.Formula, ws.Name).ToList();
+      depChain.Add(f);
+      FollowChain(depChain, lexer, ws.Workbook, ws, f, options);
+    }
+  }
+
+  private static void GetChain(
+      DependencyChain depChain,
+      ILexer lexer,
+      ExcelRangeBase range,
+      ExcelCalculationOption options) {
+    var ws = range.Worksheet;
+    var fs = new CellsStoreEnumerator<object>(
+        ws._formulas,
+        range.Start.Row,
+        range.Start.Column,
+        range.End.Row,
+        range.End.Column);
+    while (fs.Next()) {
+      if (fs.Value == null || fs.Value.ToString().Trim() == "") {
+        continue;
+      }
+      var id = ExcelCellBase.GetCellId(ws.SheetID, fs.Row, fs.Column);
+      if (!depChain.index.ContainsKey(id)) {
+        var f = new FormulaCell {
+          SheetID = ws.SheetID,
+          Row = fs.Row,
+          Column = fs.Column,
+        };
+        if (fs.Value is int value) {
+          f.Formula = ws._sharedFormulas[value].GetFormula(fs.Row, fs.Column, ws.Name);
+        } else {
+          f.Formula = fs.Value.ToString();
+        }
+        if (!string.IsNullOrEmpty(f.Formula)) {
+          f.Tokens = lexer.Tokenize(f.Formula, range.Worksheet.Name).ToList();
+          ws._formulaTokens.SetValue(fs.Row, fs.Column, f.Tokens);
+          depChain.Add(f);
+          FollowChain(depChain, lexer, ws.Workbook, ws, f, options);
+        }
+      }
+    }
+  }
+
+  /// <summary>
+  /// This method follows the calculation chain to get the order of the calculation
+  /// Goto (!) is used internally to prevent stackoverflow on extremly larget dependency trees (that is, many recursive formulas).
+  /// </summary>
+  /// <param name="depChain">The dependency chain object</param>
+  /// <param name="lexer">The formula tokenizer</param>
+  /// <param name="wb">The workbook where the formula comes from</param>
+  /// <param name="ws">The worksheet where the formula comes from</param>
+  /// <param name="f">The cell function object</param>
+  /// <param name="options">Calcultaiton options</param>
+  private static void FollowChain(
+      DependencyChain depChain,
+      ILexer lexer,
+      ExcelWorkbook wb,
+      ExcelWorksheet ws,
+      FormulaCell f,
+      ExcelCalculationOption options) {
+    Stack<FormulaCell> stack = new Stack<FormulaCell>();
+    iterateToken:
+    while (f.tokenIx < f.Tokens.Count) {
+      var t = f.Tokens[f.tokenIx];
+      if (t.TokenType == TokenType.ExcelAddress) {
+        var adr = new ExcelFormulaAddress(t.Value);
+        if (adr.Table != null) {
+          adr.SetRcFromTable(ws.Workbook, new(f.Row, f.Column, f.Row, f.Column));
+        }
+
+        if (adr.WorkSheet == null
+            && adr.Collide(new(f.Row, f.Column, f.Row, f.Column))
+                != ExcelAddressBase.eAddressCollition.No) {
+          throw (new CircularReferenceException(
+                  string.Format(
+                      "Circular Reference in cell {0}",
+                      ExcelCellBase.GetAddress(f.Row, f.Column))));
+        }
+
+        if (adr._fromRow > 0 && adr._fromCol > 0) {
+          if (string.IsNullOrEmpty(adr.WorkSheet)) {
+            if (f.ws == null) {
+              f.ws = ws;
+            } else if (f.ws.SheetID != f.SheetID) {
+              f.ws = wb.Worksheets.GetBySheetId(f.SheetID);
+            }
+          } else {
+            f.ws = wb.Worksheets[adr.WorkSheet];
+          }
+
+          if (f.ws != null) {
+            f.iterator = new(
+                f.ws._formulas,
+                adr.Start.Row,
+                adr.Start.Column,
+                adr.End.Row,
+                adr.End.Column);
+            goto iterateCells;
+          }
+        }
+      } else if (t.TokenType == TokenType.NameValue) {
+        string adrWb;
+        ExcelNamedRange name;
+        ExcelAddressBase.SplitAddress(
+            t.Value,
+            out adrWb,
+            out var adrWs,
+            out var adrName,
+            f.ws == null ? "" : f.ws.Name);
+        if (!string.IsNullOrEmpty(adrWs)) {
+          if (f.ws == null) {
+            f.ws = wb.Worksheets[adrWs];
+          }
+          if (f.ws.Names.ContainsKey(t.Value)) {
+            name = f.ws.Names[adrName];
+          } else if (wb.Names.ContainsKey(adrName)) {
+            name = wb.Names[adrName];
+          } else {
+            name = null;
+          }
+          if (name != null) {
+            f.ws = name.Worksheet;
+          }
+        } else if (wb.Names.ContainsKey(adrName)) {
+          name = wb.Names[t.Value];
+          if (string.IsNullOrEmpty(adrWs)) {
+            f.ws = name.Worksheet;
+          }
+        } else {
+          name = null;
+        }
+
+        if (name != null) {
+          if (string.IsNullOrEmpty(name.NameFormula)) {
+            if (name.NameValue == null) {
+              f.iterator = new(
+                  f.ws._formulas,
+                  name.Start.Row,
+                  name.Start.Column,
+                  name.End.Row,
+                  name.End.Column);
+              goto iterateCells;
+            }
+          } else {
+            var id = ExcelCellBase.GetCellId(name.LocalSheetId, name.Index, 0);
+
+            if (!depChain.index.ContainsKey(id)) {
+              var rf = new FormulaCell {
+                SheetID = name.LocalSheetId,
+                Row = name.Index,
+                Column = 0,
+              };
+              rf.Formula = name.NameFormula;
+              rf.Tokens =
+                  name.LocalSheetId == -1
+                      ? lexer.Tokenize(rf.Formula).ToList()
+                      : lexer
+                          .Tokenize(rf.Formula, wb.Worksheets.GetBySheetId(name.LocalSheetId).Name)
+                          .ToList();
+
+              depChain.Add(rf);
+              stack.Push(f);
+              f = rf;
+              goto iterateToken;
+            }
+            if (stack.Count > 0) {
+              //Check for circular references
+              foreach (var par in stack) {
+                if (ExcelCellBase.GetCellId(par.SheetID, par.Row, par.Column) == id) {
+                  throw (new CircularReferenceException(
+                          string.Format("Circular Reference in name {0}", name.Name)));
+                }
+              }
+            }
+          }
+        }
+      }
+      f.tokenIx++;
+    }
+    depChain.CalcOrder.Add(f.Index);
+    if (stack.Count > 0) {
+      f = stack.Pop();
+      goto iterateCells;
+    }
+    return;
+    iterateCells:
+
+    while (f.iterator != null && f.iterator.Next()) {
+      var v = f.iterator.Value;
+      if (v == null || v.ToString().Trim() == "") {
+        continue;
+      }
+      var id = ExcelCellBase.GetCellId(f.ws.SheetID, f.iterator.Row, f.iterator.Column);
+      if (!depChain.index.ContainsKey(id)) {
+        var rf = new FormulaCell {
+          SheetID = f.ws.SheetID,
+          Row = f.iterator.Row,
+          Column = f.iterator.Column,
+        };
+        if (f.iterator.Value is int) {
+          rf.Formula = f.ws._sharedFormulas[(int)v]
+              .GetFormula(f.iterator.Row, f.iterator.Column, ws.Name);
+        } else {
+          rf.Formula = v.ToString();
+        }
+        rf.ws = f.ws;
+        rf.Tokens = lexer.Tokenize(rf.Formula, f.ws.Name).ToList();
+        ws._formulaTokens.SetValue(rf.Row, rf.Column, rf.Tokens);
+        depChain.Add(rf);
+        stack.Push(f);
+        f = rf;
+        goto iterateToken;
+      }
+      if (stack.Count > 0) {
+        //Check for circular references
+        foreach (var par in stack) {
+          if (ExcelCellBase.GetCellId(par.ws.SheetID, par.iterator.Row, par.iterator.Column)
+              == id) {
+            if (options.AllowCirculareReferences == false) {
+              throw (new CircularReferenceException(
+                      string.Format(
+                          "Circular Reference in cell {0}!{1}",
+                          par.ws.Name,
+                          ExcelCellBase.GetAddress(f.Row, f.Column))));
+            }
+            f = stack.Pop();
+            goto iterateCells;
+          }
+        }
+      }
+    }
+    f.tokenIx++;
+    goto iterateToken;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/DependencyChain/FormulaCell.cs b/AppsheetEpplus/FormulaParsing/DependencyChain/FormulaCell.cs
new file mode 100644
index 0000000..50ceb10
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/DependencyChain/FormulaCell.cs
@@ -0,0 +1,47 @@
+/* Copyright (C) 2011  Jan K�llman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+internal class FormulaCell {
+  internal int Index { get; set; }
+
+  internal int SheetID { get; set; }
+
+  internal int Row { get; set; }
+
+  internal int Column { get; set; }
+
+  internal string Formula { get; set; }
+
+  internal List<Token> Tokens { get; set; }
+
+  internal int tokenIx = 0;
+  internal int addressIx = 0;
+  internal CellsStoreEnumerator<object> iterator;
+  internal ExcelWorksheet ws;
+}
diff --git a/AppsheetEpplus/FormulaParsing/EpplusExcelDataProvider.cs b/AppsheetEpplus/FormulaParsing/EpplusExcelDataProvider.cs
new file mode 100644
index 0000000..b6feb98
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/EpplusExcelDataProvider.cs
@@ -0,0 +1,355 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class EpplusExcelDataProvider : ExcelDataProvider {
+  public class RangeInfo : IRangeInfo {
+    internal ExcelWorksheet _ws;
+    private readonly CellsStoreEnumerator<object> _values;
+    private readonly int _fromRow;
+    private readonly int _toRow;
+    private readonly int _fromCol;
+    private readonly int _toCol;
+    private int _cellCount;
+    private readonly ExcelAddressBase _address;
+    private readonly ICellInfo _cell;
+
+    public RangeInfo(ExcelWorksheet ws, int fromRow, int fromCol, int toRow, int toCol) {
+      _ws = ws;
+      _fromRow = fromRow;
+      _fromCol = fromCol;
+      _toRow = toRow;
+      _toCol = toCol;
+      _address = new(_fromRow, _fromCol, _toRow, _toCol);
+      _address._ws = ws.Name;
+      _values = new(ws._values, _fromRow, _fromCol, _toRow, _toCol);
+      _cell = new CellInfo(_ws, _values);
+    }
+
+    public int GetNCells() {
+      return ((_toRow - _fromRow) + 1) * ((_toCol - _fromCol) + 1);
+    }
+
+    public bool IsEmpty {
+      get {
+        if (_cellCount > 0) {
+          return false;
+        }
+        if (_values.Next()) {
+          _values.Reset();
+          return false;
+        }
+        return true;
+      }
+    }
+
+    public bool IsMulti {
+      get {
+        if (_cellCount == 0) {
+          if (_values.Next() && _values.Next()) {
+            _values.Reset();
+            return true;
+          }
+          _values.Reset();
+          return false;
+        }
+        if (_cellCount > 1) {
+          return true;
+        }
+        return false;
+      }
+    }
+
+    public ICellInfo Current => _cell;
+
+    public ExcelWorksheet Worksheet => _ws;
+
+    public void Dispose() {}
+
+    object IEnumerator.Current => this;
+
+    public bool MoveNext() {
+      _cellCount++;
+      return _values.MoveNext();
+    }
+
+    public void Reset() {
+      _values.Init();
+    }
+
+    public bool NextCell() {
+      _cellCount++;
+      return _values.MoveNext();
+    }
+
+    public IEnumerator<ICellInfo> GetEnumerator() {
+      Reset();
+      return this;
+    }
+
+    IEnumerator IEnumerable.GetEnumerator() {
+      return this;
+    }
+
+    public ExcelAddressBase Address => _address;
+
+    public object GetValue(int row, int col) {
+      return _ws.GetValue(row, col);
+    }
+
+    public object GetOffset(int rowOffset, int colOffset) {
+      if (_values.Row < _fromRow || _values.Column < _fromCol) {
+        return _ws.GetValue(_fromRow + rowOffset, _fromCol + colOffset);
+      }
+      return _ws.GetValue(_values.Row + rowOffset, _values.Column + colOffset);
+    }
+  }
+
+  public class CellInfo : ICellInfo {
+    private readonly ExcelWorksheet _ws;
+    private readonly CellsStoreEnumerator<object> _values;
+
+    internal CellInfo(ExcelWorksheet ws, CellsStoreEnumerator<object> values) {
+      _ws = ws;
+      _values = values;
+    }
+
+    public string Address => _values.CellAddress;
+
+    public int Row => _values.Row;
+
+    public int Column => _values.Column;
+
+    public string Formula => _ws.GetFormula(_values.Row, _values.Column);
+
+    public object Value => _values.Value;
+
+    public double ValueDouble => ConvertUtil.GetValueDouble(_values.Value, true);
+
+    public double ValueDoubleLogical => ConvertUtil.GetValueDouble(_values.Value);
+
+    public bool IsHiddenRow {
+      get {
+        var row = _ws._values.GetValue(_values.Row, 0) as RowInternal;
+        if (row != null) {
+          return row.Hidden || row.Height == 0;
+        }
+        return false;
+      }
+    }
+
+    public bool IsExcelError => ExcelErrorValue.Values.IsErrorValue(_values.Value);
+
+    public IList<Token> Tokens => _ws._formulaTokens.GetValue(_values.Row, _values.Column);
+  }
+
+  public class NameInfo : INameInfo {
+    public ulong Id { get; set; }
+
+    public string Worksheet { get; set; }
+
+    public string Name { get; set; }
+
+    public string Formula { get; set; }
+
+    public IList<Token> Tokens { get; internal set; }
+
+    public object Value { get; set; }
+  }
+
+  private readonly ExcelWorkbook _workbook;
+  private ExcelWorksheet _currentWorksheet;
+  private Dictionary<ulong, INameInfo> _names = new();
+
+  public EpplusExcelDataProvider(ExcelWorkbook workbook) {
+    _workbook = workbook;
+  }
+
+  public override ExcelNamedRangeCollection GetWorksheetNames(string worksheet) {
+    var ws = _workbook.Worksheets[worksheet];
+    if (ws != null) {
+      return ws.Names;
+    }
+    return null;
+  }
+
+  public override ExcelNamedRangeCollection GetWorkbookNameValues() {
+    return _workbook.Names;
+  }
+
+  public override IRangeInfo GetRange(
+      string worksheet,
+      int fromRow,
+      int fromCol,
+      int toRow,
+      int toCol) {
+    SetCurrentWorksheet(worksheet);
+    var wsName = string.IsNullOrEmpty(worksheet) ? _currentWorksheet.Name : worksheet;
+    var ws = _workbook.Worksheets[wsName];
+    return new RangeInfo(ws, fromRow, fromCol, toRow, toCol);
+  }
+
+  public override IRangeInfo GetRange(string worksheet, int row, int column, string address) {
+    var addr = new ExcelAddress(worksheet, address);
+    if (addr.Table != null) {
+      addr.SetRcFromTable(_workbook, new(row, column, row, column));
+    }
+    //SetCurrentWorksheet(addr.WorkSheet);
+    var wsName = string.IsNullOrEmpty(addr.WorkSheet) ? _currentWorksheet.Name : addr.WorkSheet;
+    var ws = _workbook.Worksheets[wsName];
+    //return new CellsStoreEnumerator<object>(ws._values, addr._fromRow, addr._fromCol, addr._toRow, addr._toCol);
+    return new RangeInfo(ws, addr._fromRow, addr._fromCol, addr._toRow, addr._toCol);
+  }
+
+  public override INameInfo GetName(string worksheet, string name) {
+    ExcelNamedRange nameItem;
+    ulong id;
+    ExcelWorksheet ws;
+    if (string.IsNullOrEmpty(worksheet)) {
+      if (_workbook.Names.ContainsKey(name)) {
+        nameItem = _workbook.Names[name];
+      } else {
+        return null;
+      }
+      ws = null;
+    } else {
+      ws = _workbook.Worksheets[worksheet];
+      if (ws != null && ws.Names.ContainsKey(name)) {
+        nameItem = ws.Names[name];
+      } else if (_workbook.Names.ContainsKey(name)) {
+        nameItem = _workbook.Names[name];
+      } else {
+        return null;
+      }
+    }
+    id = ExcelCellBase.GetCellId(nameItem.LocalSheetId, nameItem.Index, 0);
+
+    if (_names.ContainsKey(id)) {
+      return _names[id];
+    }
+    var ni = new NameInfo {
+      Id = id,
+      Name = name,
+      Worksheet = nameItem.Worksheet == null ? nameItem._ws : nameItem.Worksheet.Name,
+      Formula = nameItem.Formula,
+    };
+    if (nameItem._fromRow > 0) {
+      ni.Value = new RangeInfo(
+          nameItem.Worksheet ?? ws,
+          nameItem._fromRow,
+          nameItem._fromCol,
+          nameItem._toRow,
+          nameItem._toCol);
+    } else {
+      ni.Value = nameItem.Value;
+    }
+    _names.Add(id, ni);
+    return ni;
+  }
+
+  public override IEnumerable<object> GetRangeValues(string address) {
+    SetCurrentWorksheet(ExcelAddressInfo.Parse(address));
+    var addr = new ExcelAddress(address);
+    var wsName = string.IsNullOrEmpty(addr.WorkSheet) ? _currentWorksheet.Name : addr.WorkSheet;
+    var ws = _workbook.Worksheets[wsName];
+    return (new CellsStoreEnumerator<object>(
+            ws._values,
+            addr._fromRow,
+            addr._fromCol,
+            addr._toRow,
+            addr._toCol));
+  }
+
+  public object GetValue(int row, int column) {
+    return _currentWorksheet._values.GetValue(row, column);
+  }
+
+  public bool IsMerged(int row, int column) {
+    //return _currentWorksheet._flags.GetFlagValue(row, column, CellFlags.Merged);
+    return _currentWorksheet.MergedCells[row, column] != null;
+  }
+
+  public bool IsHidden(int row, int column) {
+    return _currentWorksheet.Column(column).Hidden
+        || _currentWorksheet.Column(column).Width == 0
+        || _currentWorksheet.Row(row).Hidden
+        || _currentWorksheet.Row(column).Height == 0;
+  }
+
+  public override object GetCellValue(string sheetName, int row, int col) {
+    SetCurrentWorksheet(sheetName);
+    return _currentWorksheet._values.GetValue(row, col);
+  }
+
+  public override ExcelCellAddress GetDimensionEnd(string worksheet) {
+    ExcelCellAddress address = null;
+    try {
+      address = _workbook.Worksheets[worksheet].Dimension.End;
+    } catch {}
+
+    return address;
+  }
+
+  private void SetCurrentWorksheet(ExcelAddressInfo addressInfo) {
+    if (addressInfo.WorksheetIsSpecified) {
+      _currentWorksheet = _workbook.Worksheets[addressInfo.Worksheet];
+    } else if (_currentWorksheet == null) {
+      _currentWorksheet = _workbook.Worksheets.First();
+    }
+  }
+
+  private void SetCurrentWorksheet(string worksheetName) {
+    if (!string.IsNullOrEmpty(worksheetName)) {
+      _currentWorksheet = _workbook.Worksheets[worksheetName];
+    } else {
+      _currentWorksheet = _workbook.Worksheets.First();
+    }
+  }
+
+  public override int ExcelMaxColumns => ExcelPackage.MaxColumns;
+
+  public override int ExcelMaxRows => ExcelPackage.MaxRows;
+
+  public override string GetRangeFormula(string worksheetName, int row, int column) {
+    SetCurrentWorksheet(worksheetName);
+    return _currentWorksheet.GetFormula(row, column);
+  }
+
+  public override object GetRangeValue(string worksheetName, int row, int column) {
+    SetCurrentWorksheet(worksheetName);
+    return _currentWorksheet.GetValue(row, column);
+  }
+
+  public override string GetFormat(object value, string format) {
+    var styles = _workbook.Styles;
+    ExcelNumberFormatXml.ExcelFormatTranslator ft = null;
+    foreach (var f in styles.NumberFormats) {
+      if (f.Format == format) {
+        ft = f.FormatTranslator;
+        break;
+      }
+    }
+    if (ft == null) {
+      ft = new(format, -1);
+    }
+    return ExcelRangeBase.FormatValue(value, ft, format, ft.NetFormat);
+  }
+
+  public override List<Token> GetRangeFormulaTokens(string worksheetName, int row, int column) {
+    return _workbook.Worksheets[worksheetName]._formulaTokens.GetValue(row, column);
+  }
+
+  public override bool IsRowHidden(string worksheetName, int row) {
+    var b =
+        _workbook.Worksheets[worksheetName].Row(row).Height == 0
+            || _workbook.Worksheets[worksheetName].Row(row).Hidden;
+
+    return b;
+  }
+
+  public override void Reset() {
+    _names = new(); //Reset name cache.
+  }
+}
diff --git a/EPPlus/FormulaParsing/EpplusExcelDataProvider.cs.orig b/AppsheetEpplus/FormulaParsing/EpplusExcelDataProvider.cs.orig
similarity index 100%
rename from EPPlus/FormulaParsing/EpplusExcelDataProvider.cs.orig
rename to AppsheetEpplus/FormulaParsing/EpplusExcelDataProvider.cs.orig
diff --git a/AppsheetEpplus/FormulaParsing/EpplusNameValueProvider.cs b/AppsheetEpplus/FormulaParsing/EpplusNameValueProvider.cs
new file mode 100644
index 0000000..18403de
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/EpplusNameValueProvider.cs
@@ -0,0 +1,29 @@
+namespace AppsheetEpplus;
+
+public class EpplusNameValueProvider : INameValueProvider {
+  private readonly ExcelDataProvider _excelDataProvider;
+  private ExcelNamedRangeCollection _values;
+
+  public EpplusNameValueProvider(ExcelDataProvider excelDataProvider) {
+    _excelDataProvider = excelDataProvider;
+    _values = _excelDataProvider.GetWorkbookNameValues();
+  }
+
+  public virtual bool IsNamedValue(string key, string ws) {
+    if (ws != null) {
+      var wsNames = _excelDataProvider.GetWorksheetNames(ws);
+      if (wsNames != null && wsNames.ContainsKey(key)) {
+        return true;
+      }
+    }
+    return _values != null && _values.ContainsKey(key);
+  }
+
+  public virtual object GetNamedValue(string key) {
+    return _values[key];
+  }
+
+  public virtual void Reload() {
+    _values = _excelDataProvider.GetWorkbookNameValues();
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/ExcelCellState.cs b/AppsheetEpplus/FormulaParsing/Excel/ExcelCellState.cs
new file mode 100644
index 0000000..fdb52c9
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/ExcelCellState.cs
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System;
+
+namespace AppsheetEpplus;
+
+[Flags]
+public enum ExcelCellState {
+  HiddenCell = 1,
+  ContainsError = 2,
+  IsResultOfSubtotal = 4,
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/ArgumentCollectionUtil.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/ArgumentCollectionUtil.cs
new file mode 100644
index 0000000..abd3c34
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/ArgumentCollectionUtil.cs
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class ArgumentCollectionUtil {
+  private readonly DoubleEnumerableArgConverter _doubleEnumerableArgConverter;
+  private readonly ObjectEnumerableArgConverter _objectEnumerableArgConverter;
+
+  public ArgumentCollectionUtil()
+      : this(new(), new()) {}
+
+  public ArgumentCollectionUtil(
+      DoubleEnumerableArgConverter doubleEnumerableArgConverter,
+      ObjectEnumerableArgConverter objectEnumerableArgConverter) {
+    _doubleEnumerableArgConverter = doubleEnumerableArgConverter;
+    _objectEnumerableArgConverter = objectEnumerableArgConverter;
+  }
+
+  public virtual IEnumerable<double> ArgsToDoubleEnumerable(
+      bool ignoreHidden,
+      bool ignoreErrors,
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    return _doubleEnumerableArgConverter.ConvertArgs(
+        ignoreHidden,
+        ignoreErrors,
+        arguments,
+        context);
+  }
+
+  public virtual IEnumerable<object> ArgsToObjectEnumerable(
+      bool ignoreHidden,
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    return _objectEnumerableArgConverter.ConvertArgs(ignoreHidden, arguments, context);
+  }
+
+  public virtual double CalculateCollection(
+      IEnumerable<FunctionArgument> collection,
+      double result,
+      Func<FunctionArgument, double, double> action) {
+    foreach (var item in collection) {
+      if (item.Value is IEnumerable<FunctionArgument> value) {
+        result = CalculateCollection(value, result, action);
+      } else {
+        result = action(item, result);
+      }
+    }
+    return result;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/ArgumentParser.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/ArgumentParser.cs
new file mode 100644
index 0000000..40967c5
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/ArgumentParser.cs
@@ -0,0 +1,30 @@
+/* Copyright (C) 2011  Jan Källman
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU Lesser General Public License for more details.
+*
+* The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+* If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+*
+* All code and executables are provided "as is" with no warranty either express or implied.
+* The author accepts no liability for any damage or loss of business that this product may cause.
+*
+* Code change notes:
+*
+* Author							Change						Date
+*******************************************************************************
+* Mats Alm   		                Added		                2013-12-03
+*******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public abstract class ArgumentParser {
+  public abstract object Parse(object obj);
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/ArgumentParserFactory.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/ArgumentParserFactory.cs
new file mode 100644
index 0000000..ef68066
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/ArgumentParserFactory.cs
@@ -0,0 +1,43 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System;
+
+namespace AppsheetEpplus;
+
+public class ArgumentParserFactory {
+  public virtual ArgumentParser CreateArgumentParser(DataType dataType) {
+    switch (dataType) {
+      case DataType.Integer:
+        return new IntArgumentParser();
+      case DataType.Boolean:
+        return new BoolArgumentParser();
+      case DataType.Decimal:
+        return new DoubleArgumentParser();
+      default:
+        throw new InvalidOperationException("non supported argument parser type " + dataType);
+    }
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/ArgumentParsers.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/ArgumentParsers.cs
new file mode 100644
index 0000000..17a2f78
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/ArgumentParsers.cs
@@ -0,0 +1,50 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class ArgumentParsers {
+  private readonly Dictionary<DataType, ArgumentParser> _parsers = new();
+  private readonly ArgumentParserFactory _parserFactory;
+
+  public ArgumentParsers()
+      : this(new()) {}
+
+  public ArgumentParsers(ArgumentParserFactory factory) {
+    Require.That(factory).Named("argumentParserfactory").IsNotNull();
+    _parserFactory = factory;
+  }
+
+  public ArgumentParser GetParser(DataType dataType) {
+    if (!_parsers.ContainsKey(dataType)) {
+      if (!_parsers.ContainsKey(dataType)) {
+        _parsers.Add(dataType, _parserFactory.CreateArgumentParser(dataType));
+      }
+    }
+    return _parsers[dataType];
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/BoolArgumentParser.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/BoolArgumentParser.cs
new file mode 100644
index 0000000..b8fcf9d
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/BoolArgumentParser.cs
@@ -0,0 +1,51 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class BoolArgumentParser : ArgumentParser {
+  public override object Parse(object obj) {
+    if (obj is ExcelDataProvider.IRangeInfo info) {
+      var r = info.FirstOrDefault();
+      obj = r?.Value;
+    }
+    if (obj == null) {
+      return false;
+    }
+    if (obj is bool b) {
+      return b;
+    }
+    if (obj.IsNumeric()) {
+      return Convert.ToBoolean(obj);
+    }
+    if (bool.TryParse(obj.ToString(), out var result)) {
+      return result;
+    }
+    return result;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/BuiltInFunctions.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/BuiltInFunctions.cs
new file mode 100644
index 0000000..eaa2ec0
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/BuiltInFunctions.cs
@@ -0,0 +1,194 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+public class BuiltInFunctions : FunctionsModule {
+  public BuiltInFunctions() {
+    // Text
+    Functions["len"] = new Len();
+    Functions["lower"] = new Lower();
+    Functions["upper"] = new Upper();
+    Functions["left"] = new Left();
+    Functions["right"] = new Right();
+    Functions["mid"] = new Mid();
+    Functions["replace"] = new Replace();
+    Functions["rept"] = new Rept();
+    Functions["substitute"] = new Substitute();
+    Functions["concatenate"] = new Concatenate();
+    Functions["char"] = new CharFunction();
+    Functions["exact"] = new Exact();
+    Functions["find"] = new Find();
+    Functions["fixed"] = new Fixed();
+    Functions["proper"] = new Proper();
+    Functions["text"] = new Text();
+    Functions["t"] = new T();
+    Functions["hyperlink"] = new Hyperlink();
+    // Numbers
+    Functions["int"] = new CInt();
+    // Math
+    Functions["abs"] = new Abs();
+    Functions["asin"] = new Asin();
+    Functions["asinh"] = new Asinh();
+    Functions["cos"] = new Cos();
+    Functions["cosh"] = new Cosh();
+    Functions["power"] = new Power();
+    Functions["sign"] = new Sign();
+    Functions["sqrt"] = new Sqrt();
+    Functions["sqrtpi"] = new SqrtPi();
+    Functions["pi"] = new Pi();
+    Functions["product"] = new Product();
+    Functions["ceiling"] = new Ceiling();
+    Functions["count"] = new Count();
+    Functions["counta"] = new CountA();
+    Functions["countblank"] = new CountBlank();
+    Functions["countif"] = new CountIf();
+    Functions["countifs"] = new CountIfs();
+    Functions["fact"] = new Fact();
+    Functions["floor"] = new Floor();
+    Functions["sin"] = new Sin();
+    Functions["sinh"] = new Sinh();
+    Functions["sum"] = new Sum();
+    Functions["sumif"] = new SumIf();
+    Functions["sumifs"] = new SumIfs();
+    Functions["sumproduct"] = new SumProduct();
+    Functions["sumsq"] = new Sumsq();
+    Functions["stdev"] = new Stdev();
+    Functions["stdevp"] = new StdevP();
+    Functions["stdev.s"] = new Stdev();
+    Functions["stdev.p"] = new StdevP();
+    Functions["subtotal"] = new Subtotal();
+    Functions["exp"] = new Exp();
+    Functions["log"] = new Log();
+    Functions["log10"] = new Log10();
+    Functions["ln"] = new Ln();
+    Functions["max"] = new Max();
+    Functions["maxa"] = new Maxa();
+    Functions["median"] = new Median();
+    Functions["min"] = new Min();
+    Functions["mina"] = new Mina();
+    Functions["mod"] = new Mod();
+    Functions["average"] = new Average();
+    Functions["averagea"] = new AverageA();
+    Functions["averageif"] = new AverageIf();
+    Functions["averageifs"] = new AverageIfs();
+    Functions["round"] = new Round();
+    Functions["rounddown"] = new Rounddown();
+    Functions["roundup"] = new Roundup();
+    Functions["rand"] = new Rand();
+    Functions["randbetween"] = new RandBetween();
+    Functions["quotient"] = new Quotient();
+    Functions["trunc"] = new Trunc();
+    Functions["tan"] = new Tan();
+    Functions["tanh"] = new Tanh();
+    Functions["atan"] = new Atan();
+    Functions["atan2"] = new Atan2();
+    Functions["atanh"] = new Atanh();
+    Functions["acos"] = new Acos();
+    Functions["acosh"] = new Acosh();
+    Functions["var"] = new Var();
+    Functions["varp"] = new VarP();
+    Functions["large"] = new Large();
+    Functions["small"] = new Small();
+    Functions["degrees"] = new Degrees();
+    // Information
+    Functions["isblank"] = new IsBlank();
+    Functions["isnumber"] = new IsNumber();
+    Functions["istext"] = new IsText();
+    Functions["isnontext"] = new IsNonText();
+    Functions["iserror"] = new IsError();
+    Functions["iserr"] = new IsErr();
+    Functions["error.type"] = new ErrorType();
+    Functions["iseven"] = new IsEven();
+    Functions["isodd"] = new IsOdd();
+    Functions["islogical"] = new IsLogical();
+    Functions["isna"] = new IsNa();
+    Functions["na"] = new Na();
+    Functions["n"] = new N();
+    // Logical
+    Functions["if"] = new If();
+    Functions["iferror"] = new IfError();
+    Functions["ifna"] = new IfNa();
+    Functions["not"] = new Not();
+    Functions["and"] = new And();
+    Functions["or"] = new Or();
+    Functions["true"] = new True();
+    Functions["false"] = new False();
+    // Reference and lookup
+    Functions["address"] = new Address();
+    Functions["hlookup"] = new HLookup();
+    Functions["vlookup"] = new VLookup();
+    Functions["lookup"] = new Lookup();
+    Functions["match"] = new ExcelMatch();
+    Functions["row"] = new Row {
+      SkipArgumentEvaluation = true,
+    };
+    Functions["rows"] = new Rows {
+      SkipArgumentEvaluation = true,
+    };
+    Functions["column"] = new Column {
+      SkipArgumentEvaluation = true,
+    };
+    Functions["columns"] = new Columns {
+      SkipArgumentEvaluation = true,
+    };
+    Functions["choose"] = new Choose();
+    Functions["index"] = new Index();
+    Functions["indirect"] = new Indirect();
+    Functions["offset"] = new Offset {
+      SkipArgumentEvaluation = true,
+    };
+    // Date
+    Functions["date"] = new Date();
+    Functions["today"] = new Today();
+    Functions["now"] = new Now();
+    Functions["day"] = new Day();
+    Functions["month"] = new Month();
+    Functions["year"] = new Year();
+    Functions["time"] = new Time();
+    Functions["hour"] = new Hour();
+    Functions["minute"] = new Minute();
+    Functions["second"] = new Second();
+    Functions["weeknum"] = new Weeknum();
+    Functions["weekday"] = new Weekday();
+    Functions["days360"] = new Days360();
+    Functions["yearfrac"] = new Yearfrac();
+    Functions["edate"] = new Edate();
+    Functions["eomonth"] = new Eomonth();
+    Functions["isoweeknum"] = new IsoWeekNum();
+    Functions["workday"] = new Workday();
+    // Database
+    Functions["dget"] = new Dget();
+    Functions["dcount"] = new Dcount();
+    Functions["dcounta"] = new DcountA();
+    Functions["dmax"] = new Dmax();
+    Functions["dmin"] = new Dmin();
+    Functions["dsum"] = new Dsum();
+    Functions["daverage"] = new Daverage();
+    Functions["dvar"] = new Dvar();
+    Functions["dvarp"] = new Dvarp();
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/CellStateHelper.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/CellStateHelper.cs
new file mode 100644
index 0000000..96be95e
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/CellStateHelper.cs
@@ -0,0 +1,56 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+internal static class CellStateHelper {
+  private static bool IsSubTotal(ExcelDataProvider.ICellInfo c) {
+    var tokens = c.Tokens;
+    if (tokens == null) {
+      return false;
+    }
+    return c.Tokens.Any(token =>
+        token.TokenType == TokenType.Function
+            && token.Value.Equals("SUBTOTAL", StringComparison.InvariantCultureIgnoreCase));
+  }
+
+  internal static bool ShouldIgnore(
+      bool ignoreHiddenValues,
+      ExcelDataProvider.ICellInfo c,
+      ParsingContext context) {
+    return (ignoreHiddenValues && c.IsHiddenRow)
+        || (context.Scopes.Current.IsSubtotal && IsSubTotal(c));
+  }
+
+  internal static bool ShouldIgnore(
+      bool ignoreHiddenValues,
+      FunctionArgument arg,
+      ParsingContext context) {
+    return (ignoreHiddenValues && arg.ExcelStateFlagIsSet(ExcelCellState.HiddenCell));
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/CollectionFlattener.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/CollectionFlattener.cs
new file mode 100644
index 0000000..247a452
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/CollectionFlattener.cs
@@ -0,0 +1,52 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public abstract class CollectionFlattener<T> {
+  public virtual IEnumerable<T> FuncArgsToFlatEnumerable(
+      IEnumerable<FunctionArgument> arguments,
+      Action<FunctionArgument, IList<T>> convertFunc) {
+    var argList = new List<T>();
+    FuncArgsToFlatEnumerable(arguments, argList, convertFunc);
+    return argList;
+  }
+
+  private void FuncArgsToFlatEnumerable(
+      IEnumerable<FunctionArgument> arguments,
+      List<T> argList,
+      Action<FunctionArgument, IList<T>> convertFunc) {
+    foreach (var arg in arguments) {
+      if (arg.Value is IEnumerable<FunctionArgument> value) {
+        FuncArgsToFlatEnumerable(value, argList, convertFunc);
+      } else {
+        convertFunc(arg, argList);
+      }
+    }
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/CompileResultValidator.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/CompileResultValidator.cs
new file mode 100644
index 0000000..0a5c36f
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/CompileResultValidator.cs
@@ -0,0 +1,41 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-26
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public abstract class CompileResultValidator {
+  public abstract void Validate(object obj);
+
+  private static CompileResultValidator _empty;
+
+  public static CompileResultValidator Empty =>
+    _empty ?? (_empty = new EmptyCompileResultValidator());
+}
+
+internal class EmptyCompileResultValidator : CompileResultValidator {
+  public override void Validate(object obj) {
+    // empty validator - do nothing
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/CompileResultValidators.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/CompileResultValidators.cs
new file mode 100644
index 0000000..e9e22a3
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/CompileResultValidators.cs
@@ -0,0 +1,46 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-26
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class CompileResultValidators {
+  private readonly Dictionary<DataType, CompileResultValidator> _validators = new();
+
+  private CompileResultValidator CreateOrGet(DataType dataType) {
+    if (_validators.ContainsKey(dataType)) {
+      return _validators[dataType];
+    }
+    if (dataType == DataType.Decimal) {
+      return _validators[DataType.Decimal] = new DecimalCompileResultValidator();
+    }
+    return CompileResultValidator.Empty;
+  }
+
+  public CompileResultValidator GetValidator(DataType dataType) {
+    return CreateOrGet(dataType);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/DSum.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/DSum.cs
new file mode 100644
index 0000000..b54ce0f
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/DSum.cs
@@ -0,0 +1,48 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-04-19
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Dsum : DatabaseFunction {
+  public Dsum()
+      : this(new()) {}
+
+  public Dsum(RowMatcher rowMatcher)
+      : base(rowMatcher) {}
+
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 3);
+    var values = GetMatchingValues(arguments, context);
+    if (!values.Any()) {
+      return CreateResult(0d, DataType.Integer);
+    }
+    return CreateResult(values.Sum(), DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/DatabaseFunction.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/DatabaseFunction.cs
new file mode 100644
index 0000000..5fdd70a
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/DatabaseFunction.cs
@@ -0,0 +1,68 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-04-19
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public abstract class DatabaseFunction : ExcelFunction {
+  protected RowMatcher RowMatcher { get; private set; }
+
+  public DatabaseFunction()
+      : this(new()) {}
+
+  public DatabaseFunction(RowMatcher rowMatcher) {
+    RowMatcher = rowMatcher;
+  }
+
+  protected IEnumerable<double> GetMatchingValues(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    var dbAddress = arguments.ElementAt(0).ValueAsRangeInfo.Address.Address;
+    //var field = ArgToString(arguments, 1).ToLower(CultureInfo.InvariantCulture);
+    var field = arguments.ElementAt(1).Value;
+    var criteriaRange = arguments.ElementAt(2).ValueAsRangeInfo.Address.Address;
+
+    var db = new ExcelDatabase(context.ExcelDataProvider, dbAddress);
+    var criteria = new ExcelDatabaseCriteria(context.ExcelDataProvider, criteriaRange);
+    var values = new List<double>();
+
+    while (db.HasMoreRows) {
+      var dataRow = db.Read();
+      if (!RowMatcher.IsMatch(dataRow, criteria)) {
+        continue;
+      }
+      var candidate = ConvertUtil.IsNumeric(field)
+          ? dataRow[(int)ConvertUtil.GetValueDouble(field)]
+          : dataRow[field.ToString().ToLower(CultureInfo.InvariantCulture)];
+      if (ConvertUtil.IsNumeric(candidate)) {
+        values.Add(ConvertUtil.GetValueDouble(candidate));
+      }
+    }
+    return values;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/Daverage.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/Daverage.cs
new file mode 100644
index 0000000..251aa9b
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/Daverage.cs
@@ -0,0 +1,48 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-04-19
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Daverage : DatabaseFunction {
+  public Daverage()
+      : this(new()) {}
+
+  public Daverage(RowMatcher rowMatcher)
+      : base(rowMatcher) {}
+
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 3);
+    var values = GetMatchingValues(arguments, context);
+    if (!values.Any()) {
+      return CreateResult(0d, DataType.Integer);
+    }
+    return CreateResult(values.Average(), DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/Dcount.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/Dcount.cs
new file mode 100644
index 0000000..b9d8e6e
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/Dcount.cs
@@ -0,0 +1,77 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-04-06
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Dcount : ExcelFunction {
+  private readonly RowMatcher _rowMatcher;
+
+  public Dcount()
+      : this(new()) {}
+
+  public Dcount(RowMatcher rowMatcher) {
+    _rowMatcher = rowMatcher;
+  }
+
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var dbAddress = arguments.ElementAt(0).ValueAsRangeInfo.Address.Address;
+    string field = null;
+    string criteriaRange = null;
+    if (arguments.Count() == 2) {
+      criteriaRange = arguments.ElementAt(1).ValueAsRangeInfo.Address.Address;
+    } else {
+      field = ArgToString(arguments, 1).ToLower(CultureInfo.InvariantCulture);
+      criteriaRange = arguments.ElementAt(2).ValueAsRangeInfo.Address.Address;
+    }
+    var db = new ExcelDatabase(context.ExcelDataProvider, dbAddress);
+    var criteria = new ExcelDatabaseCriteria(context.ExcelDataProvider, criteriaRange);
+
+    var nHits = 0;
+    while (db.HasMoreRows) {
+      var dataRow = db.Read();
+      if (_rowMatcher.IsMatch(dataRow, criteria)) {
+        // if a fieldname is supplied, count only this row if the value
+        // of the supplied field is numeric.
+        if (!string.IsNullOrEmpty(field)) {
+          var candidate = dataRow[field];
+          if (ConvertUtil.IsNumeric(candidate)) {
+            nHits++;
+          }
+        } else {
+          // no fieldname was supplied, always count matching row.
+          nHits++;
+        }
+      }
+    }
+    return CreateResult(nHits, DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/DcountA.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/DcountA.cs
new file mode 100644
index 0000000..8f6bd9b
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/DcountA.cs
@@ -0,0 +1,81 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-04-06
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class DcountA : DatabaseFunction {
+  public DcountA()
+      : this(new()) {}
+
+  public DcountA(RowMatcher rowMatcher)
+      : base(rowMatcher) {}
+
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var dbAddress = arguments.ElementAt(0).ValueAsRangeInfo.Address.Address;
+    string field = null;
+    string criteriaRange;
+    if (arguments.Count() == 2) {
+      criteriaRange = arguments.ElementAt(1).ValueAsRangeInfo.Address.Address;
+    } else {
+      field = ArgToString(arguments, 1).ToLower(CultureInfo.InvariantCulture);
+      criteriaRange = arguments.ElementAt(2).ValueAsRangeInfo.Address.Address;
+    }
+    var db = new ExcelDatabase(context.ExcelDataProvider, dbAddress);
+    var criteria = new ExcelDatabaseCriteria(context.ExcelDataProvider, criteriaRange);
+
+    var nHits = 0;
+    while (db.HasMoreRows) {
+      var dataRow = db.Read();
+      if (RowMatcher.IsMatch(dataRow, criteria)) {
+        // if a fieldname is supplied, count only this row if the value
+        // of the supplied field is not blank.
+        if (!string.IsNullOrEmpty(field)) {
+          var candidate = dataRow[field];
+          if (ShouldCount(candidate)) {
+            nHits++;
+          }
+        } else {
+          // no fieldname was supplied, always count matching row.
+          nHits++;
+        }
+      }
+    }
+    return CreateResult(nHits, DataType.Integer);
+  }
+
+  private bool ShouldCount(object value) {
+    if (value == null) {
+      return false;
+    }
+    return (!string.IsNullOrEmpty(value.ToString()));
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/Dget.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/Dget.cs
new file mode 100644
index 0000000..204fcfd
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/Dget.cs
@@ -0,0 +1,64 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-04-06
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Dget : DatabaseFunction {
+  public Dget()
+      : this(new()) {}
+
+  public Dget(RowMatcher rowMatcher)
+      : base(rowMatcher) {}
+
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 3);
+    var dbAddress = arguments.ElementAt(0).ValueAsRangeInfo.Address.Address;
+    var field = ArgToString(arguments, 1).ToLower(CultureInfo.InvariantCulture);
+    var criteriaRange = arguments.ElementAt(2).ValueAsRangeInfo.Address.Address;
+
+    var db = new ExcelDatabase(context.ExcelDataProvider, dbAddress);
+    var criteria = new ExcelDatabaseCriteria(context.ExcelDataProvider, criteriaRange);
+
+    var nHits = 0;
+    object retVal = null;
+    while (db.HasMoreRows) {
+      var dataRow = db.Read();
+      if (!RowMatcher.IsMatch(dataRow, criteria)) {
+        continue;
+      }
+      if (++nHits > 1) {
+        return CreateResult(ExcelErrorValue.Values.Num, DataType.ExcelError);
+      }
+      retVal = dataRow[field];
+    }
+    return new CompileResultFactory().Create(retVal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/Dmax.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/Dmax.cs
new file mode 100644
index 0000000..c87e23d
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/Dmax.cs
@@ -0,0 +1,48 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-04-19
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Dmax : DatabaseFunction {
+  public Dmax()
+      : this(new()) {}
+
+  public Dmax(RowMatcher rowMatcher)
+      : base(rowMatcher) {}
+
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 3);
+    var values = GetMatchingValues(arguments, context);
+    if (!values.Any()) {
+      return CreateResult(0d, DataType.Integer);
+    }
+    return CreateResult(values.Max(), DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/Dmin.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/Dmin.cs
new file mode 100644
index 0000000..df9f8a9
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/Dmin.cs
@@ -0,0 +1,48 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-04-19
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Dmin : DatabaseFunction {
+  public Dmin()
+      : this(new()) {}
+
+  public Dmin(RowMatcher rowMatcher)
+      : base(rowMatcher) {}
+
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 3);
+    var values = GetMatchingValues(arguments, context);
+    if (!values.Any()) {
+      return CreateResult(0d, DataType.Integer);
+    }
+    return CreateResult(values.Min(), DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/Dvar.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/Dvar.cs
new file mode 100644
index 0000000..feb1265
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/Dvar.cs
@@ -0,0 +1,48 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-04-19
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Dvar : DatabaseFunction {
+  public Dvar()
+      : this(new()) {}
+
+  public Dvar(RowMatcher rowMatcher)
+      : base(rowMatcher) {}
+
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 3);
+    var values = GetMatchingValues(arguments, context);
+    if (!values.Any()) {
+      return CreateResult(0d, DataType.Integer);
+    }
+    return CreateResult(VarMethods.Var(values), DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/Dvarp.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/Dvarp.cs
new file mode 100644
index 0000000..9484b71
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/Dvarp.cs
@@ -0,0 +1,48 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-04-19
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Dvarp : DatabaseFunction {
+  public Dvarp()
+      : this(new()) {}
+
+  public Dvarp(RowMatcher rowMatcher)
+      : base(rowMatcher) {}
+
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 3);
+    var values = GetMatchingValues(arguments, context);
+    if (!values.Any()) {
+      return CreateResult(0d, DataType.Integer);
+    }
+    return CreateResult(VarMethods.VarP(values), DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/ExcelDatabase.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/ExcelDatabase.cs
new file mode 100644
index 0000000..2c9cf12
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/ExcelDatabase.cs
@@ -0,0 +1,81 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-04-06
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Globalization;
+
+namespace AppsheetEpplus;
+
+public class ExcelDatabase {
+  private readonly ExcelDataProvider _dataProvider;
+  private readonly int _fromCol;
+  private readonly int _toCol;
+  private readonly int _fieldRow;
+  private readonly int _endRow;
+  private readonly string _worksheet;
+  private int _rowIndex;
+  private readonly List<ExcelDatabaseField> _fields = new();
+
+  public IEnumerable<ExcelDatabaseField> Fields => _fields;
+
+  public ExcelDatabase(ExcelDataProvider dataProvider, string range) {
+    _dataProvider = dataProvider;
+    var address = new ExcelAddressBase(range);
+    _fromCol = address._fromCol;
+    _toCol = address._toCol;
+    _fieldRow = address._fromRow;
+    _endRow = address._toRow;
+    _worksheet = address.WorkSheet;
+    _rowIndex = _fieldRow;
+    Initialize();
+  }
+
+  private void Initialize() {
+    var fieldIx = 0;
+    for (var colIndex = _fromCol; colIndex <= _toCol; colIndex++) {
+      var nameObj = GetCellValue(_fieldRow, colIndex);
+      var name =
+          nameObj != null ? nameObj.ToString().ToLower(CultureInfo.InvariantCulture) : string.Empty;
+      _fields.Add(new(name, fieldIx++));
+    }
+  }
+
+  private object GetCellValue(int row, int col) {
+    return _dataProvider.GetRangeValue(_worksheet, row, col);
+  }
+
+  public bool HasMoreRows => _rowIndex < _endRow;
+
+  public ExcelDatabaseRow Read() {
+    var retVal = new ExcelDatabaseRow();
+    _rowIndex++;
+    foreach (var field in Fields) {
+      var colIndex = _fromCol + field.ColIndex;
+      var val = GetCellValue(_rowIndex, colIndex);
+      retVal[field.FieldName] = val;
+    }
+    return retVal;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseCriteria.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseCriteria.cs
new file mode 100644
index 0000000..1859c8c
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseCriteria.cs
@@ -0,0 +1,67 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-04-06
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Globalization;
+
+namespace AppsheetEpplus;
+
+public class ExcelDatabaseCriteria {
+  private readonly ExcelDataProvider _dataProvider;
+  private readonly int _fromCol;
+  private readonly int _toCol;
+  private readonly string _worksheet;
+  private readonly int _fieldRow;
+  private readonly Dictionary<ExcelDatabaseCriteriaField, object> _criterias = new();
+
+  public ExcelDatabaseCriteria(ExcelDataProvider dataProvider, string range) {
+    _dataProvider = dataProvider;
+    var address = new ExcelAddressBase(range);
+    _fromCol = address._fromCol;
+    _toCol = address._toCol;
+    _worksheet = address.WorkSheet;
+    _fieldRow = address._fromRow;
+    Initialize();
+  }
+
+  private void Initialize() {
+    for (var x = _fromCol; x <= _toCol; x++) {
+      var fieldObj = _dataProvider.GetCellValue(_worksheet, _fieldRow, x);
+      var val = _dataProvider.GetCellValue(_worksheet, _fieldRow + 1, x);
+      if (fieldObj != null && val != null) {
+        if (fieldObj is string) {
+          var field = new ExcelDatabaseCriteriaField(
+              fieldObj.ToString().ToLower(CultureInfo.InvariantCulture));
+          _criterias.Add(field, val);
+        } else if (ConvertUtil.IsNumeric(fieldObj)) {
+          var field = new ExcelDatabaseCriteriaField((int)fieldObj);
+          _criterias.Add(field, val);
+        }
+      }
+    }
+  }
+
+  public virtual IDictionary<ExcelDatabaseCriteriaField, object> Items => _criterias;
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseCriteriaField.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseCriteriaField.cs
new file mode 100644
index 0000000..9fa2d2b
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseCriteriaField.cs
@@ -0,0 +1,47 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-04-19
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public class ExcelDatabaseCriteriaField {
+  public ExcelDatabaseCriteriaField(string fieldName) {
+    FieldName = fieldName;
+  }
+
+  public ExcelDatabaseCriteriaField(int fieldIndex) {
+    FieldIndex = fieldIndex;
+  }
+
+  public override string ToString() {
+    if (!string.IsNullOrEmpty(FieldName)) {
+      return FieldName;
+    }
+    return base.ToString();
+  }
+
+  public string FieldName { get; private set; }
+
+  public int? FieldIndex { get; private set; }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseField.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseField.cs
new file mode 100644
index 0000000..8472a99
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseField.cs
@@ -0,0 +1,37 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-04-06
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public class ExcelDatabaseField {
+  public string FieldName { get; private set; }
+
+  public int ColIndex { get; private set; }
+
+  public ExcelDatabaseField(string fieldName, int colIndex) {
+    FieldName = fieldName;
+    ColIndex = colIndex;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseRow.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseRow.cs
new file mode 100644
index 0000000..c948477
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseRow.cs
@@ -0,0 +1,49 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-04-19
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class ExcelDatabaseRow {
+  private readonly Dictionary<int, string> _fieldIndexes = new();
+  private readonly Dictionary<string, object> _items = new();
+  private int _colIndex = 1;
+
+  public object this[string field] {
+    get => _items[field];
+    set {
+      _items[field] = value;
+      _fieldIndexes[_colIndex++] = field;
+    }
+  }
+
+  public object this[int index] {
+    get {
+      var field = _fieldIndexes[index];
+      return _items[field];
+    }
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/RowMatcher.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/RowMatcher.cs
new file mode 100644
index 0000000..71ff077
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Database/RowMatcher.cs
@@ -0,0 +1,79 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-04-06
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+public class RowMatcher {
+  private readonly WildCardValueMatcher _wildCardValueMatcher;
+  private readonly NumericExpressionEvaluator _numericExpressionEvaluator;
+
+  public RowMatcher()
+      : this(new(), new()) {}
+
+  public RowMatcher(
+      WildCardValueMatcher wildCardValueMatcher,
+      NumericExpressionEvaluator numericExpressionEvaluator) {
+    _wildCardValueMatcher = wildCardValueMatcher;
+    _numericExpressionEvaluator = numericExpressionEvaluator;
+  }
+
+  public bool IsMatch(ExcelDatabaseRow row, ExcelDatabaseCriteria criteria) {
+    var retVal = true;
+    foreach (var c in criteria.Items) {
+      var candidate = c.Key.FieldIndex.HasValue
+          ? row[c.Key.FieldIndex.Value]
+          : row[c.Key.FieldName];
+      var crit = c.Value;
+      if (candidate.IsNumeric() && crit.IsNumeric()) {
+        if (System.Math.Abs(
+                ConvertUtil.GetValueDouble(candidate) - ConvertUtil.GetValueDouble(crit))
+            > double.Epsilon) {
+          return false;
+        }
+      } else {
+        var criteriaString = crit.ToString();
+        if (!Evaluate(candidate, criteriaString)) {
+          return false;
+        }
+      }
+    }
+    return retVal;
+  }
+
+  private bool Evaluate(object obj, string expression) {
+    if (obj == null) {
+      return false;
+    }
+    double? candidate = default(double?);
+    if (ConvertUtil.IsNumeric(obj)) {
+      candidate = ConvertUtil.GetValueDouble(obj);
+    }
+    if (candidate.HasValue) {
+      return _numericExpressionEvaluator.Evaluate(candidate.Value, expression);
+    }
+    return _wildCardValueMatcher.IsMatch(expression, obj.ToString()) == 0;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Date.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Date.cs
new file mode 100644
index 0000000..fe43877
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Date.cs
@@ -0,0 +1,44 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Date : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 3);
+    var year = ArgToInt(arguments, 0);
+    var month = ArgToInt(arguments, 1);
+    var day = ArgToInt(arguments, 2);
+    var date = new System.DateTime(year, 1, 1);
+    month -= 1;
+    date = date.AddMonths(month);
+    date = date.AddDays(day - 1);
+    return CreateResult(date.ToOADate(), DataType.Date);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/DateParsingFunction.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/DateParsingFunction.cs
new file mode 100644
index 0000000..a30bb49
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/DateParsingFunction.cs
@@ -0,0 +1,17 @@
+using System.Collections.Generic;
+using System.Globalization;
+
+namespace AppsheetEpplus;
+
+public abstract class DateParsingFunction : ExcelFunction {
+  protected System.DateTime ParseDate(IEnumerable<FunctionArgument> arguments, object dateObj) {
+    System.DateTime date;
+    if (dateObj is string) {
+      date = System.DateTime.Parse(dateObj.ToString(), CultureInfo.InvariantCulture);
+    } else {
+      var d = ArgToDecimal(arguments, 0);
+      date = System.DateTime.FromOADate(d);
+    }
+    return date;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/DateStringParser.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/DateStringParser.cs
new file mode 100644
index 0000000..c3e4618
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/DateStringParser.cs
@@ -0,0 +1,28 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public class DateStringParser {}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/DateValue.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/DateValue.cs
new file mode 100644
index 0000000..8f97f83
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/DateValue.cs
@@ -0,0 +1,24 @@
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Simple implementation of DateValue function, just using .NET built-in
+/// function System.DateTime.TryParse, based on current culture
+/// </summary>
+public class DateValue : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var dateString = ArgToString(arguments, 0);
+    return Execute(dateString);
+  }
+
+  internal CompileResult Execute(string dateString) {
+    System.DateTime.TryParse(dateString, out var result);
+    return result != System.DateTime.MinValue
+        ? CreateResult(result.ToOADate(), DataType.Date)
+        : CreateResult(ExcelErrorValue.Create(eErrorType.Value), DataType.ExcelError);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Day.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Day.cs
new file mode 100644
index 0000000..b226b31
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Day.cs
@@ -0,0 +1,40 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Day : DateParsingFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var dateObj = GetFirstValue(arguments);
+    var date = ParseDate(arguments, dateObj);
+
+    return CreateResult(date.Day, DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Days360.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Days360.cs
new file mode 100644
index 0000000..a797688
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Days360.cs
@@ -0,0 +1,70 @@
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Days360 : ExcelFunction {
+  private enum Days360Calctype {
+    European,
+    Us,
+  }
+
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var numDate1 = ArgToDecimal(arguments, 0);
+    var numDate2 = ArgToDecimal(arguments, 1);
+    var dt1 = System.DateTime.FromOADate(numDate1);
+    var dt2 = System.DateTime.FromOADate(numDate2);
+
+    var calcType = Days360Calctype.Us;
+    if (arguments.Count() > 2) {
+      var european = ArgToBool(arguments, 2);
+      if (european) {
+        calcType = Days360Calctype.European;
+      }
+    }
+
+    var startYear = dt1.Year;
+    var startMonth = dt1.Month;
+    var startDay = dt1.Day;
+    var endYear = dt2.Year;
+    var endMonth = dt2.Month;
+    var endDay = dt2.Day;
+
+    if (calcType == Days360Calctype.European) {
+      if (startDay == 31) {
+        startDay = 30;
+      }
+      if (endDay == 31) {
+        endDay = 30;
+      }
+    } else {
+      var calendar = new GregorianCalendar();
+      var nDaysInFeb = calendar.IsLeapYear(dt1.Year) ? 29 : 28;
+
+      // If the investment is EOM and (Date1 is the last day of February) and (Date2 is the last day of February), then change D2 to 30.
+      if (startMonth == 2 && startDay == nDaysInFeb && endMonth == 2 && endDay == nDaysInFeb) {
+        endDay = 30;
+      }
+      // If the investment is EOM and (Date1 is the last day of February), then change D1 to 30.
+      if (startMonth == 2 && startDay == nDaysInFeb) {
+        startDay = 30;
+      }
+      // If D2 is 31 and D1 is 30 or 31, then change D2 to 30.
+      if (endDay == 31 && (startDay == 30 || startDay == 31)) {
+        endDay = 30;
+      }
+      // If D1 is 31, then change D1 to 30.
+      if (startDay == 31) {
+        startDay = 30;
+      }
+    }
+    var result =
+        (endYear * 12 * 30 + endMonth * 30 + endDay)
+            - (startYear * 12 * 30 + startMonth * 30 + startDay);
+    return CreateResult(result, DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Edate.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Edate.cs
new file mode 100644
index 0000000..530a13c
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Edate.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Edate : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2, eErrorType.Value);
+    var dateSerial = ArgToDecimal(arguments, 0);
+    var date = System.DateTime.FromOADate(dateSerial);
+    var nMonthsToAdd = ArgToInt(arguments, 1);
+    var resultDate = date.AddMonths(nMonthsToAdd);
+    return CreateResult(resultDate.ToOADate(), DataType.Date);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Eomonth.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Eomonth.cs
new file mode 100644
index 0000000..cae6cbb
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Eomonth.cs
@@ -0,0 +1,17 @@
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Eomonth : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var date = System.DateTime.FromOADate(ArgToDecimal(arguments, 0));
+    var monthsToAdd = ArgToInt(arguments, 1);
+    var resultDate = new System.DateTime(date.Year, date.Month, 1)
+        .AddMonths(monthsToAdd + 1)
+        .AddDays(-1);
+    return CreateResult(resultDate.ToOADate(), DataType.Date);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Hour.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Hour.cs
new file mode 100644
index 0000000..ecdc1a8
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Hour.cs
@@ -0,0 +1,40 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Hour : DateParsingFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var dateObj = arguments.ElementAt(0).Value;
+    var date = ParseDate(arguments, dateObj);
+    return CreateResult(date.Hour, DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/IsoWeekNum.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/IsoWeekNum.cs
new file mode 100644
index 0000000..0ef8c4f
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/IsoWeekNum.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class IsoWeekNum : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var dateInt = ArgToInt(arguments, 0);
+    var date = System.DateTime.FromOADate(dateInt);
+    return CreateResult(WeekNumber(date), DataType.Integer);
+  }
+
+  /// <summary>
+  /// This implementation was found on http://stackoverflow.com/questions/1285191/get-week-of-date-from-linq-query
+  /// </summary>
+  /// <param name="fromDate"></param>
+  /// <returns></returns>
+  private int WeekNumber(System.DateTime fromDate) {
+    // Get jan 1st of the year
+    var startOfYear = fromDate.AddDays(-fromDate.Day + 1).AddMonths(-fromDate.Month + 1);
+    // Get dec 31st of the year
+    var endOfYear = startOfYear.AddYears(1).AddDays(-1);
+    // ISO 8601 weeks start with Monday
+    // The first week of a year includes the first Thursday
+    // DayOfWeek returns 0 for sunday up to 6 for saterday
+    int[] iso8601Correction = [6, 7, 8, 9, 10, 4, 5];
+    int nds = fromDate.Subtract(startOfYear).Days + iso8601Correction[(int)startOfYear.DayOfWeek];
+    int wk = nds / 7;
+    switch (wk) {
+      case 0:
+        // Return weeknumber of dec 31st of the previous year
+        return WeekNumber(startOfYear.AddDays(-1));
+      case 53:
+        // If dec 31st falls before thursday it is week 01 of next year
+        if (endOfYear.DayOfWeek < DayOfWeek.Thursday) {
+          return 1;
+        }
+        return wk;
+      default:
+        return wk;
+    }
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Minute.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Minute.cs
new file mode 100644
index 0000000..6b67254
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Minute.cs
@@ -0,0 +1,46 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Minute : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var dateObj = arguments.ElementAt(0).Value;
+    System.DateTime date;
+    if (dateObj is string) {
+      date = System.DateTime.Parse(dateObj.ToString());
+    } else {
+      var d = ArgToDecimal(arguments, 0);
+      date = System.DateTime.FromOADate(d);
+    }
+    return CreateResult(date.Minute, DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Month.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Month.cs
new file mode 100644
index 0000000..361615e
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Month.cs
@@ -0,0 +1,40 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Month : DateParsingFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var dateObj = arguments.ElementAt(0).Value;
+    var date = ParseDate(arguments, dateObj);
+    return CreateResult(date.Month, DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Networkdays.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Networkdays.cs
new file mode 100644
index 0000000..3ba7a10
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Networkdays.cs
@@ -0,0 +1,22 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Networkdays : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray();
+    ValidateArguments(functionArguments, 2);
+    var startDate = System.DateTime.FromOADate(ArgToInt(functionArguments, 0));
+    var endDate = System.DateTime.FromOADate(ArgToInt(functionArguments, 1));
+    var calculator = new WorkdayCalculator();
+    var result = calculator.CalculateNumberOfWorkdays(startDate, endDate);
+    if (functionArguments.Length > 2) {
+      result = calculator.ReduceWorkdaysWithHolidays(result, functionArguments[2]);
+    }
+
+    return new(result.NumberOfWorkdays, DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/NetworkdaysIntl.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/NetworkdaysIntl.cs
new file mode 100644
index 0000000..96fd71c
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/NetworkdaysIntl.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.RegularExpressions;
+
+namespace AppsheetEpplus;
+
+public class NetworkdaysIntl : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray();
+    ValidateArguments(functionArguments, 2);
+    var startDate = System.DateTime.FromOADate(ArgToInt(functionArguments, 0));
+    var endDate = System.DateTime.FromOADate(ArgToInt(functionArguments, 1));
+    WorkdayCalculator calculator = new WorkdayCalculator();
+    var weekdayFactory = new HolidayWeekdaysFactory();
+    if (functionArguments.Length > 2) {
+      var holidayArg = functionArguments[2].Value;
+      if (Regex.IsMatch(holidayArg.ToString(), "^[01]{7}")) {
+        calculator = new(weekdayFactory.Create(holidayArg.ToString()));
+      } else if (IsNumeric(holidayArg)) {
+        var holidayCode = Convert.ToInt32(holidayArg);
+        calculator = new(weekdayFactory.Create(holidayCode));
+      } else {
+        return new(eErrorType.Value);
+      }
+    }
+    var result = calculator.CalculateNumberOfWorkdays(startDate, endDate);
+    if (functionArguments.Length > 3) {
+      result = calculator.ReduceWorkdaysWithHolidays(result, functionArguments[3]);
+    }
+    return new(result.NumberOfWorkdays, DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Now.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Now.cs
new file mode 100644
index 0000000..c78c2f4
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Now.cs
@@ -0,0 +1,36 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Now : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    return CreateResult(System.DateTime.Now.ToOADate(), DataType.Date);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Second.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Second.cs
new file mode 100644
index 0000000..353d043
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Second.cs
@@ -0,0 +1,40 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Second : DateParsingFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var dateObj = arguments.ElementAt(0).Value;
+    System.DateTime date = ParseDate(arguments, dateObj);
+    return CreateResult(date.Second, DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Time.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Time.cs
new file mode 100644
index 0000000..4a38142
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Time.cs
@@ -0,0 +1,53 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Time : TimeBaseFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var firstArg = arguments.ElementAt(0).Value.ToString();
+    if (arguments.Count() == 1 && TimeStringParser.CanParse(firstArg)) {
+      var result = TimeStringParser.Parse(firstArg);
+      return new(result, DataType.Time);
+    }
+    ValidateArguments(arguments, 3);
+    var hour = ArgToInt(arguments, 0);
+    var min = ArgToInt(arguments, 1);
+    var sec = ArgToInt(arguments, 2);
+
+    ThrowArgumentExceptionIf(() => sec < 0 || sec > 59, "Invalid second: " + sec);
+    ThrowArgumentExceptionIf(() => min < 0 || min > 59, "Invalid minute: " + min);
+    ThrowArgumentExceptionIf(() => min < 0 || hour > 23, "Invalid hour: " + hour);
+
+    var secondsOfThisTime = (double)(hour * 60 * 60 + min * 60 + sec);
+    return CreateResult(GetTimeSerialNumber(secondsOfThisTime), DataType.Time);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/TimeBaseFunction.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/TimeBaseFunction.cs
new file mode 100644
index 0000000..557154e
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/TimeBaseFunction.cs
@@ -0,0 +1,64 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public abstract class TimeBaseFunction : ExcelFunction {
+  protected TimeStringParser TimeStringParser { get; private set; } = new();
+
+  protected double SerialNumber { get; private set; }
+
+  public void ValidateAndInitSerialNumber(IEnumerable<FunctionArgument> arguments) {
+    ValidateArguments(arguments, 1);
+    SerialNumber = ArgToDecimal(arguments, 0);
+  }
+
+  protected double SecondsInADay => 24 * 60 * 60;
+
+  protected double GetTimeSerialNumber(double seconds) {
+    return seconds / SecondsInADay;
+  }
+
+  protected double GetSeconds(double serialNumber) {
+    return serialNumber * SecondsInADay;
+  }
+
+  protected double GetHour(double serialNumber) {
+    var seconds = GetSeconds(serialNumber);
+    return (int)seconds / (60 * 60);
+  }
+
+  protected double GetMinute(double serialNumber) {
+    var seconds = GetSeconds(serialNumber);
+    seconds -= GetHour(serialNumber) * 60 * 60;
+    return (seconds - (seconds % 60)) / 60;
+  }
+
+  protected double GetSecond(double serialNumber) {
+    return GetSeconds(serialNumber) % 60;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/TimeStringParser.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/TimeStringParser.cs
new file mode 100644
index 0000000..a94809c
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/TimeStringParser.cs
@@ -0,0 +1,109 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System;
+using System.Text.RegularExpressions;
+
+namespace AppsheetEpplus;
+
+public class TimeStringParser {
+  private const string _regEx24 = @"^[0-9]{1,2}(\:[0-9]{1,2}){0,2}$";
+  private const string _regEx12 = @"^[0-9]{1,2}(\:[0-9]{1,2}){0,2}( PM| AM)$";
+
+  private double GetSerialNumber(int hour, int minute, int second) {
+    var secondsInADay = 24d * 60d * 60d;
+    return ((double)hour * 60 * 60 + (double)minute * 60 + second) / secondsInADay;
+  }
+
+  private void ValidateValues(int hour, int minute, int second) {
+    if (second < 0 || second > 59) {
+      throw new FormatException("Illegal value for second: " + second);
+    }
+    if (minute < 0 || minute > 59) {
+      throw new FormatException("Illegal value for minute: " + minute);
+    }
+  }
+
+  public virtual double Parse(string input) {
+    return InternalParse(input);
+  }
+
+  public virtual bool CanParse(string input) {
+    System.DateTime dt;
+    return Regex.IsMatch(input, _regEx24)
+        || Regex.IsMatch(input, _regEx12)
+        || System.DateTime.TryParse(input, out dt);
+  }
+
+  private double InternalParse(string input) {
+    if (Regex.IsMatch(input, _regEx24)) {
+      return Parse24HourTimeString(input);
+    }
+    if (Regex.IsMatch(input, _regEx12)) {
+      return Parse12HourTimeString(input);
+    }
+    if (System.DateTime.TryParse(input, out var dateTime)) {
+      return GetSerialNumber(dateTime.Hour, dateTime.Minute, dateTime.Second);
+    }
+    return -1;
+  }
+
+  private double Parse12HourTimeString(string input) {
+    var dayPart = input.Substring(input.Length - 2, 2);
+    GetValuesFromString(input, out var hour, out var minute, out var second);
+    if (dayPart == "PM") {
+      hour += 12;
+    }
+    ValidateValues(hour, minute, second);
+    return GetSerialNumber(hour, minute, second);
+  }
+
+  private double Parse24HourTimeString(string input) {
+    GetValuesFromString(input, out var hour, out var minute, out var second);
+    ValidateValues(hour, minute, second);
+    return GetSerialNumber(hour, minute, second);
+  }
+
+  private static void GetValuesFromString(
+      string input,
+      out int hour,
+      out int minute,
+      out int second) {
+    hour = 0;
+    minute = 0;
+    second = 0;
+
+    var items = input.Split(':');
+    hour = int.Parse(items[0]);
+    if (items.Length > 1) {
+      minute = int.Parse(items[1]);
+    }
+    if (items.Length > 2) {
+      var val = items[2];
+      val = Regex.Replace(val, "[^0-9]+$", string.Empty);
+      second = int.Parse(val);
+    }
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/TimeValue.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/TimeValue.cs
new file mode 100644
index 0000000..dcdc584
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/TimeValue.cs
@@ -0,0 +1,30 @@
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Simple implementation of TimeValue function, just using .NET built-in
+/// function System.DateTime.TryParse, based on current culture
+/// </summary>
+public class TimeValue : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var dateString = ArgToString(arguments, 0);
+    return Execute(dateString);
+  }
+
+  internal CompileResult Execute(string dateString) {
+    System.DateTime.TryParse(dateString, out var result);
+    return result != System.DateTime.MinValue
+        ? CreateResult(GetTimeValue(result), DataType.Date)
+        : CreateResult(ExcelErrorValue.Create(eErrorType.Value), DataType.ExcelError);
+  }
+
+  private double GetTimeValue(System.DateTime result) {
+    return (int)result.TimeOfDay.TotalSeconds == 0
+        ? 0d
+        : result.TimeOfDay.TotalSeconds / (3600 * 24);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Today.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Today.cs
new file mode 100644
index 0000000..8a899e0
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Today.cs
@@ -0,0 +1,36 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Today : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    return CreateResult(System.DateTime.Today.ToOADate(), DataType.Date);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Weekday.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Weekday.cs
new file mode 100644
index 0000000..e62fba7
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Weekday.cs
@@ -0,0 +1,60 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Weekday : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var serialNumber = ArgToDecimal(arguments, 0);
+    var returnType = arguments.Count() > 1 ? ArgToInt(arguments, 1) : 1;
+    return CreateResult(
+        CalculateDayOfWeek(System.DateTime.FromOADate(serialNumber), returnType),
+        DataType.Integer);
+  }
+
+  private static readonly List<int> _oneBasedStartOnSunday = [1, 2, 3, 4, 5, 6, 7];
+  private static readonly List<int> _oneBasedStartOnMonday = [7, 1, 2, 3, 4, 5, 6];
+  private static readonly List<int> _zeroBasedStartOnSunday = [6, 0, 1, 2, 3, 4, 5];
+
+  private int CalculateDayOfWeek(System.DateTime dateTime, int returnType) {
+    var dayIx = (int)dateTime.DayOfWeek;
+    switch (returnType) {
+      case 1:
+        return _oneBasedStartOnSunday[dayIx];
+      case 2:
+        return _oneBasedStartOnMonday[dayIx];
+      case 3:
+        return _zeroBasedStartOnSunday[dayIx];
+      default:
+        throw new ExcelErrorValueException(eErrorType.Num);
+    }
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Weeknum.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Weeknum.cs
new file mode 100644
index 0000000..4706399
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Weeknum.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Weeknum : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1, eErrorType.Value);
+    var dateSerial = ArgToDecimal(arguments, 0);
+    var date = System.DateTime.FromOADate(dateSerial);
+    var startDay = DayOfWeek.Sunday;
+    if (arguments.Count() > 1) {
+      var argStartDay = ArgToInt(arguments, 1);
+      switch (argStartDay) {
+        case 1:
+          startDay = DayOfWeek.Sunday;
+          break;
+        case 2:
+        case 11:
+          startDay = DayOfWeek.Monday;
+          break;
+        case 12:
+          startDay = DayOfWeek.Tuesday;
+          break;
+        case 13:
+          startDay = DayOfWeek.Wednesday;
+          break;
+        case 14:
+          startDay = DayOfWeek.Thursday;
+          break;
+        case 15:
+          startDay = DayOfWeek.Friday;
+          break;
+        case 16:
+          startDay = DayOfWeek.Saturday;
+          break;
+        default:
+          // Not supported
+          ThrowExcelErrorValueException(eErrorType.Num);
+          break;
+      }
+    }
+    if (DateTimeFormatInfo.CurrentInfo == null) {
+      throw new InvalidOperationException(
+          "Could not execute Weeknum function because DateTimeFormatInfo.CurrentInfo was null");
+    }
+    var week = DateTimeFormatInfo.CurrentInfo.Calendar.GetWeekOfYear(
+        date,
+        CalendarWeekRule.FirstDay,
+        startDay);
+    return CreateResult(week, DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Workday.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Workday.cs
new file mode 100644
index 0000000..a5649b8
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Workday.cs
@@ -0,0 +1,77 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Workday : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var startDate = System.DateTime.FromOADate(ArgToInt(arguments, 0));
+    var nWorkDays = ArgToInt(arguments, 1);
+    var resultDate = System.DateTime.MinValue;
+    var workdaysCounted = 0;
+    var tmpDate = startDate;
+    // first move forward to the first monday
+    while (tmpDate.DayOfWeek != DayOfWeek.Monday && (nWorkDays - workdaysCounted) > 0) {
+      if (!IsHoliday(tmpDate)) {
+        workdaysCounted++;
+      }
+      tmpDate = tmpDate.AddDays(1);
+    }
+    // then calculate whole weeks
+    var nWholeWeeks = (nWorkDays - workdaysCounted) / 5;
+    tmpDate = tmpDate.AddDays(nWholeWeeks * 7);
+    workdaysCounted += nWholeWeeks * 5;
+
+    // calculate the rest
+    while (workdaysCounted < nWorkDays) {
+      tmpDate = tmpDate.AddDays(1);
+      if (!IsHoliday(tmpDate)) {
+        workdaysCounted++;
+      }
+    }
+    resultDate = AdjustResultWithHolidays(tmpDate, arguments);
+    return CreateResult(resultDate.ToOADate(), DataType.Date);
+  }
+
+  private System.DateTime AdjustResultWithHolidays(
+      System.DateTime resultDate,
+      IEnumerable<FunctionArgument> arguments) {
+    if (arguments.Count() == 2) {
+      return resultDate;
+    }
+    var holidays = arguments.ElementAt(2).Value as IEnumerable<FunctionArgument>;
+    if (holidays != null) {
+      foreach (var arg in holidays) {
+        if (ConvertUtil.IsNumeric(arg.Value)) {
+          var dateSerial = ConvertUtil.GetValueDouble(arg.Value);
+          var holidayDate = System.DateTime.FromOADate(dateSerial);
+          if (!IsHoliday(holidayDate)) {
+            resultDate = resultDate.AddDays(1);
+          }
+        }
+      }
+    } else {
+      var range = arguments.ElementAt(2).Value as ExcelDataProvider.IRangeInfo;
+      if (range != null) {
+        foreach (var cell in range) {
+          if (ConvertUtil.IsNumeric(cell.Value)) {
+            var dateSerial = ConvertUtil.GetValueDouble(cell.Value);
+            var holidayDate = System.DateTime.FromOADate(dateSerial);
+            if (!IsHoliday(holidayDate)) {
+              resultDate = resultDate.AddDays(1);
+            }
+          }
+        }
+      }
+    }
+    return resultDate;
+  }
+
+  private bool IsHoliday(System.DateTime date) {
+    return date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Workdays/AdditionalHolidayDays.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Workdays/AdditionalHolidayDays.cs
new file mode 100644
index 0000000..7aef11b
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Workdays/AdditionalHolidayDays.cs
@@ -0,0 +1,40 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class AdditionalHolidayDays {
+  private readonly FunctionArgument _holidayArg;
+  private readonly List<System.DateTime> _holidayDates = new();
+
+  public AdditionalHolidayDays(FunctionArgument holidayArg) {
+    _holidayArg = holidayArg;
+    Initialize();
+  }
+
+  public IEnumerable<System.DateTime> AdditionalDates => _holidayDates;
+
+  private void Initialize() {
+    var holidays = _holidayArg.Value as IEnumerable<FunctionArgument>;
+    if (holidays != null) {
+      foreach (var holidayDate in from arg in holidays
+          where ConvertUtil.IsNumeric(arg.Value)
+          select ConvertUtil.GetValueDouble(arg.Value) into dateSerial
+          select System.DateTime.FromOADate(dateSerial)) {
+        _holidayDates.Add(holidayDate);
+      }
+    }
+    var range = _holidayArg.Value as ExcelDataProvider.IRangeInfo;
+    if (range != null) {
+      foreach (var holidayDate in from cell in range
+          where ConvertUtil.IsNumeric(cell.Value)
+          select ConvertUtil.GetValueDouble(cell.Value) into dateSerial
+          select System.DateTime.FromOADate(dateSerial)) {
+        _holidayDates.Add(holidayDate);
+      }
+    }
+    if (ConvertUtil.IsNumeric(_holidayArg.Value)) {
+      _holidayDates.Add(System.DateTime.FromOADate(ConvertUtil.GetValueDouble(_holidayArg.Value)));
+    }
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Workdays/HolidayWeekdays.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Workdays/HolidayWeekdays.cs
new file mode 100644
index 0000000..0beea5a
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Workdays/HolidayWeekdays.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class HolidayWeekdays {
+  private readonly List<DayOfWeek> _holidayDays = new();
+
+  public HolidayWeekdays()
+      : this(DayOfWeek.Saturday, DayOfWeek.Sunday) {}
+
+  public int NumberOfWorkdaysPerWeek => 7 - _holidayDays.Count;
+
+  public HolidayWeekdays(params DayOfWeek[] holidayDays) {
+    foreach (var dayOfWeek in holidayDays) {
+      _holidayDays.Add(dayOfWeek);
+    }
+  }
+
+  public bool IsHolidayWeekday(System.DateTime dateTime) {
+    return _holidayDays.Contains(dateTime.DayOfWeek);
+  }
+
+  public System.DateTime AdjustResultWithHolidays(
+      System.DateTime resultDate,
+      IEnumerable<FunctionArgument> arguments) {
+    if (arguments.Count() == 2) {
+      return resultDate;
+    }
+    var holidays = arguments.ElementAt(2).Value as IEnumerable<FunctionArgument>;
+    if (holidays != null) {
+      foreach (var arg in holidays) {
+        if (ConvertUtil.IsNumeric(arg.Value)) {
+          var dateSerial = ConvertUtil.GetValueDouble(arg.Value);
+          var holidayDate = System.DateTime.FromOADate(dateSerial);
+          if (!IsHolidayWeekday(holidayDate)) {
+            resultDate = resultDate.AddDays(1);
+          }
+        }
+      }
+    } else {
+      var range = arguments.ElementAt(2).Value as ExcelDataProvider.IRangeInfo;
+      if (range != null) {
+        foreach (var cell in range) {
+          if (ConvertUtil.IsNumeric(cell.Value)) {
+            var dateSerial = ConvertUtil.GetValueDouble(cell.Value);
+            var holidayDate = System.DateTime.FromOADate(dateSerial);
+            if (!IsHolidayWeekday(holidayDate)) {
+              resultDate = resultDate.AddDays(1);
+            }
+          }
+        }
+      }
+    }
+    return resultDate;
+  }
+
+  public System.DateTime GetNextWorkday(
+      System.DateTime date,
+      WorkdayCalculationDirection direction = WorkdayCalculationDirection.Forward) {
+    var changeParam = (int)direction;
+    var tmpDate = date.AddDays(changeParam);
+    while (IsHolidayWeekday(tmpDate)) {
+      tmpDate = tmpDate.AddDays(changeParam);
+    }
+    return tmpDate;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Workdays/HolidayWeekdaysFactory.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Workdays/HolidayWeekdaysFactory.cs
new file mode 100644
index 0000000..60b3177
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Workdays/HolidayWeekdaysFactory.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class HolidayWeekdaysFactory {
+  private readonly DayOfWeek[] _dayOfWeekArray = [
+    DayOfWeek.Monday,
+    DayOfWeek.Tuesday,
+    DayOfWeek.Wednesday,
+    DayOfWeek.Thursday,
+    DayOfWeek.Friday,
+    DayOfWeek.Saturday,
+    DayOfWeek.Sunday,
+  ];
+
+  public HolidayWeekdays Create(string weekdays) {
+    if (string.IsNullOrEmpty(weekdays) || weekdays.Length != 7) {
+      throw new ArgumentException("Illegal weekday string", nameof(Weekday));
+    }
+
+    var retVal = new List<DayOfWeek>();
+    var arr = weekdays.ToCharArray();
+    for (var i = 0; i < arr.Length; i++) {
+      var ch = arr[i];
+      if (ch == '1') {
+        retVal.Add(_dayOfWeekArray[i]);
+      }
+    }
+    return new(retVal.ToArray());
+  }
+
+  public HolidayWeekdays Create(int code) {
+    switch (code) {
+      case 1:
+        return new(DayOfWeek.Saturday, DayOfWeek.Sunday);
+      case 2:
+        return new(DayOfWeek.Sunday, DayOfWeek.Monday);
+      case 3:
+        return new(DayOfWeek.Monday, DayOfWeek.Tuesday);
+      case 4:
+        return new(DayOfWeek.Tuesday, DayOfWeek.Wednesday);
+      case 5:
+        return new(DayOfWeek.Wednesday, DayOfWeek.Thursday);
+      case 6:
+        return new(DayOfWeek.Thursday, DayOfWeek.Friday);
+      case 7:
+        return new(DayOfWeek.Friday, DayOfWeek.Saturday);
+      case 11:
+        return new(DayOfWeek.Sunday);
+      case 12:
+        return new(DayOfWeek.Monday);
+      case 13:
+        return new(DayOfWeek.Tuesday);
+      case 14:
+        return new(DayOfWeek.Wednesday);
+      case 15:
+        return new(DayOfWeek.Thursday);
+      case 16:
+        return new(DayOfWeek.Friday);
+      case 17:
+        return new(DayOfWeek.Saturday);
+      default:
+        throw new ArgumentException("Invalid code supplied to HolidayWeekdaysFactory: " + code);
+    }
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculationDirection.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculationDirection.cs
new file mode 100644
index 0000000..1eaf0d3
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculationDirection.cs
@@ -0,0 +1,6 @@
+namespace AppsheetEpplus;
+
+public enum WorkdayCalculationDirection {
+  Forward = 1,
+  Backward = -1,
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculator.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculator.cs
new file mode 100644
index 0000000..b9c031e
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculator.cs
@@ -0,0 +1,123 @@
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class WorkdayCalculator {
+  private readonly HolidayWeekdays _holidayWeekdays;
+
+  public WorkdayCalculator()
+      : this(new()) {}
+
+  public WorkdayCalculator(HolidayWeekdays holidayWeekdays) {
+    _holidayWeekdays = holidayWeekdays;
+  }
+
+  public WorkdayCalculatorResult CalculateNumberOfWorkdays(
+      System.DateTime startDate,
+      System.DateTime endDate) {
+    var calcDirection =
+        startDate < endDate
+            ? WorkdayCalculationDirection.Forward
+            : WorkdayCalculationDirection.Backward;
+    System.DateTime calcStartDate;
+    System.DateTime calcEndDate;
+    if (calcDirection == WorkdayCalculationDirection.Forward) {
+      calcStartDate = startDate.Date;
+      calcEndDate = endDate.Date;
+    } else {
+      calcStartDate = endDate.Date;
+      calcEndDate = startDate.Date;
+    }
+    var nWholeWeeks = (int)calcEndDate.Subtract(calcStartDate).TotalDays / 7;
+    var workdaysCounted = nWholeWeeks * _holidayWeekdays.NumberOfWorkdaysPerWeek;
+    if (!_holidayWeekdays.IsHolidayWeekday(calcStartDate)) {
+      workdaysCounted++;
+    }
+    var tmpDate = calcStartDate.AddDays(nWholeWeeks * 7);
+    while (tmpDate < calcEndDate) {
+      tmpDate = tmpDate.AddDays(1);
+      if (!_holidayWeekdays.IsHolidayWeekday(tmpDate)) {
+        workdaysCounted++;
+      }
+    }
+    return new(workdaysCounted, startDate, endDate, calcDirection);
+  }
+
+  public WorkdayCalculatorResult CalculateWorkday(System.DateTime startDate, int nWorkDays) {
+    var calcDirection =
+        nWorkDays > 0 ? WorkdayCalculationDirection.Forward : WorkdayCalculationDirection.Backward;
+    var direction = (int)calcDirection;
+    nWorkDays *= direction;
+    var workdaysCounted = 0;
+    var tmpDate = startDate;
+
+    // calculate whole weeks
+    var nWholeWeeks = nWorkDays / _holidayWeekdays.NumberOfWorkdaysPerWeek;
+    tmpDate = tmpDate.AddDays(nWholeWeeks * 7 * direction);
+    workdaysCounted += nWholeWeeks * _holidayWeekdays.NumberOfWorkdaysPerWeek;
+
+    // calculate the rest
+    while (workdaysCounted < nWorkDays) {
+      tmpDate = tmpDate.AddDays(direction);
+      if (!_holidayWeekdays.IsHolidayWeekday(tmpDate)) {
+        workdaysCounted++;
+      }
+    }
+    return new(workdaysCounted, startDate, tmpDate, calcDirection);
+  }
+
+  public WorkdayCalculatorResult ReduceWorkdaysWithHolidays(
+      WorkdayCalculatorResult calculatedResult,
+      FunctionArgument holidayArgument) {
+    var startDate = calculatedResult.StartDate;
+    var endDate = calculatedResult.EndDate;
+    var additionalDays = new AdditionalHolidayDays(holidayArgument);
+    System.DateTime calcStartDate;
+    System.DateTime calcEndDate;
+    if (startDate < endDate) {
+      calcStartDate = startDate;
+      calcEndDate = endDate;
+    } else {
+      calcStartDate = endDate;
+      calcEndDate = startDate;
+    }
+    var nAdditionalHolidayDays = additionalDays.AdditionalDates.Count(x =>
+        x >= calcStartDate && x <= calcEndDate && !_holidayWeekdays.IsHolidayWeekday(x));
+    return new(
+        calculatedResult.NumberOfWorkdays - nAdditionalHolidayDays,
+        startDate,
+        endDate,
+        calculatedResult.Direction);
+  }
+
+  public WorkdayCalculatorResult AdjustResultWithHolidays(
+      WorkdayCalculatorResult calculatedResult,
+      FunctionArgument holidayArgument) {
+    var startDate = calculatedResult.StartDate;
+    var endDate = calculatedResult.EndDate;
+    var direction = calculatedResult.Direction;
+    var workdaysCounted = calculatedResult.NumberOfWorkdays;
+    var additionalDays = new AdditionalHolidayDays(holidayArgument);
+    foreach (var date in additionalDays.AdditionalDates) {
+      if (direction == WorkdayCalculationDirection.Forward
+          && (date < startDate || date > endDate)) {
+        continue;
+      }
+      if (direction == WorkdayCalculationDirection.Backward
+          && (date > startDate || date < endDate)) {
+        continue;
+      }
+      if (_holidayWeekdays.IsHolidayWeekday(date)) {
+        continue;
+      }
+      var tmpDate = _holidayWeekdays.GetNextWorkday(endDate, direction);
+      while (additionalDays.AdditionalDates.Contains(tmpDate)) {
+        tmpDate = _holidayWeekdays.GetNextWorkday(tmpDate, direction);
+      }
+      workdaysCounted++;
+      endDate = tmpDate;
+    }
+
+    return new(workdaysCounted, calculatedResult.StartDate, endDate, direction);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculatorResult.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculatorResult.cs
new file mode 100644
index 0000000..9583d95
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculatorResult.cs
@@ -0,0 +1,22 @@
+namespace AppsheetEpplus;
+
+public class WorkdayCalculatorResult {
+  public WorkdayCalculatorResult(
+      int numberOfWorkdays,
+      System.DateTime startDate,
+      System.DateTime endDate,
+      WorkdayCalculationDirection direction) {
+    NumberOfWorkdays = numberOfWorkdays;
+    StartDate = startDate;
+    EndDate = endDate;
+    Direction = direction;
+  }
+
+  public int NumberOfWorkdays { get; }
+
+  public System.DateTime StartDate { get; }
+
+  public System.DateTime EndDate { get; }
+
+  public WorkdayCalculationDirection Direction { get; set; }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Year.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Year.cs
new file mode 100644
index 0000000..d719bff
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Year.cs
@@ -0,0 +1,46 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Year : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var dateObj = arguments.ElementAt(0).Value;
+    System.DateTime date = System.DateTime.MinValue;
+    if (dateObj is string) {
+      date = System.DateTime.Parse(dateObj.ToString());
+    } else {
+      var d = ArgToDecimal(arguments, 0);
+      date = System.DateTime.FromOADate(d);
+    }
+    return CreateResult(date.Year, DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Yearfrac.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Yearfrac.cs
new file mode 100644
index 0000000..b59fcf0
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DateTime/Yearfrac.cs
@@ -0,0 +1,84 @@
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Yearfrac : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray();
+    ValidateArguments(functionArguments, 2);
+    var date1Num = ArgToDecimal(functionArguments, 0);
+    var date2Num = ArgToDecimal(functionArguments, 1);
+    if (date1Num
+        > date2Num) //Switch to make date1 the lowest date
+    {
+      var t = date1Num;
+      date1Num = date2Num;
+      date2Num = t;
+      var fa = functionArguments[1];
+      functionArguments[1] = functionArguments[0];
+      functionArguments[0] = fa;
+    }
+    var date1 = System.DateTime.FromOADate(date1Num);
+    var date2 = System.DateTime.FromOADate(date2Num);
+
+    var basis = 0;
+    if (functionArguments.Count() > 2) {
+      basis = ArgToInt(functionArguments, 2);
+      ThrowExcelErrorValueExceptionIf(() => basis < 0 || basis > 4, eErrorType.Num);
+    }
+    var func = context.Configuration.FunctionRepository.GetFunction("days360");
+    var calendar = new GregorianCalendar();
+    switch (basis) {
+      case 0:
+        var d360Result = System.Math.Abs(func.Execute(functionArguments, context).ResultNumeric);
+        // reproducing excels behaviour
+        if (date1.Month == 2 && date2.Day == 31) {
+          var daysInFeb = calendar.IsLeapYear(date1.Year) ? 29 : 28;
+          if (date1.Day == daysInFeb) {
+            d360Result++;
+          }
+        }
+        return CreateResult(d360Result / 360d, DataType.Decimal);
+      case 1:
+        return CreateResult(
+            System.Math.Abs((date2 - date1).TotalDays / CalculateAcutalYear(date1, date2)),
+            DataType.Decimal);
+      case 2:
+        return CreateResult(System.Math.Abs((date2 - date1).TotalDays / 360d), DataType.Decimal);
+      case 3:
+        return CreateResult(System.Math.Abs((date2 - date1).TotalDays / 365d), DataType.Decimal);
+      case 4:
+        var args = functionArguments.ToList();
+        args.Add(new(true));
+        double? result = System.Math.Abs(func.Execute(args, context).ResultNumeric / 360d);
+        return CreateResult(result.Value, DataType.Decimal);
+      default:
+        return null;
+    }
+  }
+
+  private double CalculateAcutalYear(System.DateTime dt1, System.DateTime dt2) {
+    var calendar = new GregorianCalendar();
+    var perYear = 0d;
+    var nYears = dt2.Year - dt1.Year + 1;
+    for (var y = dt1.Year; y <= dt2.Year; ++y) {
+      perYear += calendar.IsLeapYear(y) ? 366 : 365;
+    }
+    if (new System.DateTime(dt1.Year + 1, dt1.Month, dt1.Day) >= dt2) {
+      nYears = 1;
+      perYear = 365;
+      if (calendar.IsLeapYear(dt1.Year) && dt1.Month <= 2) {
+        perYear = 366;
+      } else if (calendar.IsLeapYear(dt2.Year) && dt2.Month > 2) {
+        perYear = 366;
+      } else if (dt2.Month == 2 && dt2.Day == 29) {
+        perYear = 366;
+      }
+    }
+    return perYear / nYears;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DecimalCompileResultValidator.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DecimalCompileResultValidator.cs
new file mode 100644
index 0000000..8ef9011
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DecimalCompileResultValidator.cs
@@ -0,0 +1,36 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-26
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+public class DecimalCompileResultValidator : CompileResultValidator {
+  public override void Validate(object obj) {
+    var num = ConvertUtil.GetValueDouble(obj);
+    if (double.IsNaN(num) || double.IsInfinity(num)) {
+      throw new ExcelErrorValueException(eErrorType.Num);
+    }
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DoubleArgumentParser.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DoubleArgumentParser.cs
new file mode 100644
index 0000000..ea04b67
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DoubleArgumentParser.cs
@@ -0,0 +1,52 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Globalization;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class DoubleArgumentParser : ArgumentParser {
+  public override object Parse(object obj) {
+    Require.That(obj).Named("argument").IsNotNull();
+    if (obj is ExcelDataProvider.IRangeInfo info) {
+      var r = info.FirstOrDefault();
+      return r?.ValueDouble ?? 0;
+    }
+    if (obj is double) {
+      return obj;
+    }
+    if (obj.IsNumeric()) {
+      return ConvertUtil.GetValueDouble(obj);
+    }
+    var str = obj != null ? obj.ToString() : string.Empty;
+    try {
+      return double.Parse(str, CultureInfo.InvariantCulture);
+    } catch // (Exception e)
+    {
+      throw new ExcelErrorValueException(ExcelErrorValue.Create(eErrorType.Value));
+    }
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/DoubleEnumerableArgConverter.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/DoubleEnumerableArgConverter.cs
new file mode 100644
index 0000000..fcf6908
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/DoubleEnumerableArgConverter.cs
@@ -0,0 +1,82 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class DoubleEnumerableArgConverter : CollectionFlattener<double> {
+  public virtual IEnumerable<double> ConvertArgs(
+      bool ignoreHidden,
+      bool ignoreErrors,
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    return base.FuncArgsToFlatEnumerable(
+        arguments,
+        (arg, argList) => {
+          if (arg.IsExcelRange) {
+            foreach (var cell in arg.ValueAsRangeInfo) {
+              if (!ignoreErrors && cell.IsExcelError) {
+                throw new ExcelErrorValueException(ExcelErrorValue.Parse(cell.Value.ToString()));
+              }
+              if (!CellStateHelper.ShouldIgnore(ignoreHidden, cell, context)
+                  && ConvertUtil.IsNumeric(cell.Value)) {
+                argList.Add(cell.ValueDouble);
+              }
+            }
+          } else {
+            if (!ignoreErrors && arg.ValueIsExcelError) {
+              throw new ExcelErrorValueException(arg.ValueAsExcelErrorValue);
+            }
+            if (ConvertUtil.IsNumeric(arg.Value)
+                && !CellStateHelper.ShouldIgnore(ignoreHidden, arg, context)) {
+              argList.Add(ConvertUtil.GetValueDouble(arg.Value));
+            }
+          }
+        });
+  }
+
+  public virtual IEnumerable<double> ConvertArgsIncludingOtherTypes(
+      IEnumerable<FunctionArgument> arguments) {
+    return base.FuncArgsToFlatEnumerable(
+        arguments,
+        (arg, argList) => {
+          //var cellInfo = arg.Value as EpplusExcelDataProvider.CellInfo;
+          //var value = cellInfo != null ? cellInfo.Value : arg.Value;
+          if (arg.Value is ExcelDataProvider.IRangeInfo info) {
+            foreach (var cell in info) {
+              argList.Add(cell.ValueDoubleLogical);
+            }
+          } else {
+            if (arg.Value is double || arg.Value is int || arg.Value is bool) {
+              argList.Add(Convert.ToDouble(arg.Value));
+            } else if (arg.Value is string) {
+              argList.Add(0d);
+            }
+          }
+        });
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/ErrorHandlingFunction.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/ErrorHandlingFunction.cs
new file mode 100644
index 0000000..c63545b
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/ErrorHandlingFunction.cs
@@ -0,0 +1,47 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Base class for functions that handles an error that occurs during the
+/// normal execution of the function.
+/// If an exception occurs during the Execute-call that exception will be
+/// caught by the compiler, then the HandleError-method will be called.
+/// </summary>
+public abstract class ErrorHandlingFunction : ExcelFunction {
+  /// <summary>
+  /// Indicates that the function is an ErrorHandlingFunction.
+  /// </summary>
+  public override bool IsErrorHandlingFunction => true;
+
+  /// <summary>
+  /// Method that should be implemented to handle the error.
+  /// </summary>
+  /// <param name="errorCode"></param>
+  /// <returns></returns>
+  public abstract CompileResult HandleError(string errorCode);
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/ExcelFunction.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/ExcelFunction.cs
new file mode 100644
index 0000000..3a359ae
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/ExcelFunction.cs
@@ -0,0 +1,436 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.RegularExpressions;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Base class for Excel function implementations.
+/// </summary>
+public abstract class ExcelFunction {
+  public ExcelFunction()
+      : this(new(), new(), new()) {}
+
+  public ExcelFunction(
+      ArgumentCollectionUtil argumentCollectionUtil,
+      ArgumentParsers argumentParsers,
+      CompileResultValidators compileResultValidators) {
+    _argumentCollectionUtil = argumentCollectionUtil;
+    _argumentParsers = argumentParsers;
+    _compileResultValidators = compileResultValidators;
+  }
+
+  private readonly ArgumentCollectionUtil _argumentCollectionUtil;
+  private readonly ArgumentParsers _argumentParsers;
+  private readonly CompileResultValidators _compileResultValidators;
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="arguments">Arguments to the function, each argument can contain primitive types, lists or <see cref="ExcelDataProvider.IRangeInfo">Excel ranges</see></param>
+  /// <param name="context">The <see cref="ParsingContext"/> contains various data that can be useful in functions.</param>
+  /// <returns>A <see cref="CompileResult"/> containing the calculated value</returns>
+  public abstract CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context);
+
+  /// <summary>
+  /// If overridden, this method is called before Execute is called.
+  /// </summary>
+  /// <param name="context"></param>
+  public virtual void BeforeInvoke(ParsingContext context) {}
+
+  public virtual bool IsLookupFuction => false;
+
+  public virtual bool IsErrorHandlingFunction => false;
+
+  /// <summary>
+  /// Used for some Lookupfunctions to indicate that function arguments should
+  /// not be compiled before the function is called.
+  /// </summary>
+  public bool SkipArgumentEvaluation { get; set; }
+
+  protected object GetFirstValue(IEnumerable<FunctionArgument> val) {
+    var arg = val.FirstOrDefault();
+    if (arg.Value is ExcelDataProvider.IRangeInfo) {
+      //var r=((ExcelDataProvider.IRangeInfo)arg);
+      var r = arg.ValueAsRangeInfo;
+      return r.GetValue(r.Address._fromRow, r.Address._fromCol);
+    }
+    return arg?.Value;
+  }
+
+  /// <summary>
+  /// This functions validates that the supplied <paramref name="arguments"/> contains at least
+  /// (the value of) <paramref name="minLength"/> elements. If one of the arguments is an
+  /// <see cref="ExcelDataProvider.IRangeInfo">Excel range</see> the number of cells in
+  /// that range will be counted as well.
+  /// </summary>
+  /// <param name="arguments"></param>
+  /// <param name="minLength"></param>
+  /// <param name="errorTypeToThrow">The <see cref="eErrorType"/> of the <see cref="ExcelErrorValueException"/> that will be thrown if <paramref name="minLength"/> is not met.</param>
+  protected void ValidateArguments(
+      IEnumerable<FunctionArgument> arguments,
+      int minLength,
+      eErrorType errorTypeToThrow) {
+    Require.That(arguments).Named("arguments").IsNotNull();
+    ThrowExcelErrorValueExceptionIf(
+        () => {
+          var nArgs = 0;
+          if (arguments.Any()) {
+            foreach (var arg in arguments) {
+              nArgs++;
+              if (nArgs >= minLength) {
+                return false;
+              }
+              if (arg.IsExcelRange) {
+                nArgs += arg.ValueAsRangeInfo.GetNCells();
+                if (nArgs >= minLength) {
+                  return false;
+                }
+              }
+            }
+          }
+          return true;
+        },
+        errorTypeToThrow);
+  }
+
+  /// <summary>
+  /// This functions validates that the supplied <paramref name="arguments"/> contains at least
+  /// (the value of) <paramref name="minLength"/> elements. If one of the arguments is an
+  /// <see cref="ExcelDataProvider.IRangeInfo">Excel range</see> the number of cells in
+  /// that range will be counted as well.
+  /// </summary>
+  /// <param name="arguments"></param>
+  /// <param name="minLength"></param>
+  /// <exception cref="ArgumentException"></exception>
+  protected void ValidateArguments(IEnumerable<FunctionArgument> arguments, int minLength) {
+    Require.That(arguments).Named("arguments").IsNotNull();
+    ThrowArgumentExceptionIf(
+        () => {
+          var nArgs = 0;
+          if (arguments.Any()) {
+            foreach (var arg in arguments) {
+              nArgs++;
+              if (nArgs >= minLength) {
+                return false;
+              }
+              if (arg.IsExcelRange) {
+                nArgs += arg.ValueAsRangeInfo.GetNCells();
+                if (nArgs >= minLength) {
+                  return false;
+                }
+              }
+            }
+          }
+          return true;
+        },
+        "Expecting at least {0} arguments",
+        minLength.ToString());
+  }
+
+  /// <summary>
+  /// Returns the value of the argument att the position of the 0-based
+  /// <paramref name="index"/> as an integer.
+  /// </summary>
+  /// <param name="arguments"></param>
+  /// <param name="index"></param>
+  /// <returns>Value of the argument as an integer.</returns>
+  /// <exception cref="ExcelErrorValueException"></exception>
+  protected int ArgToInt(IEnumerable<FunctionArgument> arguments, int index) {
+    var val = arguments.ElementAt(index).ValueFirst;
+    return (int)_argumentParsers.GetParser(DataType.Integer).Parse(val);
+  }
+
+  /// <summary>
+  /// Returns the value of the argument att the position of the 0-based
+  /// <paramref name="index"/> as a string.
+  /// </summary>
+  /// <param name="arguments"></param>
+  /// <param name="index"></param>
+  /// <returns>Value of the argument as a string.</returns>
+  protected string ArgToString(IEnumerable<FunctionArgument> arguments, int index) {
+    var obj = arguments.ElementAt(index).ValueFirst;
+    return obj != null ? obj.ToString() : string.Empty;
+  }
+
+  /// <summary>
+  /// Returns the value of the argument att the position of the 0-based
+  /// </summary>
+  /// <param name="obj"></param>
+  /// <returns>Value of the argument as a double.</returns>
+  /// <exception cref="ExcelErrorValueException"></exception>
+  protected double ArgToDecimal(object obj) {
+    return (double)_argumentParsers.GetParser(DataType.Decimal).Parse(obj);
+  }
+
+  /// <summary>
+  /// Returns the value of the argument att the position of the 0-based
+  /// <paramref name="index"/> as a <see cref="System.Double"/>.
+  /// </summary>
+  /// <param name="arguments"></param>
+  /// <param name="index"></param>
+  /// <returns>Value of the argument as an integer.</returns>
+  /// <exception cref="ExcelErrorValueException"></exception>
+  protected double ArgToDecimal(IEnumerable<FunctionArgument> arguments, int index) {
+    return ArgToDecimal(arguments.ElementAt(index).Value);
+  }
+
+  protected double Divide(double left, double right) {
+    if (System.Math.Abs(right - 0d) < double.Epsilon) {
+      throw new ExcelErrorValueException(eErrorType.Div0);
+    }
+    return left / right;
+  }
+
+  protected bool IsNumericString(object value) {
+    if (value == null || string.IsNullOrEmpty(value.ToString())) {
+      return false;
+    }
+    return Regex.IsMatch(value.ToString(), @"^[\d]+(\,[\d])?");
+  }
+
+  /// <summary>
+  /// If the argument is a boolean value its value will be returned.
+  /// If the argument is an integer value, true will be returned if its
+  /// value is not 0, otherwise false.
+  /// </summary>
+  /// <param name="arguments"></param>
+  /// <param name="index"></param>
+  /// <returns></returns>
+  protected bool ArgToBool(IEnumerable<FunctionArgument> arguments, int index) {
+    var obj = arguments.ElementAt(index).Value ?? string.Empty;
+    return (bool)_argumentParsers.GetParser(DataType.Boolean).Parse(obj);
+  }
+
+  /// <summary>
+  /// Throws an <see cref="ArgumentException"/> if <paramref name="condition"/> evaluates to true.
+  /// </summary>
+  /// <param name="condition"></param>
+  /// <param name="message"></param>
+  /// <exception cref="ArgumentException"></exception>
+  protected void ThrowArgumentExceptionIf(Func<bool> condition, string message) {
+    if (condition()) {
+      throw new ArgumentException(message);
+    }
+  }
+
+  /// <summary>
+  /// Throws an <see cref="ArgumentException"/> if <paramref name="condition"/> evaluates to true.
+  /// </summary>
+  /// <param name="condition"></param>
+  /// <param name="message"></param>
+  /// <param name="formats">Formats to the message string.</param>
+  protected void ThrowArgumentExceptionIf(
+      Func<bool> condition,
+      string message,
+      params object[] formats) {
+    message = string.Format(message, formats);
+    ThrowArgumentExceptionIf(condition, message);
+  }
+
+  /// <summary>
+  /// Throws an <see cref="ExcelErrorValueException"/> with the given <paramref name="errorType"/> set.
+  /// </summary>
+  /// <param name="errorType"></param>
+  protected void ThrowExcelErrorValueException(eErrorType errorType) {
+    throw new ExcelErrorValueException(
+        "An excel function error occurred",
+        ExcelErrorValue.Create(errorType));
+  }
+
+  /// <summary>
+  /// Throws an <see cref="ArgumentException"/> if <paramref name="condition"/> evaluates to true.
+  /// </summary>
+  /// <param name="condition"></param>
+  /// <param name="errorType"></param>
+  /// <exception cref="ExcelErrorValueException"></exception>
+  protected void ThrowExcelErrorValueExceptionIf(Func<bool> condition, eErrorType errorType) {
+    if (condition()) {
+      throw new ExcelErrorValueException(
+          "An excel function error occurred",
+          ExcelErrorValue.Create(errorType));
+    }
+  }
+
+  protected bool IsNumeric(object val) {
+    if (val == null) {
+      return false;
+    }
+    return (val.GetType().IsPrimitive
+            || val is double
+            || val is decimal
+            || val is System.DateTime
+            || val is TimeSpan);
+  }
+
+  //protected virtual bool IsNumber(object obj)
+  //{
+  //    if (obj == null) return false;
+  //    return (obj is int || obj is double || obj is short || obj is decimal || obj is long);
+  //}
+
+  /// <summary>
+  /// Helper method for comparison of two doubles.
+  /// </summary>
+  /// <param name="d1"></param>
+  /// <param name="d2"></param>
+  /// <returns></returns>
+  protected bool AreEqual(double d1, double d2) {
+    return System.Math.Abs(d1 - d2) < double.Epsilon;
+  }
+
+  /// <summary>
+  /// Will return the arguments as an enumerable of doubles.
+  /// </summary>
+  /// <param name="arguments"></param>
+  /// <param name="context"></param>
+  /// <returns></returns>
+  protected virtual IEnumerable<double> ArgsToDoubleEnumerable(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    return ArgsToDoubleEnumerable(false, arguments, context);
+  }
+
+  /// <summary>
+  /// Will return the arguments as an enumerable of doubles.
+  /// </summary>
+  /// <param name="ignoreHiddenCells">If a cell is hidden and this value is true the value of that cell will be ignored</param>
+  /// <param name="ignoreErrors">If a cell contains an error, that error will be ignored if this method is set to true</param>
+  /// <param name="arguments"></param>
+  /// <param name="context"></param>
+  /// <returns></returns>
+  protected virtual IEnumerable<double> ArgsToDoubleEnumerable(
+      bool ignoreHiddenCells,
+      bool ignoreErrors,
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    return _argumentCollectionUtil.ArgsToDoubleEnumerable(
+        ignoreHiddenCells,
+        ignoreErrors,
+        arguments,
+        context);
+  }
+
+  /// <summary>
+  /// Will return the arguments as an enumerable of doubles.
+  /// </summary>
+  /// <param name="ignoreHiddenCells">If a cell is hidden and this value is true the value of that cell will be ignored</param>
+  /// <param name="arguments"></param>
+  /// <param name="context"></param>
+  /// <returns></returns>
+  protected virtual IEnumerable<double> ArgsToDoubleEnumerable(
+      bool ignoreHiddenCells,
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    return ArgsToDoubleEnumerable(ignoreHiddenCells, true, arguments, context);
+  }
+
+  /// <summary>
+  /// Will return the arguments as an enumerable of objects.
+  /// </summary>
+  /// <param name="ignoreHiddenCells">If a cell is hidden and this value is true the value of that cell will be ignored</param>
+  /// <param name="arguments"></param>
+  /// <param name="context"></param>
+  /// <returns></returns>
+  protected virtual IEnumerable<object> ArgsToObjectEnumerable(
+      bool ignoreHiddenCells,
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    return _argumentCollectionUtil.ArgsToObjectEnumerable(ignoreHiddenCells, arguments, context);
+  }
+
+  /// <summary>
+  /// Use this method to create a result to return from Excel functions.
+  /// </summary>
+  /// <param name="result"></param>
+  /// <param name="dataType"></param>
+  /// <returns></returns>
+  protected CompileResult CreateResult(object result, DataType dataType) {
+    var validator = _compileResultValidators.GetValidator(dataType);
+    validator.Validate(result);
+    return new(result, dataType);
+  }
+
+  /// <summary>
+  /// Use this method to apply a function on a collection of arguments. The <paramref name="result"/>
+  /// should be modifyed in the supplied <paramref name="action"/> and will contain the result
+  /// after this operation has been performed.
+  /// </summary>
+  /// <param name="collection"></param>
+  /// <param name="result"></param>
+  /// <param name="action"></param>
+  /// <returns></returns>
+  protected virtual double CalculateCollection(
+      IEnumerable<FunctionArgument> collection,
+      double result,
+      Func<FunctionArgument, double, double> action) {
+    return _argumentCollectionUtil.CalculateCollection(collection, result, action);
+  }
+
+  /// <summary>
+  /// if the supplied <paramref name="arg">argument</paramref> contains an Excel error
+  /// an <see cref="ExcelErrorValueException"/> with that errorcode will be thrown
+  /// </summary>
+  /// <param name="arg"></param>
+  /// <exception cref="ExcelErrorValueException"></exception>
+  protected void CheckForAndHandleExcelError(FunctionArgument arg) {
+    if (arg.ValueIsExcelError) {
+      throw (new ExcelErrorValueException(arg.ValueAsExcelErrorValue));
+    }
+  }
+
+  /// <summary>
+  /// If the supplied <paramref name="cell"/> contains an Excel error
+  /// an <see cref="ExcelErrorValueException"/> with that errorcode will be thrown
+  /// </summary>
+  /// <param name="cell"></param>
+  protected void CheckForAndHandleExcelError(ExcelDataProvider.ICellInfo cell) {
+    if (cell.IsExcelError) {
+      throw (new ExcelErrorValueException(ExcelErrorValue.Parse(cell.Value.ToString())));
+    }
+  }
+
+  protected CompileResult GetResultByObject(object result) {
+    if (IsNumeric(result)) {
+      return CreateResult(result, DataType.Decimal);
+    }
+    if (result is string) {
+      return CreateResult(result, DataType.String);
+    }
+    if (ExcelErrorValue.Values.IsErrorValue(result)) {
+      return CreateResult(result, DataType.ExcelAddress);
+    }
+    if (result == null) {
+      return CompileResult.Empty;
+    }
+    return CreateResult(result, DataType.Enumerable);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/FunctionArgument.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/FunctionArgument.cs
new file mode 100644
index 0000000..3d93f48
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/FunctionArgument.cs
@@ -0,0 +1,69 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System;
+
+namespace AppsheetEpplus;
+
+public class FunctionArgument {
+  public FunctionArgument(object val) {
+    Value = val;
+  }
+
+  private ExcelCellState _excelCellState;
+
+  public void SetExcelStateFlag(ExcelCellState state) {
+    _excelCellState |= state;
+  }
+
+  public bool ExcelStateFlagIsSet(ExcelCellState state) {
+    return (_excelCellState & state) != 0;
+  }
+
+  public object Value { get; private set; }
+
+  public Type Type => Value?.GetType();
+
+  public bool IsExcelRange => Value != null && Value is ExcelDataProvider.IRangeInfo;
+
+  public bool ValueIsExcelError => ExcelErrorValue.Values.IsErrorValue(Value);
+
+  public ExcelErrorValue ValueAsExcelErrorValue => ExcelErrorValue.Parse(Value.ToString());
+
+  public ExcelDataProvider.IRangeInfo ValueAsRangeInfo => Value as ExcelDataProvider.IRangeInfo;
+
+  public object ValueFirst {
+    get {
+      if (Value is ExcelDataProvider.INameInfo info) {
+        Value = info.Value;
+      }
+      var v = Value as ExcelDataProvider.IRangeInfo;
+      if (v == null) {
+        return Value;
+      }
+      return v.GetValue(v.Address._fromRow, v.Address._fromCol);
+    }
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/FunctionNameProvider.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/FunctionNameProvider.cs
new file mode 100644
index 0000000..87ec87d
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/FunctionNameProvider.cs
@@ -0,0 +1,36 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public class FunctionNameProvider : IFunctionNameProvider {
+  private FunctionNameProvider() {}
+
+  public static FunctionNameProvider Empty => new();
+
+  public virtual bool IsFunctionName(string name) {
+    return false;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/FunctionRepository.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/FunctionRepository.cs
new file mode 100644
index 0000000..5927624
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/FunctionRepository.cs
@@ -0,0 +1,120 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+
+namespace AppsheetEpplus;
+
+// Used to report the names of Excel functions that are not supported by EPPlus
+public class FunctionException : SystemException {
+  // Summary:
+  //     Initializes a new instance of the System.FunctionException class.
+  public FunctionException() {}
+
+  //
+  // Summary:
+  //     Initializes a new instance of the System.FunctionException class with a specified
+  //     error message.
+  //
+  // Parameters:
+  //   message:
+  //     The message that describes the error.
+  public FunctionException(string message)
+      : base(message) {}
+}
+
+/// <summary>
+/// This class provides methods for accessing/modifying VBA Functions.
+/// </summary>
+public class FunctionRepository : IFunctionNameProvider {
+  private readonly Dictionary<string, ExcelFunction> _functions = new(
+      StringComparer.InvariantCulture);
+
+  private FunctionRepository() {}
+
+  public static FunctionRepository Create() {
+    var repo = new FunctionRepository();
+    repo.LoadModule(new BuiltInFunctions());
+    return repo;
+  }
+
+  /// <summary>
+  /// Loads a module of <see cref="ExcelFunction"/>s to the function repository.
+  /// </summary>
+  /// <param name="module">A <see cref="IFunctionModule"/> that can be used for adding functions</param>
+  public virtual void LoadModule(IFunctionModule module) {
+    foreach (var key in module.Functions.Keys) {
+      var lowerKey = key.ToLower(CultureInfo.InvariantCulture);
+      _functions[lowerKey] = module.Functions[key];
+    }
+  }
+
+  public virtual ExcelFunction GetFunction(string name) {
+    if (!_functions.ContainsKey(name.ToLower(CultureInfo.InvariantCulture))) {
+      // Report that Excel function is not supported by EPPlus
+      throw new FunctionException(
+          string.Format("Excel function '{0}' is not supported in formulas.", name));
+    }
+    return _functions[name.ToLower(CultureInfo.InvariantCulture)];
+  }
+
+  /// <summary>
+  /// Removes all functions from the repository
+  /// </summary>
+  public virtual void Clear() {
+    _functions.Clear();
+  }
+
+  /// <summary>
+  /// Returns true if the the supplied <paramref name="name"/> exists in the repository.
+  /// </summary>
+  /// <param name="name"></param>
+  /// <returns></returns>
+  public bool IsFunctionName(string name) {
+    return _functions.ContainsKey(name.ToLower(CultureInfo.InvariantCulture));
+  }
+
+  /// <summary>
+  /// Returns the names of all implemented functions.
+  /// </summary>
+  public IEnumerable<string> FunctionNames => _functions.Keys;
+
+  /// <summary>
+  /// Adds or replaces a function.
+  /// </summary>
+  /// <param name="functionName"> Case-insensitive name of the function that should be added or replaced.</param>
+  /// <param name="functionImpl">An implementation of an <see cref="ExcelFunction"/>.</param>
+  public void AddOrReplaceFunction(string functionName, ExcelFunction functionImpl) {
+    Require.That(functionName).Named("functionName").IsNotNullOrEmpty();
+    Require.That(functionImpl).Named("functionImpl").IsNotNull();
+    var fName = functionName.ToLower(CultureInfo.InvariantCulture);
+    if (_functions.ContainsKey(fName)) {
+      _functions.Remove(fName);
+    }
+    _functions[fName] = functionImpl;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/FunctionsModule.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/FunctionsModule.cs
new file mode 100644
index 0000000..6ea6d70
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/FunctionsModule.cs
@@ -0,0 +1,37 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Base class
+/// </summary>
+public abstract class FunctionsModule : IFunctionModule {
+  private readonly Dictionary<string, ExcelFunction> _functions = new();
+
+  public IDictionary<string, ExcelFunction> Functions => _functions;
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/HiddenValuesHandlingFunction.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/HiddenValuesHandlingFunction.cs
new file mode 100644
index 0000000..9941304
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/HiddenValuesHandlingFunction.cs
@@ -0,0 +1,70 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Base class for functions that needs to handle cells that is not visible.
+/// </summary>
+public abstract class HiddenValuesHandlingFunction : ExcelFunction {
+  /// <summary>
+  /// Set to true or false to indicate whether the function should ignore hidden values.
+  /// </summary>
+  public bool IgnoreHiddenValues { get; set; }
+
+  protected override IEnumerable<double> ArgsToDoubleEnumerable(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    return ArgsToDoubleEnumerable(arguments, context, true);
+  }
+
+  protected IEnumerable<double> ArgsToDoubleEnumerable(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context,
+      bool ignoreErrors) {
+    if (!arguments.Any()) {
+      return [];
+    }
+    if (IgnoreHiddenValues) {
+      var nonHidden = arguments.Where(x => !x.ExcelStateFlagIsSet(ExcelCellState.HiddenCell));
+      return base.ArgsToDoubleEnumerable(IgnoreHiddenValues, nonHidden, context);
+    }
+    return base.ArgsToDoubleEnumerable(IgnoreHiddenValues, ignoreErrors, arguments, context);
+  }
+
+  protected bool ShouldIgnore(ExcelDataProvider.ICellInfo c, ParsingContext context) {
+    return CellStateHelper.ShouldIgnore(IgnoreHiddenValues, c, context);
+  }
+
+  protected bool ShouldIgnore(FunctionArgument arg) {
+    if (IgnoreHiddenValues && arg.ExcelStateFlagIsSet(ExcelCellState.HiddenCell)) {
+      return true;
+    }
+    return false;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/IFunctionModule.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/IFunctionModule.cs
new file mode 100644
index 0000000..025cbfd
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/IFunctionModule.cs
@@ -0,0 +1,32 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public interface IFunctionModule {
+  IDictionary<string, ExcelFunction> Functions { get; }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/IFunctionNameProvider.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/IFunctionNameProvider.cs
new file mode 100644
index 0000000..59d5871
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/IFunctionNameProvider.cs
@@ -0,0 +1,30 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public interface IFunctionNameProvider {
+  bool IsFunctionName(string name);
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/ErrorType.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/ErrorType.cs
new file mode 100644
index 0000000..f028b4e
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/ErrorType.cs
@@ -0,0 +1,64 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-01-15
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class ErrorType : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var error = arguments.ElementAt(0);
+    var isErrorFunc = context.Configuration.FunctionRepository.GetFunction("iserror");
+    var isErrorResult = isErrorFunc.Execute(arguments, context);
+    if (!(bool)isErrorResult.Result) {
+      return CreateResult(ExcelErrorValue.Create(eErrorType.Na), DataType.ExcelError);
+    }
+    var errorType = error.ValueAsExcelErrorValue;
+    switch (errorType.Type) {
+      case eErrorType.Null:
+        return CreateResult(1, DataType.Integer);
+      case eErrorType.Div0:
+        return CreateResult(2, DataType.Integer);
+      case eErrorType.Value:
+        return CreateResult(3, DataType.Integer);
+      case eErrorType.Ref:
+        return CreateResult(4, DataType.Integer);
+      case eErrorType.Name:
+        return CreateResult(5, DataType.Integer);
+      case eErrorType.Num:
+        return CreateResult(6, DataType.Integer);
+      case eErrorType.Na:
+        return CreateResult(7, DataType.Integer);
+      // Bug G0004
+      case eErrorType.Error:
+        return CreateResult(8, DataType.Integer);
+    }
+    return CreateResult(ExcelErrorValue.Create(eErrorType.Na), DataType.ExcelError);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsBlank.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsBlank.cs
new file mode 100644
index 0000000..568d757
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsBlank.cs
@@ -0,0 +1,53 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class IsBlank : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    if (arguments == null || arguments.Count() == 0) {
+      return CreateResult(true, DataType.Boolean);
+    }
+    var result = true;
+    foreach (var arg in arguments) {
+      if (arg.Value is ExcelDataProvider.IRangeInfo info) {
+        if (info.GetValue(info.Address._fromRow, info.Address._fromCol) != null) {
+          result = false;
+        }
+      } else {
+        if (arg.Value != null && (arg.Value.ToString() != string.Empty)) {
+          result = false;
+          break;
+        }
+      }
+    }
+    return CreateResult(result, DataType.Boolean);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsErr.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsErr.cs
new file mode 100644
index 0000000..91346ca
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsErr.cs
@@ -0,0 +1,30 @@
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class IsErr : ErrorHandlingFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    var isError = new IsError();
+    var result = isError.Execute(arguments, context);
+    if ((bool)result.Result) {
+      var arg = GetFirstValue(arguments);
+      if (arg is ExcelDataProvider.IRangeInfo info) {
+        var e = info.GetValue(info.Address._fromRow, info.Address._fromCol) as ExcelErrorValue;
+        if (e != null && e.Type == eErrorType.Na) {
+          return CreateResult(false, DataType.Boolean);
+        }
+      } else {
+        if (arg is ExcelErrorValue value && value.Type == eErrorType.Na) {
+          return CreateResult(false, DataType.Boolean);
+        }
+      }
+    }
+    return result;
+  }
+
+  public override CompileResult HandleError(string errorCode) {
+    return CreateResult(true, DataType.Boolean);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsError.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsError.cs
new file mode 100644
index 0000000..9147876
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsError.cs
@@ -0,0 +1,56 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class IsError : ErrorHandlingFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    if (arguments == null || arguments.Count() == 0) {
+      return CreateResult(false, DataType.Boolean);
+    }
+    foreach (var argument in arguments) {
+      if (argument.Value is ExcelDataProvider.IRangeInfo info) {
+        if (ExcelErrorValue.Values.IsErrorValue(
+            info.GetValue(info.Address._fromRow, info.Address._fromCol))) {
+          return CreateResult(true, DataType.Boolean);
+        }
+      } else {
+        if (ExcelErrorValue.Values.IsErrorValue(argument.Value)) {
+          return CreateResult(true, DataType.Boolean);
+        }
+      }
+    }
+    return CreateResult(false, DataType.Boolean);
+  }
+
+  public override CompileResult HandleError(string errorCode) {
+    return CreateResult(true, DataType.Boolean);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsEven.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsEven.cs
new file mode 100644
index 0000000..9bed4f7
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsEven.cs
@@ -0,0 +1,17 @@
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class IsEven : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var arg1 = GetFirstValue(arguments); //arguments.ElementAt(0);
+    if (!ConvertUtil.IsNumeric(arg1)) {
+      ThrowExcelErrorValueException(eErrorType.Value);
+    }
+    var number = (int)System.Math.Floor(ConvertUtil.GetValueDouble(arg1));
+    return CreateResult(number % 2 == 0, DataType.Boolean);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsLogical.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsLogical.cs
new file mode 100644
index 0000000..94f4628
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsLogical.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class IsLogical : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray();
+    ValidateArguments(functionArguments, 1);
+    var v = GetFirstValue(arguments);
+    return CreateResult(v is bool, DataType.Boolean);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsNa.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsNa.cs
new file mode 100644
index 0000000..fecaabb
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsNa.cs
@@ -0,0 +1,46 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-01-15
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class IsNa : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    if (arguments == null || arguments.Count() == 0) {
+      return CreateResult(false, DataType.Boolean);
+    }
+
+    var v = GetFirstValue(arguments);
+
+    if (v is ExcelErrorValue value && value.Type == eErrorType.Na) {
+      return CreateResult(true, DataType.Boolean);
+    }
+    return CreateResult(false, DataType.Boolean);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsNonText.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsNonText.cs
new file mode 100644
index 0000000..ad7700d
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsNonText.cs
@@ -0,0 +1,42 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-01-15
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class IsNonText : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var firstArg = arguments.ElementAt(0);
+    if (firstArg.Value == null || firstArg.ValueIsExcelError) {
+      return CreateResult(false, DataType.Boolean);
+    }
+    return CreateResult(!(firstArg.Value is string), DataType.Boolean);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsNumber.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsNumber.cs
new file mode 100644
index 0000000..fd049cf
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsNumber.cs
@@ -0,0 +1,38 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class IsNumber : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var arg = GetFirstValue(arguments);
+    return CreateResult(IsNumeric(arg), DataType.Boolean);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsOdd.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsOdd.cs
new file mode 100644
index 0000000..b69524e
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsOdd.cs
@@ -0,0 +1,42 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-01-15
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class IsOdd : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var arg1 = GetFirstValue(arguments); //arguments.ElementAt(0);
+    if (!ConvertUtil.IsNumeric(arg1)) {
+      ThrowExcelErrorValueException(eErrorType.Value);
+    }
+    var number = (int)System.Math.Floor(ConvertUtil.GetValueDouble(arg1));
+    return CreateResult(number % 2 == 1, DataType.Boolean);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsText.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsText.cs
new file mode 100644
index 0000000..d4e4e31
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/IsText.cs
@@ -0,0 +1,41 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class IsText : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    if (arguments.Count() == 1 && arguments.ElementAt(0).Value != null) {
+      return CreateResult((GetFirstValue(arguments) is string), DataType.Boolean);
+    }
+    return CreateResult(false, DataType.Boolean);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/N.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/N.cs
new file mode 100644
index 0000000..1544445
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/N.cs
@@ -0,0 +1,28 @@
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class N : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var arg = GetFirstValue(arguments);
+
+    if (arg is bool b) {
+      var val = b ? 1d : 0d;
+      return CreateResult(val, DataType.Decimal);
+    }
+    if (IsNumeric(arg)) {
+      var val = ConvertUtil.GetValueDouble(arg);
+      return CreateResult(val, DataType.Decimal);
+    }
+    if (arg is string) {
+      return CreateResult(0d, DataType.Decimal);
+    }
+    if (arg is ExcelErrorValue) {
+      return CreateResult(arg, DataType.ExcelError);
+    }
+    throw new ExcelErrorValueException(eErrorType.Value);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/Na.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/Na.cs
new file mode 100644
index 0000000..6247dc4
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Information/Na.cs
@@ -0,0 +1,11 @@
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Na : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    return CreateResult(ExcelErrorValue.Create(eErrorType.Na), DataType.ExcelError);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/IntArgumentParser.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/IntArgumentParser.cs
new file mode 100644
index 0000000..e5e8a99
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/IntArgumentParser.cs
@@ -0,0 +1,50 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class IntArgumentParser : ArgumentParser {
+  public override object Parse(object obj) {
+    Require.That(obj).Named("argument").IsNotNull();
+    if (obj is ExcelDataProvider.IRangeInfo info) {
+      var r = info.FirstOrDefault();
+      return r == null ? 0 : Convert.ToInt32(r.ValueDouble);
+    }
+    var objType = obj.GetType();
+    if (objType == typeof(int)) {
+      return (int)obj;
+    }
+    if (objType == typeof(double) || objType == typeof(decimal)) {
+      return Convert.ToInt32(obj);
+    }
+    if (!int.TryParse(obj.ToString(), out var result)) {
+      throw new ExcelErrorValueException(ExcelErrorValue.Create(eErrorType.Value));
+    }
+    return result;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Logical/And.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Logical/And.cs
new file mode 100644
index 0000000..311a2b3
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Logical/And.cs
@@ -0,0 +1,43 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class And : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    for (var x = 0; x < arguments.Count(); x++) {
+      if (!ArgToBool(arguments, x)) {
+        return new(false, DataType.Boolean);
+      }
+    }
+    return new(true, DataType.Boolean);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Logical/False.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Logical/False.cs
new file mode 100644
index 0000000..89aa4e8
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Logical/False.cs
@@ -0,0 +1,36 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class False : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    return CreateResult(false, DataType.Boolean);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Logical/If.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Logical/If.cs
new file mode 100644
index 0000000..31c0d50
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Logical/If.cs
@@ -0,0 +1,42 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class If : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 3);
+    var condition = ArgToBool(arguments, 0);
+    var firstStatement = arguments.ElementAt(1).Value;
+    var secondStatement = arguments.ElementAt(2).Value;
+    var factory = new CompileResultFactory();
+    return condition ? factory.Create(firstStatement) : factory.Create(secondStatement);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Logical/IfError.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Logical/IfError.cs
new file mode 100644
index 0000000..e71272d
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Logical/IfError.cs
@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class IfError : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var firstArg = arguments.First();
+    return GetResultByObject(firstArg.Value);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Logical/IfNa.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Logical/IfNa.cs
new file mode 100644
index 0000000..05cd85e
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Logical/IfNa.cs
@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class IfNa : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var firstArg = arguments.First();
+    return GetResultByObject(firstArg.Value);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Logical/Not.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Logical/Not.cs
new file mode 100644
index 0000000..eece7e4
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Logical/Not.cs
@@ -0,0 +1,38 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Not : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var result = !ArgToBool(arguments, 0);
+    return new(result, DataType.Boolean);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Logical/Or.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Logical/Or.cs
new file mode 100644
index 0000000..44e2694
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Logical/Or.cs
@@ -0,0 +1,43 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Or : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    for (var x = 0; x < arguments.Count(); x++) {
+      if (ArgToBool(arguments, x)) {
+        return new(true, DataType.Boolean);
+      }
+    }
+    return new(false, DataType.Boolean);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Logical/True.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Logical/True.cs
new file mode 100644
index 0000000..7888cfe
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Logical/True.cs
@@ -0,0 +1,36 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class True : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    return CreateResult(true, DataType.Boolean);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Abs.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Abs.cs
new file mode 100644
index 0000000..cc17860
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Abs.cs
@@ -0,0 +1,41 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Abs : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var val = ArgToDecimal(arguments, 0);
+    if (val < 0) {
+      val *= -1;
+    }
+    return CreateResult(val, DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Acos.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Acos.cs
new file mode 100644
index 0000000..2cf2499
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Acos.cs
@@ -0,0 +1,38 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-01-11
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Acos : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var arg = ArgToDecimal(arguments, 0);
+    return CreateResult(MathHelper.Arccos(arg), DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Acosh.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Acosh.cs
new file mode 100644
index 0000000..ee728e0
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Acosh.cs
@@ -0,0 +1,38 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-01-11
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Acosh : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var arg = ArgToDecimal(arguments, 0);
+    return CreateResult(MathHelper.HArccos(arg), DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Asin.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Asin.cs
new file mode 100644
index 0000000..25dcd74
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Asin.cs
@@ -0,0 +1,38 @@
+using System.Collections.Generic;
+
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-01-11
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public class Asin : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var arg = ArgToDecimal(arguments, 0);
+    return CreateResult(System.Math.Asin(arg), DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Asinh.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Asinh.cs
new file mode 100644
index 0000000..685cb82
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Asinh.cs
@@ -0,0 +1,38 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-01-11
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Asinh : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var arg = ArgToDecimal(arguments, 0);
+    return CreateResult(MathHelper.HArcsin(arg), DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Atan.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Atan.cs
new file mode 100644
index 0000000..d7300fd
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Atan.cs
@@ -0,0 +1,38 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Atan : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var arg = ArgToDecimal(arguments, 0);
+    return CreateResult(System.Math.Atan(arg), DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Atan2.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Atan2.cs
new file mode 100644
index 0000000..a0ff906
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Atan2.cs
@@ -0,0 +1,40 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Atan2 : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var arg1 = ArgToDecimal(arguments, 0);
+    var arg2 = ArgToDecimal(arguments, 1);
+    // Had to switch order of the arguments to get the same result as in excel /MA
+    return CreateResult(System.Math.Atan2(arg2, arg1), DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Atanh.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Atanh.cs
new file mode 100644
index 0000000..256125a
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Atanh.cs
@@ -0,0 +1,38 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-01-11
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Atanh : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var arg = ArgToDecimal(arguments, 0);
+    return CreateResult(MathHelper.HArctan(arg), DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Average.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Average.cs
new file mode 100644
index 0000000..9ec1ec3
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Average.cs
@@ -0,0 +1,95 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Globalization;
+
+namespace AppsheetEpplus;
+
+public class Average : HiddenValuesHandlingFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1, eErrorType.Div0);
+    double nValues = 0d,
+        result = 0d;
+    foreach (var arg in arguments) {
+      Calculate(arg, context, ref result, ref nValues);
+    }
+    return CreateResult(Divide(result, nValues), DataType.Decimal);
+  }
+
+  private void Calculate(
+      FunctionArgument arg,
+      ParsingContext context,
+      ref double retVal,
+      ref double nValues,
+      bool isInArray = false) {
+    if (ShouldIgnore(arg)) {
+      return;
+    }
+    if (arg.Value is IEnumerable<FunctionArgument> value) {
+      foreach (var item in value) {
+        Calculate(item, context, ref retVal, ref nValues, true);
+      }
+    } else if (arg.IsExcelRange) {
+      foreach (var c in arg.ValueAsRangeInfo) {
+        if (ShouldIgnore(c, context)) {
+          continue;
+        }
+        CheckForAndHandleExcelError(c);
+        if (!IsNumeric(c.Value)) {
+          continue;
+        }
+        nValues++;
+        retVal += c.ValueDouble;
+      }
+    } else {
+      var numericValue = GetNumericValue(arg.Value, isInArray);
+      if (numericValue.HasValue) {
+        nValues++;
+        retVal += numericValue.Value;
+      } else if ((arg.Value is string) && !ConvertUtil.IsNumericString(arg.Value)) {
+        if (!isInArray) {
+          ThrowExcelErrorValueException(eErrorType.Value);
+        }
+      }
+    }
+    CheckForAndHandleExcelError(arg);
+  }
+
+  private double? GetNumericValue(object obj, bool isInArray) {
+    if (IsNumeric(obj)) {
+      return ConvertUtil.GetValueDouble(obj);
+    }
+    if ((obj is bool) && !isInArray) {
+      return ConvertUtil.GetValueDouble(obj);
+    }
+    if (ConvertUtil.IsNumericString(obj)) {
+      return double.Parse(obj.ToString(), CultureInfo.InvariantCulture);
+    }
+    return default(double?);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/AverageA.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/AverageA.cs
new file mode 100644
index 0000000..567a8ef
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/AverageA.cs
@@ -0,0 +1,104 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2014-01-06
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Globalization;
+
+namespace AppsheetEpplus;
+
+public class AverageA : HiddenValuesHandlingFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1, eErrorType.Div0);
+    double nValues = 0d,
+        result = 0d;
+    foreach (var arg in arguments) {
+      Calculate(arg, context, ref result, ref nValues);
+    }
+    return CreateResult(Divide(result, nValues), DataType.Decimal);
+  }
+
+  private void Calculate(
+      FunctionArgument arg,
+      ParsingContext context,
+      ref double retVal,
+      ref double nValues,
+      bool isInArray = false) {
+    if (ShouldIgnore(arg)) {
+      return;
+    }
+    if (arg.Value is IEnumerable<FunctionArgument> value) {
+      foreach (var item in value) {
+        Calculate(item, context, ref retVal, ref nValues, true);
+      }
+    } else if (arg.IsExcelRange) {
+      foreach (var c in arg.ValueAsRangeInfo) {
+        if (ShouldIgnore(c, context)) {
+          continue;
+        }
+        CheckForAndHandleExcelError(c);
+        if (IsNumeric(c.Value)) {
+          nValues++;
+          retVal += c.ValueDouble;
+        } else if (c.Value is bool cValue) {
+          nValues++;
+          retVal += cValue ? 1 : 0;
+        } else if (c.Value is string) {
+          nValues++;
+        }
+      }
+    } else {
+      var numericValue = GetNumericValue(arg.Value, isInArray);
+      if (numericValue.HasValue) {
+        nValues++;
+        retVal += numericValue.Value;
+      } else if ((arg.Value is string) && !ConvertUtil.IsNumericString(arg.Value)) {
+        if (isInArray) {
+          nValues++;
+        } else {
+          ThrowExcelErrorValueException(eErrorType.Value);
+        }
+      }
+    }
+    CheckForAndHandleExcelError(arg);
+  }
+
+  private double? GetNumericValue(object obj, bool isInArray) {
+    if (IsNumeric(obj)) {
+      return ConvertUtil.GetValueDouble(obj);
+    }
+    if (obj is bool) {
+      if (isInArray) {
+        return default(double?);
+      }
+      return ConvertUtil.GetValueDouble(obj);
+    }
+    if (ConvertUtil.IsNumericString(obj)) {
+      return double.Parse(obj.ToString(), CultureInfo.InvariantCulture);
+    }
+    return default(double?);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/AverageIf.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/AverageIf.cs
new file mode 100644
index 0000000..92c698d
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/AverageIf.cs
@@ -0,0 +1,123 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class AverageIf : HiddenValuesHandlingFunction {
+  private readonly NumericExpressionEvaluator _numericExpressionEvaluator;
+  private readonly WildCardValueMatcher _wildCardValueMatcher;
+
+  public AverageIf()
+      : this(new(), new()) {}
+
+  public AverageIf(
+      NumericExpressionEvaluator evaluator,
+      WildCardValueMatcher wildCardValueMatcher) {
+    Require.That(evaluator).Named("evaluator").IsNotNull();
+    Require.That(evaluator).Named("wildCardValueMatcher").IsNotNull();
+    _numericExpressionEvaluator = evaluator;
+    _wildCardValueMatcher = wildCardValueMatcher;
+  }
+
+  private bool Evaluate(object obj, string expression) {
+    double? candidate = default(double?);
+    if (IsNumeric(obj)) {
+      candidate = ConvertUtil.GetValueDouble(obj);
+    }
+    if (candidate.HasValue) {
+      return _numericExpressionEvaluator.Evaluate(candidate.Value, expression);
+    }
+    if (obj == null) {
+      return false;
+    }
+    return _wildCardValueMatcher.IsMatch(expression, obj.ToString()) == 0;
+  }
+
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var firstArg = arguments.ElementAt(0);
+    var args = firstArg.Value as IEnumerable<FunctionArgument>;
+    if (args == null && firstArg.IsExcelRange) {
+      args = new List<FunctionArgument> { firstArg };
+    }
+    var criteria = arguments.ElementAt(1).Value;
+    ThrowExcelErrorValueExceptionIf(
+        () => criteria == null || criteria.ToString().Length > 255,
+        eErrorType.Value);
+    double retVal;
+    if (arguments.Count() > 2) {
+      var secondArg = arguments.ElementAt(2);
+      var lookupRange = secondArg.Value as IEnumerable<FunctionArgument>;
+      if (lookupRange == null && secondArg.IsExcelRange) {
+        lookupRange = new List<FunctionArgument> { secondArg };
+      }
+      retVal = CalculateWithLookupRange(args, criteria.ToString(), lookupRange, context);
+    } else {
+      retVal = CalculateSingleRange(args, criteria.ToString(), context);
+    }
+    return CreateResult(retVal, DataType.Decimal);
+  }
+
+  private double CalculateWithLookupRange(
+      IEnumerable<FunctionArgument> range,
+      string criteria,
+      IEnumerable<FunctionArgument> sumRange,
+      ParsingContext context) {
+    var retVal = 0d;
+    var nMatches = 0;
+    var flattenedRange = ArgsToObjectEnumerable(false, range, context);
+    var flattenedSumRange = ArgsToDoubleEnumerable(sumRange, context);
+    for (var x = 0; x < flattenedRange.Count(); x++) {
+      var candidate = flattenedSumRange.ElementAt(x);
+      if (Evaluate(flattenedRange.ElementAt(x), criteria)) {
+        nMatches++;
+        retVal += candidate;
+      }
+    }
+    return Divide(retVal, nMatches);
+  }
+
+  private double CalculateSingleRange(
+      IEnumerable<FunctionArgument> args,
+      string expression,
+      ParsingContext context) {
+    var retVal = 0d;
+    var nMatches = 0;
+    var flattendedRange = ArgsToDoubleEnumerable(args, context);
+    var candidates = flattendedRange as double[] ?? flattendedRange.ToArray();
+    foreach (var candidate in candidates) {
+      if (Evaluate(candidate, expression)) {
+        retVal += candidate;
+        nMatches++;
+      }
+    }
+    return Divide(retVal, nMatches);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/AverageIfs.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/AverageIfs.cs
new file mode 100644
index 0000000..af7e25f
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/AverageIfs.cs
@@ -0,0 +1,68 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-02-01
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class AverageIfs : MultipleRangeCriteriasFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray();
+    ValidateArguments(functionArguments, 3);
+    var sumRange = ArgsToDoubleEnumerable(
+            true,
+            new List<FunctionArgument> { functionArguments[0] },
+            context)
+        .ToList();
+    var argRanges = new List<ExcelDataProvider.IRangeInfo>();
+    var criterias = new List<object>();
+    for (var ix = 1; ix < 31; ix += 2) {
+      if (functionArguments.Length <= ix) {
+        break;
+      }
+      var rangeInfo = functionArguments[ix].ValueAsRangeInfo;
+      argRanges.Add(rangeInfo);
+      if (ix > 1) {
+        ThrowExcelErrorValueExceptionIf(
+            () => rangeInfo.GetNCells() != argRanges[0].GetNCells(),
+            eErrorType.Value);
+      }
+      criterias.Add(functionArguments[ix + 1].Value);
+    }
+    IEnumerable<int> matchIndexes = GetMatchIndexes(argRanges[0], criterias[0]);
+    var enumerable = matchIndexes as IList<int> ?? matchIndexes.ToList();
+    for (var ix = 1; ix < argRanges.Count && enumerable.Any(); ix++) {
+      var indexes = GetMatchIndexes(argRanges[ix], criterias[ix]);
+      matchIndexes = enumerable.Intersect(indexes);
+    }
+
+    var result = matchIndexes.Average(index => sumRange[index]);
+
+    return CreateResult(result, DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Ceiling.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Ceiling.cs
new file mode 100644
index 0000000..6a2e4b2
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Ceiling.cs
@@ -0,0 +1,59 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Ceiling : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var number = ArgToDecimal(arguments, 0);
+    var significance = ArgToDecimal(arguments, 1);
+    ValidateNumberAndSign(number, significance);
+    if (significance < 1 && significance > 0) {
+      var floor = System.Math.Floor(number);
+      var rest = number - floor;
+      var nSign = (int)(rest / significance) + 1;
+      return CreateResult(floor + (nSign * significance), DataType.Decimal);
+    }
+    if (significance == 1) {
+      return CreateResult(System.Math.Ceiling(number), DataType.Decimal);
+    }
+    var result = number - (number % significance) + significance;
+    return CreateResult(result, DataType.Decimal);
+  }
+
+  private void ValidateNumberAndSign(double number, double sign) {
+    if (number > 0d && sign < 0) {
+      var values = string.Format("num: {0}, sign: {1}", number, sign);
+      throw new InvalidOperationException(
+          "Ceiling cannot handle a negative significance when the number is positive" + values);
+    }
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Cos.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Cos.cs
new file mode 100644
index 0000000..d936044
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Cos.cs
@@ -0,0 +1,38 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Cos : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var arg = ArgToDecimal(arguments, 0);
+    return CreateResult(System.Math.Cos(arg), DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Cosh.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Cosh.cs
new file mode 100644
index 0000000..b4271fc
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Cosh.cs
@@ -0,0 +1,38 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Cosh : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var arg = ArgToDecimal(arguments, 0);
+    return CreateResult(System.Math.Cosh(arg), DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Count.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Count.cs
new file mode 100644
index 0000000..cf9d0ae
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Count.cs
@@ -0,0 +1,103 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Count : HiddenValuesHandlingFunction {
+  private enum ItemContext {
+    InRange,
+    InArray,
+    SingleArg,
+  }
+
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var nItems = 0d;
+    Calculate(arguments, ref nItems, context, ItemContext.SingleArg);
+    return CreateResult(nItems, DataType.Integer);
+  }
+
+  private void Calculate(
+      IEnumerable<FunctionArgument> items,
+      ref double nItems,
+      ParsingContext context,
+      ItemContext itemContext) {
+    foreach (var item in items) {
+      var cs = item.Value as ExcelDataProvider.IRangeInfo;
+      if (cs != null) {
+        foreach (var c in cs) {
+          _CheckForAndHandleExcelError(c, context);
+          if (ShouldIgnore(c, context) == false && ShouldCount(c.Value, ItemContext.InRange)) {
+            nItems++;
+          }
+        }
+      } else {
+        var value = item.Value as IEnumerable<FunctionArgument>;
+        if (value != null) {
+          Calculate(value, ref nItems, context, ItemContext.InArray);
+        } else {
+          _CheckForAndHandleExcelError(item, context);
+          if (ShouldIgnore(item) == false && ShouldCount(item.Value, itemContext)) {
+            nItems++;
+          }
+        }
+      }
+    }
+  }
+
+  private void _CheckForAndHandleExcelError(FunctionArgument arg, ParsingContext context) {
+    //if (context.Scopes.Current.IsSubtotal)
+    //{
+    //    CheckForAndHandleExcelError(arg);
+    //}
+  }
+
+  private void _CheckForAndHandleExcelError(
+      ExcelDataProvider.ICellInfo cell,
+      ParsingContext context) {
+    //if (context.Scopes.Current.IsSubtotal)
+    //{
+    //    CheckForAndHandleExcelError(cell);
+    //}
+  }
+
+  private bool ShouldCount(object value, ItemContext context) {
+    switch (context) {
+      case ItemContext.SingleArg:
+        return IsNumeric(value) || IsNumericString(value);
+      case ItemContext.InRange:
+        return IsNumeric(value);
+      case ItemContext.InArray:
+        return IsNumeric(value) || IsNumericString(value);
+      default:
+        throw new ArgumentException("Unknown ItemContext:" + context);
+    }
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/CountA.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/CountA.cs
new file mode 100644
index 0000000..3055aa0
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/CountA.cs
@@ -0,0 +1,84 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class CountA : HiddenValuesHandlingFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var nItems = 0d;
+    Calculate(arguments, context, ref nItems);
+    return CreateResult(nItems, DataType.Integer);
+  }
+
+  private void Calculate(
+      IEnumerable<FunctionArgument> items,
+      ParsingContext context,
+      ref double nItems) {
+    foreach (var item in items) {
+      var cs = item.Value as ExcelDataProvider.IRangeInfo;
+      if (cs != null) {
+        foreach (var c in cs) {
+          _CheckForAndHandleExcelError(c, context);
+          if (!ShouldIgnore(c, context) && ShouldCount(c.Value)) {
+            nItems++;
+          }
+        }
+      } else if (item.Value is IEnumerable<FunctionArgument> value) {
+        Calculate(value, context, ref nItems);
+      } else {
+        _CheckForAndHandleExcelError(item, context);
+        if (!ShouldIgnore(item) && ShouldCount(item.Value)) {
+          nItems++;
+        }
+      }
+    }
+  }
+
+  private void _CheckForAndHandleExcelError(FunctionArgument arg, ParsingContext context) {
+    if (context.Scopes.Current.IsSubtotal) {
+      CheckForAndHandleExcelError(arg);
+    }
+  }
+
+  private void _CheckForAndHandleExcelError(
+      ExcelDataProvider.ICellInfo cell,
+      ParsingContext context) {
+    if (context.Scopes.Current.IsSubtotal) {
+      CheckForAndHandleExcelError(cell);
+    }
+  }
+
+  private bool ShouldCount(object value) {
+    if (value == null) {
+      return false;
+    }
+    return (!string.IsNullOrEmpty(value.ToString()));
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/CountBlank.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/CountBlank.cs
new file mode 100644
index 0000000..bb851bb
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/CountBlank.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class CountBlank : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var arg = arguments.First();
+    if (!arg.IsExcelRange) {
+      throw new InvalidOperationException("CountBlank only support ranges as arguments");
+    }
+    var result = arg.ValueAsRangeInfo.GetNCells();
+    foreach (var cell in arg.ValueAsRangeInfo) {
+      if (cell.Value is not (null or string { Length: 0 })) {
+        result--;
+      }
+    }
+    return CreateResult(result, DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/CountIf.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/CountIf.cs
new file mode 100644
index 0000000..f38c224
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/CountIf.cs
@@ -0,0 +1,61 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class CountIf : ExcelFunction {
+  private readonly NumericExpressionEvaluator _numericExpressionEvaluator;
+  private readonly WildCardValueMatcher _wildCardValueMatcher;
+
+  public CountIf()
+      : this(new(), new()) {}
+
+  public CountIf(NumericExpressionEvaluator evaluator, WildCardValueMatcher wildCardValueMatcher) {
+    Require.That(evaluator).Named("evaluator").IsNotNull();
+    Require.That(wildCardValueMatcher).Named("wildCardValueMatcher").IsNotNull();
+    _numericExpressionEvaluator = evaluator;
+    _wildCardValueMatcher = wildCardValueMatcher;
+  }
+
+  private bool Evaluate(object obj, string expression) {
+    double? candidate = default(double?);
+    if (IsNumeric(obj)) {
+      candidate = ConvertUtil.GetValueDouble(obj);
+    }
+    if (candidate.HasValue) {
+      return _numericExpressionEvaluator.Evaluate(candidate.Value, expression);
+    }
+    if (obj == null) {
+      return false;
+    }
+    return _wildCardValueMatcher.IsMatch(expression, obj.ToString()) == 0;
+  }
+
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray();
+    ValidateArguments(functionArguments, 2);
+    var range = functionArguments.ElementAt(0);
+    var criteria = ArgToString(functionArguments, 1);
+    double result = 0d;
+    if (range.IsExcelRange) {
+      foreach (var cell in range.ValueAsRangeInfo) {
+        if (Evaluate(cell.Value, criteria)) {
+          result++;
+        }
+      }
+    } else if (range.Value is IEnumerable<FunctionArgument> value) {
+      foreach (var arg in value) {
+        if (Evaluate(arg.Value, criteria)) {
+          result++;
+        }
+      }
+    } else {
+      if (Evaluate(range.Value, criteria)) {
+        result++;
+      }
+    }
+    return CreateResult(result, DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/CountIfs.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/CountIfs.cs
new file mode 100644
index 0000000..9159e24
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/CountIfs.cs
@@ -0,0 +1,61 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-01-11
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class CountIfs : MultipleRangeCriteriasFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray();
+    ValidateArguments(functionArguments, 2);
+    var argRanges = new List<ExcelDataProvider.IRangeInfo>();
+    var criterias = new List<object>();
+    for (var ix = 0; ix < 30; ix += 2) {
+      if (functionArguments.Length <= ix) {
+        break;
+      }
+      var rangeInfo = functionArguments[ix].ValueAsRangeInfo;
+      argRanges.Add(rangeInfo);
+      if (ix > 0) {
+        ThrowExcelErrorValueExceptionIf(
+            () => rangeInfo.GetNCells() != argRanges[0].GetNCells(),
+            eErrorType.Value);
+      }
+      criterias.Add(functionArguments[ix + 1].Value);
+    }
+    IEnumerable<int> matchIndexes = GetMatchIndexes(argRanges[0], criterias[0]);
+    var enumerable = matchIndexes as IList<int> ?? matchIndexes.ToList();
+    for (var ix = 1; ix < argRanges.Count && enumerable.Any(); ix++) {
+      var indexes = GetMatchIndexes(argRanges[ix], criterias[ix]);
+      matchIndexes = enumerable.Intersect(indexes);
+    }
+
+    return CreateResult((double)matchIndexes.Count(), DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Degrees.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Degrees.cs
new file mode 100644
index 0000000..e06ea6a
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Degrees.cs
@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Degrees : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var angle = ArgToDecimal(arguments, 0);
+    var result = (angle * 180) / System.Math.PI;
+    return CreateResult(result, DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Exp.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Exp.cs
new file mode 100644
index 0000000..b76f489
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Exp.cs
@@ -0,0 +1,38 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Exp : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var number = ArgToDecimal(arguments, 0);
+    return CreateResult(System.Math.Exp(number), DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Fact.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Fact.cs
new file mode 100644
index 0000000..53372f0
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Fact.cs
@@ -0,0 +1,18 @@
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Fact : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var number = ArgToDecimal(arguments, 0);
+    ThrowExcelErrorValueExceptionIf(() => number < 0, eErrorType.Na);
+    var result = 1d;
+    for (var x = 1; x < number; x++) {
+      result *= x;
+    }
+    return CreateResult(result, DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Floor.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Floor.cs
new file mode 100644
index 0000000..ff3bca7
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Floor.cs
@@ -0,0 +1,64 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Floor : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var number = ArgToDecimal(arguments, 0);
+    var significance = ArgToDecimal(arguments, 1);
+    ValidateNumberAndSign(number, significance);
+    if (significance < 1 && significance > 0) {
+      var floor = System.Math.Floor(number);
+      var rest = number - floor;
+      var nSign = (int)(rest / significance);
+      return CreateResult(floor + (nSign * significance), DataType.Decimal);
+    }
+    if (significance == 1) {
+      return CreateResult(System.Math.Floor(number), DataType.Decimal);
+    }
+    double result;
+    if (number > 1) {
+      result = number - (number % significance) + significance;
+    } else {
+      result = number - (number % significance);
+    }
+    return CreateResult(result, DataType.Decimal);
+  }
+
+  private void ValidateNumberAndSign(double number, double sign) {
+    if (number > 0d && sign < 0) {
+      var values = string.Format("num: {0}, sign: {1}", number, sign);
+      throw new InvalidOperationException(
+          "Floor cannot handle a negative significance when the number is positive" + values);
+    }
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Large.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Large.cs
new file mode 100644
index 0000000..dd5786b
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Large.cs
@@ -0,0 +1,18 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Large : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var args = arguments.ElementAt(0);
+    var index = ArgToInt(arguments, 1) - 1;
+    var values = ArgsToDoubleEnumerable(new List<FunctionArgument> { args }, context);
+    ThrowExcelErrorValueExceptionIf(() => index < 0 || index >= values.Count(), eErrorType.Num);
+    var result = values.OrderByDescending(x => x).ElementAt(index);
+    return CreateResult(result, DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Ln.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Ln.cs
new file mode 100644
index 0000000..f0705a0
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Ln.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Ln : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var arg = ArgToDecimal(arguments, 0);
+    return CreateResult(System.Math.Log(arg, System.Math.E), DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Log.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Log.cs
new file mode 100644
index 0000000..203d773
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Log.cs
@@ -0,0 +1,43 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Log : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var number = ArgToDecimal(arguments, 0);
+    if (arguments.Count() == 1) {
+      return CreateResult(System.Math.Log(number, 10d), DataType.Decimal);
+    }
+    var newBase = ArgToDecimal(arguments, 1);
+    return CreateResult(System.Math.Log(number, newBase), DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Log10.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Log10.cs
new file mode 100644
index 0000000..0333f09
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Log10.cs
@@ -0,0 +1,38 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Log10 : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var number = ArgToDecimal(arguments, 0);
+    return CreateResult(System.Math.Log10(number), DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/MathHelper.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/MathHelper.cs
new file mode 100644
index 0000000..2d6f69f
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/MathHelper.cs
@@ -0,0 +1,138 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-01-11
+ *******************************************************************************/
+
+using MathObj = System.Math;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Thanks to the guys in this thread: http://stackoverflow.com/questions/2840798/c-sharp-math-class-question
+/// </summary>
+public static class MathHelper {
+  // Secant
+  public static double Sec(double x) {
+    return 1 / MathObj.Cos(x);
+  }
+
+  // Cosecant
+  public static double Cosec(double x) {
+    return 1 / MathObj.Sin(x);
+  }
+
+  // Cotangent
+  public static double Cotan(double x) {
+    return 1 / MathObj.Tan(x);
+  }
+
+  // Inverse Sine
+  public static double Arcsin(double x) {
+    return MathObj.Atan(x / MathObj.Sqrt(-x * x + 1));
+  }
+
+  // Inverse Cosine
+  public static double Arccos(double x) {
+    return MathObj.Atan(-x / MathObj.Sqrt(-x * x + 1)) + 2 * MathObj.Atan(1);
+  }
+
+  // Inverse Secant
+  public static double Arcsec(double x) {
+    return 2 * MathObj.Atan(1) - MathObj.Atan(MathObj.Sign(x) / MathObj.Sqrt(x * x - 1));
+  }
+
+  // Inverse Cosecant
+  public static double Arccosec(double x) {
+    return MathObj.Atan(MathObj.Sign(x) / MathObj.Sqrt(x * x - 1));
+  }
+
+  // Inverse Cotangent
+  public static double Arccotan(double x) {
+    return 2 * MathObj.Atan(1) - MathObj.Atan(x);
+  }
+
+  // Hyperbolic Sine
+  public static double HSin(double x) {
+    return (MathObj.Exp(x) - MathObj.Exp(-x)) / 2;
+  }
+
+  // Hyperbolic Cosine
+  public static double HCos(double x) {
+    return (MathObj.Exp(x) + MathObj.Exp(-x)) / 2;
+  }
+
+  // Hyperbolic Tangent
+  public static double HTan(double x) {
+    return (MathObj.Exp(x) - MathObj.Exp(-x)) / (MathObj.Exp(x) + MathObj.Exp(-x));
+  }
+
+  // Hyperbolic Secant
+  public static double HSec(double x) {
+    return 2 / (MathObj.Exp(x) + MathObj.Exp(-x));
+  }
+
+  // Hyperbolic Cosecant
+  public static double HCosec(double x) {
+    return 2 / (MathObj.Exp(x) - MathObj.Exp(-x));
+  }
+
+  // Hyperbolic Cotangent
+  public static double HCotan(double x) {
+    return (MathObj.Exp(x) + MathObj.Exp(-x)) / (MathObj.Exp(x) - MathObj.Exp(-x));
+  }
+
+  // Inverse Hyperbolic Sine
+  public static double HArcsin(double x) {
+    return MathObj.Log(x + MathObj.Sqrt(x * x + 1));
+  }
+
+  // Inverse Hyperbolic Cosine
+  public static double HArccos(double x) {
+    return MathObj.Log(x + MathObj.Sqrt(x * x - 1));
+  }
+
+  // Inverse Hyperbolic Tangent
+  public static double HArctan(double x) {
+    return MathObj.Log((1 + x) / (1 - x)) / 2;
+  }
+
+  // Inverse Hyperbolic Secant
+  public static double HArcsec(double x) {
+    return MathObj.Log((MathObj.Sqrt(-x * x + 1) + 1) / x);
+  }
+
+  // Inverse Hyperbolic Cosecant
+  public static double HArccosec(double x) {
+    return MathObj.Log((MathObj.Sign(x) * MathObj.Sqrt(x * x + 1) + 1) / x);
+  }
+
+  // Inverse Hyperbolic Cotangent
+  public static double HArccotan(double x) {
+    return MathObj.Log((x + 1) / (x - 1)) / 2;
+  }
+
+  // Logarithm to base N
+  public static double LogN(double x, double n) {
+    return MathObj.Log(x) / MathObj.Log(n);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Max.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Max.cs
new file mode 100644
index 0000000..cf490ac
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Max.cs
@@ -0,0 +1,39 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Max : HiddenValuesHandlingFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var values = ArgsToDoubleEnumerable(IgnoreHiddenValues, false, arguments, context);
+    return CreateResult(values.Max(), DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Maxa.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Maxa.cs
new file mode 100644
index 0000000..a65e13a
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Maxa.cs
@@ -0,0 +1,49 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Maxa : ExcelFunction {
+  private readonly DoubleEnumerableArgConverter _argConverter;
+
+  public Maxa()
+      : this(new()) {}
+
+  public Maxa(DoubleEnumerableArgConverter argConverter) {
+    Require.That(argConverter).Named("argConverter").IsNotNull();
+    _argConverter = argConverter;
+  }
+
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var values = _argConverter.ConvertArgsIncludingOtherTypes(arguments);
+    return CreateResult(values.Max(), DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Median.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Median.cs
new file mode 100644
index 0000000..dc39636
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Median.cs
@@ -0,0 +1,49 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-01-10
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Median : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    var nums = ArgsToDoubleEnumerable(arguments, context);
+    var arr = nums.ToArray();
+    Array.Sort(arr);
+    ThrowExcelErrorValueExceptionIf(() => arr.Length == 0, eErrorType.Num);
+    double result;
+    if (arr.Length % 2 == 1) {
+      result = arr[arr.Length / 2];
+    } else {
+      var startIndex = arr.Length / 2 - 1;
+      result = (arr[startIndex] + arr[startIndex + 1]) / 2d;
+    }
+    return CreateResult(result, DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Min.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Min.cs
new file mode 100644
index 0000000..850ceeb
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Min.cs
@@ -0,0 +1,39 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Min : HiddenValuesHandlingFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var values = ArgsToDoubleEnumerable(IgnoreHiddenValues, false, arguments, context);
+    return CreateResult(values.Min(), DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Mina.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Mina.cs
new file mode 100644
index 0000000..3321d65
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Mina.cs
@@ -0,0 +1,49 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Mina : ExcelFunction {
+  private readonly DoubleEnumerableArgConverter _argConverter;
+
+  public Mina()
+      : this(new()) {}
+
+  public Mina(DoubleEnumerableArgConverter argConverter) {
+    Require.That(argConverter).Named("argConverter").IsNotNull();
+    _argConverter = argConverter;
+  }
+
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var values = _argConverter.ConvertArgsIncludingOtherTypes(arguments);
+    return CreateResult(values.Min(), DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Mod.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Mod.cs
new file mode 100644
index 0000000..ff0c907
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Mod.cs
@@ -0,0 +1,39 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Mod : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var n1 = ArgToDecimal(arguments, 0);
+    var n2 = ArgToDecimal(arguments, 1);
+    return new(n1 % n2, DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/MultipleRangeCriteriasFunction.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/MultipleRangeCriteriasFunction.cs
new file mode 100644
index 0000000..dead9a8
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/MultipleRangeCriteriasFunction.cs
@@ -0,0 +1,74 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-01-15
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public abstract class MultipleRangeCriteriasFunction : ExcelFunction {
+  private readonly NumericExpressionEvaluator _numericExpressionEvaluator;
+  private readonly WildCardValueMatcher _wildCardValueMatcher;
+
+  protected MultipleRangeCriteriasFunction()
+      : this(new(), new()) {}
+
+  protected MultipleRangeCriteriasFunction(
+      NumericExpressionEvaluator evaluator,
+      WildCardValueMatcher wildCardValueMatcher) {
+    Require.That(evaluator).Named("evaluator").IsNotNull();
+    Require.That(wildCardValueMatcher).Named("wildCardValueMatcher").IsNotNull();
+    _numericExpressionEvaluator = evaluator;
+    _wildCardValueMatcher = wildCardValueMatcher;
+  }
+
+  protected bool Evaluate(object obj, object expression) {
+    double? candidate = default(double?);
+    if (IsNumeric(obj)) {
+      candidate = ConvertUtil.GetValueDouble(obj);
+    }
+    if (candidate.HasValue && expression is string) {
+      return _numericExpressionEvaluator.Evaluate(candidate.Value, expression.ToString());
+    }
+    if (obj == null) {
+      return false;
+    }
+    return _wildCardValueMatcher.IsMatch(expression, obj.ToString()) == 0;
+  }
+
+  protected List<int> GetMatchIndexes(ExcelDataProvider.IRangeInfo rangeInfo, object searched) {
+    var result = new List<int>();
+    var internalIndex = 0;
+    for (var row = rangeInfo.Address._fromRow; row <= rangeInfo.Address._toRow; row++) {
+      for (var col = rangeInfo.Address._fromCol; col <= rangeInfo.Address._toCol; col++) {
+        var candidate = rangeInfo.GetValue(row, col);
+        if (Evaluate(candidate, searched)) {
+          result.Add(internalIndex);
+        }
+        internalIndex++;
+      }
+    }
+    return result;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Pi.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Pi.cs
new file mode 100644
index 0000000..476824e
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Pi.cs
@@ -0,0 +1,37 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Pi : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    var result = System.Math.Round(System.Math.PI, 14);
+    return CreateResult(result, DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Power.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Power.cs
new file mode 100644
index 0000000..78b8887
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Power.cs
@@ -0,0 +1,40 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Power : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var number = ArgToDecimal(arguments, 0);
+    var power = ArgToDecimal(arguments, 1);
+    var result = System.Math.Pow(number, power);
+    return CreateResult(result, DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Product.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Product.cs
new file mode 100644
index 0000000..64e1821
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Product.cs
@@ -0,0 +1,88 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Product : HiddenValuesHandlingFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var result = 0d;
+    var index = 0;
+    while (AreEqual(result, 0d) && index < arguments.Count()) {
+      result = CalculateFirstItem(arguments, index++, context);
+    }
+    result = CalculateCollection(
+        arguments.Skip(index),
+        result,
+        (arg, current) => {
+          if (ShouldIgnore(arg)) {
+            return current;
+          }
+          if (arg.ValueIsExcelError) {
+            ThrowExcelErrorValueException(arg.ValueAsExcelErrorValue.Type);
+          }
+          if (arg.IsExcelRange) {
+            foreach (var cell in arg.ValueAsRangeInfo) {
+              if (ShouldIgnore(cell, context)) {
+                return current;
+              }
+              current *= cell.ValueDouble;
+            }
+            return current;
+          }
+          var obj = arg.Value;
+          if (obj != null && IsNumeric(obj)) {
+            var val = Convert.ToDouble(obj);
+            current *= val;
+          }
+          return current;
+        });
+    return CreateResult(result, DataType.Decimal);
+  }
+
+  private double CalculateFirstItem(
+      IEnumerable<FunctionArgument> arguments,
+      int index,
+      ParsingContext context) {
+    var element = arguments.ElementAt(index);
+    var argList = new List<FunctionArgument> { element };
+    var valueList = ArgsToDoubleEnumerable(false, false, argList, context);
+    var result = 0d;
+    foreach (var value in valueList) {
+      if (result == 0d && value > 0d) {
+        result = value;
+      } else {
+        result *= value;
+      }
+    }
+    return result;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Quotient.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Quotient.cs
new file mode 100644
index 0000000..052856f
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Quotient.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Quotient : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var num = ArgToDecimal(arguments, 0);
+    var denom = ArgToDecimal(arguments, 1);
+    ThrowExcelErrorValueExceptionIf(() => (int)denom == 0, eErrorType.Div0);
+    var result = (int)(num / denom);
+    return CreateResult(result, DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Rand.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Rand.cs
new file mode 100644
index 0000000..2687e7c
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Rand.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Rand : ExcelFunction {
+  private static int Seed { get; set; }
+
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    Seed = Seed > 50 ? 0 : Seed + 5;
+    var val = new Random(System.DateTime.Now.Millisecond + Seed).NextDouble();
+    return CreateResult(val, DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/RandBetween.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/RandBetween.cs
new file mode 100644
index 0000000..8821710
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/RandBetween.cs
@@ -0,0 +1,52 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class RandBetween : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var low = ArgToDecimal(arguments, 0);
+    var high = ArgToDecimal(arguments, 1);
+    var rand = new Rand().Execute(new FunctionArgument[0], context).Result;
+    var randPart = (CalulateDiff(high, low) * (double)rand) + 1;
+    randPart = System.Math.Floor(randPart);
+    return CreateResult(low + randPart, DataType.Integer);
+  }
+
+  private double CalulateDiff(double high, double low) {
+    if (high > 0 && low < 0) {
+      return high + low * -1;
+    }
+    if (high < 0 && low < 0) {
+      return high * -1 - low * -1;
+    }
+    return high - low;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Round.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Round.cs
new file mode 100644
index 0000000..0a95cc7
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Round.cs
@@ -0,0 +1,43 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Round : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var number = ArgToDecimal(arguments, 0);
+    var nDigits = ArgToInt(arguments, 1);
+    if (nDigits < 0) {
+      nDigits *= -1;
+      return CreateResult(number - (number % (System.Math.Pow(10, nDigits))), DataType.Integer);
+    }
+    return CreateResult(System.Math.Round(number, nDigits), DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Rounddown.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Rounddown.cs
new file mode 100644
index 0000000..6d1c3ab
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Rounddown.cs
@@ -0,0 +1,59 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2014-01-06
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Rounddown : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var number = ArgToDecimal(arguments, 0);
+    var nDecimals = ArgToInt(arguments, 1);
+
+    var nFactor = number < 0 ? -1 : 1;
+    number *= nFactor;
+
+    double result;
+    if (nDecimals > 0) {
+      result = RoundDownDecimalNumber(number, nDecimals);
+    } else {
+      result = (int)System.Math.Floor(number);
+      result = result - (result % System.Math.Pow(10, (nDecimals * -1)));
+    }
+    return CreateResult(result * nFactor, DataType.Decimal);
+  }
+
+  private static double RoundDownDecimalNumber(double number, int nDecimals) {
+    var integerPart = System.Math.Floor(number);
+    var decimalPart = number - integerPart;
+    decimalPart = System.Math.Pow(10d, nDecimals) * decimalPart;
+    decimalPart = System.Math.Truncate(decimalPart) / System.Math.Pow(10d, nDecimals);
+    var result = integerPart + decimalPart;
+    return result;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Roundup.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Roundup.cs
new file mode 100644
index 0000000..c98d577
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Roundup.cs
@@ -0,0 +1,45 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2014-01-06
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Roundup : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var number = ArgToDecimal(arguments, 0);
+    var nDigits = ArgToInt(arguments, 1);
+    double result =
+        (number >= 0)
+            ? System.Math.Ceiling(number * System.Math.Pow(10, nDigits))
+                / System.Math.Pow(10, nDigits)
+            : System.Math.Floor(number * System.Math.Pow(10, nDigits))
+                / System.Math.Pow(10, nDigits);
+    return CreateResult(result, DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Sign.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Sign.cs
new file mode 100644
index 0000000..2f40664
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Sign.cs
@@ -0,0 +1,44 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Sign : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var result = 0d;
+    var val = ArgToDecimal(arguments, 0);
+    if (val < 0) {
+      result = -1;
+    } else if (val > 0) {
+      result = 1;
+    }
+    return CreateResult(result, DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Sin.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Sin.cs
new file mode 100644
index 0000000..292bdc1
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Sin.cs
@@ -0,0 +1,38 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Sin : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var arg = ArgToDecimal(arguments, 0);
+    return CreateResult(System.Math.Sin(arg), DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Sinh.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Sinh.cs
new file mode 100644
index 0000000..5b4bece
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Sinh.cs
@@ -0,0 +1,38 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Sinh : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var arg = ArgToDecimal(arguments, 0);
+    return CreateResult(System.Math.Sinh(arg), DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Small.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Small.cs
new file mode 100644
index 0000000..f39ceb4
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Small.cs
@@ -0,0 +1,18 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Small : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var args = arguments.ElementAt(0);
+    var index = ArgToInt(arguments, 1) - 1;
+    var values = ArgsToDoubleEnumerable(new List<FunctionArgument> { args }, context);
+    ThrowExcelErrorValueExceptionIf(() => index < 0 || index >= values.Count(), eErrorType.Num);
+    var result = values.OrderBy(x => x).ElementAt(index);
+    return CreateResult(result, DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Sqrt.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Sqrt.cs
new file mode 100644
index 0000000..636a12e
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Sqrt.cs
@@ -0,0 +1,39 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Sqrt : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var arg = ArgToDecimal(arguments, 0);
+    var result = System.Math.Sqrt(arg);
+    return CreateResult(result, DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/SqrtPi.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/SqrtPi.cs
new file mode 100644
index 0000000..bca7531
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/SqrtPi.cs
@@ -0,0 +1,38 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class SqrtPi : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var number = ArgToDecimal(arguments, 0);
+    return CreateResult(System.Math.Sqrt(number * System.Math.PI), DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Stdev.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Stdev.cs
new file mode 100644
index 0000000..96165c2
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Stdev.cs
@@ -0,0 +1,57 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+using MathObj = System.Math;
+
+namespace AppsheetEpplus;
+
+public class Stdev : HiddenValuesHandlingFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var values = ArgsToDoubleEnumerable(arguments, context, false);
+    return CreateResult(StandardDeviation(values), DataType.Decimal);
+  }
+
+  private double StandardDeviation(IEnumerable<double> values) {
+    double ret = 0;
+    if (values.Any()) {
+      var nValues = values.Count();
+      if (nValues == 1) {
+        throw new ExcelErrorValueException(eErrorType.Div0);
+      }
+      //Compute the Average
+      double avg = values.Average();
+      //Perform the Sum of (value-avg)_2_2
+      double sum = values.Sum(d => MathObj.Pow(d - avg, 2));
+      //Put it all together
+      ret = MathObj.Sqrt(Divide(sum, (values.Count() - 1)));
+    }
+    return ret;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/StdevP.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/StdevP.cs
new file mode 100644
index 0000000..92ec913
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/StdevP.cs
@@ -0,0 +1,44 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+using MathObj = System.Math;
+
+namespace AppsheetEpplus;
+
+public class StdevP : HiddenValuesHandlingFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    var args = ArgsToDoubleEnumerable(IgnoreHiddenValues, false, arguments, context);
+    return CreateResult(StandardDeviation(args), DataType.Decimal);
+  }
+
+  private static double StandardDeviation(IEnumerable<double> values) {
+    double avg = values.Average();
+    return MathObj.Sqrt(values.Average(v => MathObj.Pow(v - avg, 2)));
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Subtotal.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Subtotal.cs
new file mode 100644
index 0000000..eedd06a
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Subtotal.cs
@@ -0,0 +1,96 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Subtotal : ExcelFunction {
+  private readonly Dictionary<int, HiddenValuesHandlingFunction> _functions = new();
+
+  public Subtotal() {
+    Initialize();
+  }
+
+  private void Initialize() {
+    _functions[1] = new Average();
+    _functions[2] = new Count();
+    _functions[3] = new CountA();
+    _functions[4] = new Max();
+    _functions[5] = new Min();
+    _functions[6] = new Product();
+    _functions[7] = new Stdev();
+    _functions[8] = new StdevP();
+    _functions[9] = new Sum();
+    _functions[10] = new Var();
+    _functions[11] = new VarP();
+
+    AddHiddenValueHandlingFunction(new Average(), 101);
+    AddHiddenValueHandlingFunction(new Count(), 102);
+    AddHiddenValueHandlingFunction(new CountA(), 103);
+    AddHiddenValueHandlingFunction(new Max(), 104);
+    AddHiddenValueHandlingFunction(new Min(), 105);
+    AddHiddenValueHandlingFunction(new Product(), 106);
+    AddHiddenValueHandlingFunction(new Stdev(), 107);
+    AddHiddenValueHandlingFunction(new StdevP(), 108);
+    AddHiddenValueHandlingFunction(new Sum(), 109);
+    AddHiddenValueHandlingFunction(new Var(), 110);
+    AddHiddenValueHandlingFunction(new VarP(), 111);
+  }
+
+  private void AddHiddenValueHandlingFunction(HiddenValuesHandlingFunction func, int funcNum) {
+    func.IgnoreHiddenValues = true;
+    _functions[funcNum] = func;
+  }
+
+  public override void BeforeInvoke(ParsingContext context) {
+    base.BeforeInvoke(context);
+    context.Scopes.Current.IsSubtotal = true;
+  }
+
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var funcNum = ArgToInt(arguments, 0);
+    if (context.Scopes.Current.Parent != null && context.Scopes.Current.Parent.IsSubtotal) {
+      return CreateResult(0d, DataType.Decimal);
+    }
+    var actualArgs = arguments.Skip(1);
+    var function = GetFunctionByCalcType(funcNum);
+    var compileResult = function.Execute(actualArgs, context);
+    compileResult.IsResultOfSubtotal = true;
+    return compileResult;
+  }
+
+  private ExcelFunction GetFunctionByCalcType(int funcNum) {
+    if (!_functions.ContainsKey(funcNum)) {
+      ThrowExcelErrorValueException(eErrorType.Value);
+      //throw new ArgumentException("Invalid funcNum " + funcNum + ", valid ranges are 1-11 and 101-111");
+    }
+    return _functions[funcNum];
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Sum.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Sum.cs
new file mode 100644
index 0000000..5f15170
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Sum.cs
@@ -0,0 +1,65 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Sum : HiddenValuesHandlingFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    var retVal = 0d;
+    if (arguments != null) {
+      foreach (var arg in arguments) {
+        retVal += Calculate(arg, context);
+      }
+    }
+    return CreateResult(retVal, DataType.Decimal);
+  }
+
+  private double Calculate(FunctionArgument arg, ParsingContext context) {
+    var retVal = 0d;
+    if (ShouldIgnore(arg)) {
+      return retVal;
+    }
+    if (arg.Value is IEnumerable<FunctionArgument> value) {
+      foreach (var item in value) {
+        retVal += Calculate(item, context);
+      }
+    } else if (arg.Value is ExcelDataProvider.IRangeInfo info) {
+      foreach (var c in info) {
+        if (ShouldIgnore(c, context) == false) {
+          CheckForAndHandleExcelError(c);
+          retVal += c.ValueDouble;
+        }
+      }
+    } else {
+      CheckForAndHandleExcelError(arg);
+      retVal += ConvertUtil.GetValueDouble(arg.Value, true);
+    }
+    return retVal;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/SumIf.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/SumIf.cs
new file mode 100644
index 0000000..fc930b3
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/SumIf.cs
@@ -0,0 +1,145 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class SumIf : HiddenValuesHandlingFunction {
+  private readonly NumericExpressionEvaluator _evaluator;
+
+  public SumIf()
+      : this(new()) {}
+
+  public SumIf(NumericExpressionEvaluator evaluator) {
+    Require.That(evaluator).Named("evaluator").IsNotNull();
+    _evaluator = evaluator;
+  }
+
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var args = arguments.ElementAt(0).Value as ExcelDataProvider.IRangeInfo; //IEnumerable<FunctionArgument>;
+    var criteria = arguments.ElementAt(1).Value;
+    ThrowExcelErrorValueExceptionIf(
+        () => criteria == null || criteria.ToString().Length > 255,
+        eErrorType.Value);
+    double retVal;
+    if (arguments.Count() > 2) {
+      var sumRange = arguments.ElementAt(2).Value as ExcelDataProvider.IRangeInfo; //IEnumerable<FunctionArgument>;
+      retVal = CalculateWithSumRange(args, criteria.ToString(), sumRange, context);
+    } else {
+      if (args != null) {
+        retVal = CalculateSingleRange(args, criteria.ToString(), context);
+      } else {
+        retVal = CalculateSingleRange(
+            (arguments.ElementAt(0).Value as IEnumerable<FunctionArgument>),
+            criteria.ToString(),
+            context);
+      }
+    }
+    return CreateResult(retVal, DataType.Decimal);
+  }
+
+  private double CalculateWithSumRange(
+      ExcelDataProvider.IRangeInfo range,
+      string criteria,
+      ExcelDataProvider.IRangeInfo sumRange,
+      ParsingContext context) {
+    var retVal = 0d;
+    foreach (var cell in range) {
+      if (_evaluator.Evaluate(cell.Value, criteria)) {
+        var or = cell.Row - range.Address._fromRow;
+        var oc = cell.Column - range.Address._fromCol;
+        if (sumRange.Address._fromRow + or <= sumRange.Address._toRow
+            && sumRange.Address._fromCol + oc <= sumRange.Address._toCol) {
+          var v = sumRange.GetOffset(or, oc);
+          if (v is ExcelErrorValue value) {
+            throw (new ExcelErrorValueException(value));
+          }
+          retVal += ConvertUtil.GetValueDouble(v, true);
+        }
+      }
+    }
+    return retVal;
+  }
+
+  private double CalculateSingleRange(
+      IEnumerable<FunctionArgument> args,
+      string expression,
+      ParsingContext context) {
+    var retVal = 0d;
+    var flattendedRange = ArgsToDoubleEnumerable(args, context);
+    foreach (var candidate in flattendedRange) {
+      if (_evaluator.Evaluate(candidate, expression)) {
+        retVal += candidate;
+      }
+    }
+    return retVal;
+  }
+
+  private double CalculateSingleRange(
+      ExcelDataProvider.IRangeInfo range,
+      string expression,
+      ParsingContext context) {
+    var retVal = 0d;
+    foreach (var candidate in range) {
+      if (_evaluator.Evaluate(candidate.Value, expression)) {
+        if (candidate.IsExcelError) {
+          throw (new ExcelErrorValueException((ExcelErrorValue)candidate.Value));
+        }
+        retVal += candidate.ValueDouble;
+      }
+    }
+    return retVal;
+  }
+
+  //private double Calculate(FunctionArgument arg, string expression)
+  //{
+  //    var retVal = 0d;
+  //    if (ShouldIgnore(arg) || !_evaluator.Evaluate(arg.Value, expression))
+  //    {
+  //        return retVal;
+  //    }
+  //    if (arg.Value is double || arg.Value is int)
+  //    {
+  //        retVal += Convert.ToDouble(arg.Value);
+  //    }
+  //    else if (arg.Value is System.DateTime)
+  //    {
+  //        retVal += Convert.ToDateTime(arg.Value).ToOADate();
+  //    }
+  //    else if (arg.Value is IEnumerable<FunctionArgument>)
+  //    {
+  //        foreach (var item in (IEnumerable<FunctionArgument>)arg.Value)
+  //        {
+  //            retVal += Calculate(item, expression);
+  //        }
+  //    }
+  //    return retVal;
+  //}
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/SumIfs.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/SumIfs.cs
new file mode 100644
index 0000000..6cd29bb
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/SumIfs.cs
@@ -0,0 +1,68 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-01-15
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class SumIfs : MultipleRangeCriteriasFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray();
+    ValidateArguments(functionArguments, 3);
+    var sumRange = ArgsToDoubleEnumerable(
+            true,
+            new List<FunctionArgument> { functionArguments[0] },
+            context)
+        .ToList();
+    var argRanges = new List<ExcelDataProvider.IRangeInfo>();
+    var criterias = new List<object>();
+    for (var ix = 1; ix < 31; ix += 2) {
+      if (functionArguments.Length <= ix) {
+        break;
+      }
+      var rangeInfo = functionArguments[ix].ValueAsRangeInfo;
+      argRanges.Add(rangeInfo);
+      if (ix > 1) {
+        ThrowExcelErrorValueExceptionIf(
+            () => rangeInfo.GetNCells() != argRanges[0].GetNCells(),
+            eErrorType.Value);
+      }
+      criterias.Add(functionArguments[ix + 1].Value);
+    }
+    IEnumerable<int> matchIndexes = GetMatchIndexes(argRanges[0], criterias[0]);
+    var enumerable = matchIndexes as IList<int> ?? matchIndexes.ToList();
+    for (var ix = 1; ix < argRanges.Count && enumerable.Any(); ix++) {
+      var indexes = GetMatchIndexes(argRanges[ix], criterias[ix]);
+      matchIndexes = enumerable.Intersect(indexes);
+    }
+
+    var result = matchIndexes.Sum(index => sumRange[index]);
+
+    return CreateResult(result, DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/SumProduct.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/SumProduct.cs
new file mode 100644
index 0000000..b0ef6c1
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/SumProduct.cs
@@ -0,0 +1,84 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class SumProduct : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    double result = 0d;
+    List<List<double>> results = new List<List<double>>();
+    foreach (var arg in arguments) {
+      results.Add(new());
+      var currentResult = results.Last();
+      if (arg.Value is IEnumerable<FunctionArgument> value) {
+        foreach (var val in value) {
+          AddValue(val.Value, currentResult);
+        }
+      } else if (arg.Value is FunctionArgument) {
+        AddValue(arg.Value, currentResult);
+      } else if (arg.IsExcelRange) {
+        var r = arg.ValueAsRangeInfo;
+        for (int col = r.Address._fromCol; col <= r.Address._toCol; col++) {
+          for (int row = r.Address._fromRow; row <= r.Address._toRow; row++) {
+            AddValue(r.GetValue(row, col), currentResult);
+          }
+        }
+      }
+    }
+    // Validate that all supplied lists have the same length
+    var arrayLength = results.First().Count;
+    foreach (var list in results) {
+      if (list.Count != arrayLength) {
+        throw new ExcelErrorValueException(ExcelErrorValue.Create(eErrorType.Value));
+        //throw new ExcelFunctionException("All supplied arrays must have the same length", ExcelErrorCodes.Value);
+      }
+    }
+    for (var rowIndex = 0; rowIndex < arrayLength; rowIndex++) {
+      double rowResult = 1;
+      for (var colIndex = 0; colIndex < results.Count; colIndex++) {
+        rowResult *= results[colIndex][rowIndex];
+      }
+      result += rowResult;
+    }
+    return CreateResult(result, DataType.Decimal);
+  }
+
+  private void AddValue(object convertVal, List<double> currentResult) {
+    if (IsNumeric(convertVal)) {
+      currentResult.Add(Convert.ToDouble(convertVal));
+    } else if (convertVal is ExcelErrorValue val) {
+      throw (new ExcelErrorValueException(val));
+    } else {
+      currentResult.Add(0d);
+    }
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Sumsq.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Sumsq.cs
new file mode 100644
index 0000000..6ef28b2
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Sumsq.cs
@@ -0,0 +1,48 @@
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Sumsq : HiddenValuesHandlingFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    var retVal = 0d;
+    if (arguments != null) {
+      foreach (var arg in arguments) {
+        retVal += Calculate(arg, context);
+      }
+    }
+    return CreateResult(retVal, DataType.Decimal);
+  }
+
+  private double Calculate(FunctionArgument arg, ParsingContext context, bool isInArray = false) {
+    var retVal = 0d;
+    if (ShouldIgnore(arg)) {
+      return retVal;
+    }
+    if (arg.Value is IEnumerable<FunctionArgument> arguments) {
+      foreach (var item in arguments) {
+        retVal += Calculate(item, context, true);
+      }
+    } else {
+      var cs = arg.Value as ExcelDataProvider.IRangeInfo;
+      if (cs != null) {
+        foreach (var c in cs) {
+          if (ShouldIgnore(c, context) == false) {
+            CheckForAndHandleExcelError(c);
+            retVal += System.Math.Pow(c.ValueDouble, 2);
+          }
+        }
+      } else {
+        CheckForAndHandleExcelError(arg);
+        if (IsNumericString(arg.Value) && !isInArray) {
+          var value = ConvertUtil.GetValueDouble(arg.Value);
+          return System.Math.Pow(value, 2);
+        }
+        var ignoreBool = isInArray;
+        retVal += System.Math.Pow(ConvertUtil.GetValueDouble(arg.Value, ignoreBool), 2);
+      }
+    }
+    return retVal;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Tan.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Tan.cs
new file mode 100644
index 0000000..badfbba
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Tan.cs
@@ -0,0 +1,38 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Tan : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var arg = ArgToDecimal(arguments, 0);
+    return CreateResult(System.Math.Tan(arg), DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Tanh.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Tanh.cs
new file mode 100644
index 0000000..bc07d93
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Tanh.cs
@@ -0,0 +1,38 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Tanh : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var arg = ArgToDecimal(arguments, 0);
+    return CreateResult(System.Math.Tanh(arg), DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Trunc.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Trunc.cs
new file mode 100644
index 0000000..09adcb1
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Trunc.cs
@@ -0,0 +1,44 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2014-01-06
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Trunc : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var number = ArgToDecimal(arguments, 0);
+    if (arguments.Count() == 1) {
+      return CreateResult(System.Math.Truncate(number), DataType.Decimal);
+    }
+    var nDigits = ArgToInt(arguments, 1);
+    var func = context.Configuration.FunctionRepository.GetFunction("rounddown");
+    return func.Execute(arguments, context);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Var.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Var.cs
new file mode 100644
index 0000000..d7e1d5e
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/Var.cs
@@ -0,0 +1,38 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Var : HiddenValuesHandlingFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var args = ArgsToDoubleEnumerable(IgnoreHiddenValues, false, arguments, context);
+    return new(VarMethods.Var(args), DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/VarMethods.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/VarMethods.cs
new file mode 100644
index 0000000..f16b902
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/VarMethods.cs
@@ -0,0 +1,50 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-04-19
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+internal static class VarMethods {
+  private static double Divide(double left, double right) {
+    if (System.Math.Abs(right - 0d) < double.Epsilon) {
+      throw new ExcelErrorValueException(eErrorType.Div0);
+    }
+    return left / right;
+  }
+
+  public static double Var(IEnumerable<double> args) {
+    double avg = args.Average();
+    double d = args.Aggregate(0.0, (total, next) => total + System.Math.Pow(next - avg, 2));
+    return Divide(d, (args.Count() - 1));
+  }
+
+  public static double VarP(IEnumerable<double> args) {
+    double avg = args.Average();
+    double d = args.Aggregate(0.0, (total, next) => total + System.Math.Pow(next - avg, 2));
+    return Divide(d, args.Count());
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/VarP.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/VarP.cs
new file mode 100644
index 0000000..9ee6bb0
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Math/VarP.cs
@@ -0,0 +1,38 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class VarP : HiddenValuesHandlingFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var args = ArgsToDoubleEnumerable(IgnoreHiddenValues, false, arguments, context);
+    return new(VarMethods.VarP(args), DataType.Decimal);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Numeric/CInt.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Numeric/CInt.cs
new file mode 100644
index 0000000..1f11dc7
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Numeric/CInt.cs
@@ -0,0 +1,38 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class CInt : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var num = ArgToDecimal(arguments, 0);
+    return CreateResult((int)System.Math.Floor(num), DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/ObjectEnumerableArgConverter.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/ObjectEnumerableArgConverter.cs
new file mode 100644
index 0000000..8db3856
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/ObjectEnumerableArgConverter.cs
@@ -0,0 +1,49 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class ObjectEnumerableArgConverter : CollectionFlattener<object> {
+  public virtual IEnumerable<object> ConvertArgs(
+      bool ignoreHidden,
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    return base.FuncArgsToFlatEnumerable(
+        arguments,
+        (arg, argList) => {
+          if (arg.Value is ExcelDataProvider.IRangeInfo info) {
+            foreach (var cell in info) {
+              if (!CellStateHelper.ShouldIgnore(ignoreHidden, cell, context)) {
+                argList.Add(cell.Value);
+              }
+            }
+          } else {
+            argList.Add(arg.Value);
+          }
+        });
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Address.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Address.cs
new file mode 100644
index 0000000..76fc916
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Address.cs
@@ -0,0 +1,62 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Address : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var row = ArgToInt(arguments, 0);
+    var col = ArgToInt(arguments, 1);
+    ThrowExcelErrorValueExceptionIf(() => row < 0 && col < 0, eErrorType.Value);
+    var referenceType = ExcelReferenceType.AbsoluteRowAndColumn;
+    var worksheetSpec = string.Empty;
+    if (arguments.Count() > 2) {
+      var arg3 = ArgToInt(arguments, 2);
+      ThrowExcelErrorValueExceptionIf(() => arg3 < 1 || arg3 > 4, eErrorType.Value);
+      referenceType = (ExcelReferenceType)ArgToInt(arguments, 2);
+    }
+    if (arguments.Count() > 3) {
+      var fourthArg = arguments.ElementAt(3).Value;
+      if (fourthArg is bool arg && !arg) {
+        throw new InvalidOperationException("Excelformulaparser does not support the R1C1 format!");
+      }
+    }
+    if (arguments.Count() > 4) {
+      var fifthArg = arguments.ElementAt(4).Value;
+      if (fifthArg is string && !string.IsNullOrEmpty(fifthArg.ToString())) {
+        worksheetSpec = fifthArg + "!";
+      }
+    }
+    var translator = new IndexToAddressTranslator(context.ExcelDataProvider, referenceType);
+    return CreateResult(worksheetSpec + translator.ToAddress(col, row), DataType.ExcelAddress);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/ArrayLookupNavigator.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/ArrayLookupNavigator.cs
new file mode 100644
index 0000000..59cc919
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/ArrayLookupNavigator.cs
@@ -0,0 +1,57 @@
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class ArrayLookupNavigator : LookupNavigator {
+  private readonly FunctionArgument[] _arrayData;
+  private int _index;
+  private object _currentValue;
+
+  public ArrayLookupNavigator(
+      LookupDirection direction,
+      LookupArguments arguments,
+      ParsingContext parsingContext)
+      : base(direction, arguments, parsingContext) {
+    Require.That(arguments).Named("arguments").IsNotNull();
+    Require.That(arguments.DataArray).Named("arguments.DataArray").IsNotNull();
+    _arrayData = arguments.DataArray.ToArray();
+    Initialize();
+  }
+
+  private void Initialize() {
+    if (Arguments.LookupIndex >= _arrayData.Length) {
+      throw new ExcelErrorValueException(eErrorType.Ref);
+    }
+    SetCurrentValue();
+  }
+
+  public override int Index => _index;
+
+  private void SetCurrentValue() {
+    _currentValue = _arrayData[_index];
+  }
+
+  private bool HasNext() {
+    if (Direction == LookupDirection.Vertical) {
+      return _index < (_arrayData.Length - 1);
+    }
+    return false;
+  }
+
+  public override bool MoveNext() {
+    if (!HasNext()) {
+      return false;
+    }
+    if (Direction == LookupDirection.Vertical) {
+      _index++;
+    }
+    SetCurrentValue();
+    return true;
+  }
+
+  public override object CurrentValue => _arrayData[_index].Value;
+
+  public override object GetLookupValue() {
+    return _arrayData[_index].Value;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Choose.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Choose.cs
new file mode 100644
index 0000000..ea80916
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Choose.cs
@@ -0,0 +1,43 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Choose : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var index = ArgToInt(arguments, 0);
+    var items = new List<string>();
+    for (int x = 0; x < arguments.Count(); x++) {
+      items.Add(arguments.ElementAt(x).ValueFirst.ToString());
+    }
+    return CreateResult(items[index], DataType.String);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Column.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Column.cs
new file mode 100644
index 0000000..810d1e4
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Column.cs
@@ -0,0 +1,47 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Column : LookupFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    if (arguments == null || arguments.Count() == 0) {
+      return CreateResult(context.Scopes.Current.Address.FromCol, DataType.Integer);
+    }
+    var rangeAddress = ArgToString(arguments, 0);
+    if (!ExcelAddressUtil.IsValidAddress(rangeAddress)) {
+      throw new ArgumentException("An invalid argument was supplied");
+    }
+    var factory = new RangeAddressFactory(context.ExcelDataProvider);
+    var address = factory.Create(rangeAddress);
+    return CreateResult(address.FromCol, DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Columns.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Columns.cs
new file mode 100644
index 0000000..5e92d1a
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Columns.cs
@@ -0,0 +1,49 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Columns : LookupFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var r = arguments.ElementAt(0).ValueAsRangeInfo;
+    if (r != null) {
+      return CreateResult(r.Address._toCol - r.Address._fromCol + 1, DataType.Integer);
+    }
+    var range = ArgToString(arguments, 0);
+    if (ExcelAddressUtil.IsValidAddress(range)) {
+      var factory = new RangeAddressFactory(context.ExcelDataProvider);
+      var address = factory.Create(range);
+      return CreateResult(address.ToCol - address.FromCol + 1, DataType.Integer);
+    }
+    throw new ArgumentException("Invalid range supplied");
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/ExcelLookupNavigator.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/ExcelLookupNavigator.cs
new file mode 100644
index 0000000..c843742
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/ExcelLookupNavigator.cs
@@ -0,0 +1,105 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+public class ExcelLookupNavigator : LookupNavigator {
+  private int _currentRow;
+  private int _currentCol;
+  private object _currentValue;
+  private RangeAddress _rangeAddress;
+  private int _index;
+
+  public ExcelLookupNavigator(
+      LookupDirection direction,
+      LookupArguments arguments,
+      ParsingContext parsingContext)
+      : base(direction, arguments, parsingContext) {
+    Initialize();
+  }
+
+  private void Initialize() {
+    _index = 0;
+    var factory = new RangeAddressFactory(ParsingContext.ExcelDataProvider);
+    if (Arguments.RangeInfo == null) {
+      _rangeAddress = factory.Create(
+          ParsingContext.Scopes.Current.Address.Worksheet,
+          Arguments.RangeAddress);
+    } else {
+      _rangeAddress = factory.Create(
+          Arguments.RangeInfo.Address.WorkSheet,
+          Arguments.RangeInfo.Address.Address);
+    }
+    _currentCol = _rangeAddress.FromCol;
+    _currentRow = _rangeAddress.FromRow;
+    SetCurrentValue();
+  }
+
+  private void SetCurrentValue() {
+    _currentValue = ParsingContext.ExcelDataProvider.GetCellValue(
+        _rangeAddress.Worksheet,
+        _currentRow,
+        _currentCol);
+  }
+
+  private bool HasNext() {
+    if (Direction == LookupDirection.Vertical) {
+      return _currentRow < _rangeAddress.ToRow;
+    }
+    return _currentCol < _rangeAddress.ToCol;
+  }
+
+  public override int Index => _index;
+
+  public override bool MoveNext() {
+    if (!HasNext()) {
+      return false;
+    }
+    if (Direction == LookupDirection.Vertical) {
+      _currentRow++;
+    } else {
+      _currentCol++;
+    }
+    _index++;
+    SetCurrentValue();
+    return true;
+  }
+
+  public override object CurrentValue => _currentValue;
+
+  public override object GetLookupValue() {
+    var row = _currentRow;
+    var col = _currentCol;
+    if (Direction == LookupDirection.Vertical) {
+      col += Arguments.LookupIndex - 1;
+      row += Arguments.LookupOffset;
+    } else {
+      row += Arguments.LookupIndex - 1;
+      col += Arguments.LookupOffset;
+    }
+    return ParsingContext.ExcelDataProvider.GetCellValue(_rangeAddress.Worksheet, row, col);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/ExcelMatch.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/ExcelMatch.cs
new file mode 100644
index 0000000..7bd3e4b
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/ExcelMatch.cs
@@ -0,0 +1,88 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class ExcelMatch : LookupFunction {
+  private enum MatchType {
+    ClosestAbove = -1,
+    ExactMatch = 0,
+    ClosestBelow = 1,
+  }
+
+  public ExcelMatch()
+      : base(new WildCardValueMatcher(), new()) {}
+
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+
+    var searchedValue = arguments.ElementAt(0).Value;
+    var address = ArgToString(arguments, 1);
+    var rangeAddressFactory = new RangeAddressFactory(context.ExcelDataProvider);
+    var rangeAddress = rangeAddressFactory.Create(address);
+    var matchType = GetMatchType(arguments);
+    var args = new LookupArguments(searchedValue, address, 0, 0, false);
+    var lookupDirection = GetLookupDirection(rangeAddress);
+    var navigator = LookupNavigatorFactory.Create(lookupDirection, args, context);
+    int? lastMatchResult = default(int?);
+    do {
+      var matchResult = IsMatch(navigator.CurrentValue, searchedValue);
+      if (matchType == MatchType.ClosestBelow && matchResult >= 0) {
+        if (!lastMatchResult.HasValue && matchResult > 0) {
+          // TODO: error handling. This happens only if the first item is
+          // below the searched value.
+        }
+        var index = matchResult == 0 ? navigator.Index + 1 : navigator.Index;
+        return CreateResult(index, DataType.Integer);
+      }
+      if (matchType == MatchType.ClosestAbove && matchResult <= 0) {
+        if (!lastMatchResult.HasValue && matchResult < 0) {
+          // TODO: error handling. This happens only if the first item is
+          // above the searched value
+        }
+        var index = matchResult == 0 ? navigator.Index + 1 : navigator.Index;
+        return CreateResult(index, DataType.Integer);
+      }
+      if (matchType == MatchType.ExactMatch && matchResult == 0) {
+        return CreateResult(navigator.Index + 1, DataType.Integer);
+      }
+      lastMatchResult = matchResult;
+    } while (navigator.MoveNext());
+    return CreateResult(null, DataType.Integer);
+  }
+
+  private MatchType GetMatchType(IEnumerable<FunctionArgument> arguments) {
+    var matchType = MatchType.ClosestBelow;
+    if (arguments.Count() > 2) {
+      matchType = (MatchType)ArgToInt(arguments, 2);
+    }
+    return matchType;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/HLookup.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/HLookup.cs
new file mode 100644
index 0000000..abd2484
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/HLookup.cs
@@ -0,0 +1,40 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class HLookup : LookupFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 3);
+    var lookupArgs = new LookupArguments(arguments);
+    ThrowExcelErrorValueExceptionIf(() => lookupArgs.LookupIndex < 1, eErrorType.Value);
+    var navigator = LookupNavigatorFactory.Create(LookupDirection.Horizontal, lookupArgs, context);
+    return Lookup(navigator, lookupArgs);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Index.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Index.cs
new file mode 100644
index 0000000..3629f4d
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Index.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Index : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var arg1 = arguments.ElementAt(0);
+    var args = arg1.Value as IEnumerable<FunctionArgument>;
+    var crf = new CompileResultFactory();
+    if (args != null) {
+      var index = ArgToInt(arguments, 1);
+      if (index > args.Count()) {
+        throw new ExcelErrorValueException(eErrorType.Ref);
+      }
+      var candidate = args.ElementAt(index - 1);
+      //Commented JK-Can be any data type
+      //if (!IsNumber(candidate.Value))
+      //{
+      //    throw new ExcelErrorValueException(eErrorType.Value);
+      //}
+      //return CreateResult(ConvertUtil.GetValueDouble(candidate.Value), DataType.Decimal);
+      return crf.Create(candidate.Value);
+    }
+    if (arg1.IsExcelRange) {
+      var row = ArgToInt(arguments, 1);
+      var col = arguments.Count() > 2 ? ArgToInt(arguments, 2) : 1;
+      var ri = arg1.ValueAsRangeInfo;
+      if (row > ri.Address._toRow - ri.Address._fromRow + 1
+          || col > ri.Address._toCol - ri.Address._fromCol + 1) {
+        ThrowExcelErrorValueException(eErrorType.Ref);
+      }
+      var candidate = ri.GetOffset(row - 1, col - 1);
+      //Commented JK-Can be any data type
+      //if (!IsNumber(candidate.Value))
+      //{
+      //    throw new ExcelErrorValueException(eErrorType.Value);
+      //}
+      return crf.Create(candidate);
+    }
+    throw new NotImplementedException();
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Indirect.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Indirect.cs
new file mode 100644
index 0000000..68319d6
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Indirect.cs
@@ -0,0 +1,49 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2014-04-13
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Indirect : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var address = ArgToString(arguments, 0);
+    var adr = new ExcelAddress(address);
+    var ws = adr.WorkSheet;
+    if (string.IsNullOrEmpty(ws)) {
+      ws = context.Scopes.Current.Address.Worksheet;
+    }
+    var result = context.ExcelDataProvider.GetRange(ws, adr._fromRow, adr._fromCol, address);
+    if (result.IsEmpty) {
+      // Bug 15290
+      var namedValueExpr = new NamedValueExpression(address, context);
+      return namedValueExpr.Compile();
+    }
+    return new(result, DataType.Enumerable);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Lookup.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Lookup.cs
new file mode 100644
index 0000000..7b1dbad
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Lookup.cs
@@ -0,0 +1,97 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Lookup : LookupFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    if (HaveTwoRanges(arguments)) {
+      return HandleTwoRanges(arguments, context);
+    }
+    return HandleSingleRange(arguments, context);
+  }
+
+  private bool HaveTwoRanges(IEnumerable<FunctionArgument> arguments) {
+    if (arguments.Count() == 2) {
+      return false;
+    }
+    return (ExcelAddressUtil.IsValidAddress(arguments.ElementAt(2).Value.ToString()));
+  }
+
+  private CompileResult HandleSingleRange(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    var searchedValue = arguments.ElementAt(0).Value;
+    Require.That(arguments.ElementAt(1).Value).Named("firstAddress").IsNotNull();
+    var firstAddress = ArgToString(arguments, 1);
+    var rangeAddressFactory = new RangeAddressFactory(context.ExcelDataProvider);
+    var address = rangeAddressFactory.Create(firstAddress);
+    var nRows = address.ToRow - address.FromRow;
+    var nCols = address.ToCol - address.FromCol;
+    var lookupIndex = nCols + 1;
+    var lookupDirection = LookupDirection.Vertical;
+    if (nCols > nRows) {
+      lookupIndex = nRows + 1;
+      lookupDirection = LookupDirection.Horizontal;
+    }
+    var lookupArgs = new LookupArguments(searchedValue, firstAddress, lookupIndex, 0, true);
+    var navigator = LookupNavigatorFactory.Create(lookupDirection, lookupArgs, context);
+    return Lookup(navigator, lookupArgs);
+  }
+
+  private CompileResult HandleTwoRanges(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    var searchedValue = arguments.ElementAt(0).Value;
+    Require.That(arguments.ElementAt(1).Value).Named("firstAddress").IsNotNull();
+    Require.That(arguments.ElementAt(2).Value).Named("secondAddress").IsNotNull();
+    var firstAddress = ArgToString(arguments, 1);
+    var secondAddress = ArgToString(arguments, 2);
+    var rangeAddressFactory = new RangeAddressFactory(context.ExcelDataProvider);
+    var address1 = rangeAddressFactory.Create(firstAddress);
+    var address2 = rangeAddressFactory.Create(secondAddress);
+    var lookupIndex = (address2.FromCol - address1.FromCol) + 1;
+    var lookupOffset = address2.FromRow - address1.FromRow;
+    var lookupDirection = GetLookupDirection(address1);
+    if (lookupDirection == LookupDirection.Horizontal) {
+      lookupIndex = (address2.FromRow - address1.FromRow) + 1;
+      lookupOffset = address2.FromCol - address1.FromCol;
+    }
+    var lookupArgs = new LookupArguments(
+        searchedValue,
+        firstAddress,
+        lookupIndex,
+        lookupOffset,
+        true);
+    var navigator = LookupNavigatorFactory.Create(lookupDirection, lookupArgs, context);
+    return Lookup(navigator, lookupArgs);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/LookupArguments.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/LookupArguments.cs
new file mode 100644
index 0000000..05933b5
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/LookupArguments.cs
@@ -0,0 +1,102 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class LookupArguments {
+  public enum LookupArgumentDataType {
+    ExcelRange,
+    DataArray,
+  }
+
+  public LookupArguments(IEnumerable<FunctionArgument> arguments)
+      : this(arguments, new()) {}
+
+  public LookupArguments(IEnumerable<FunctionArgument> arguments, ArgumentParsers argumentParsers) {
+    _argumentParsers = argumentParsers;
+    SearchedValue = arguments.ElementAt(0).Value;
+    var arg1 = arguments.ElementAt(1).Value;
+    var dataArray = arg1 as IEnumerable<FunctionArgument>;
+    if (dataArray != null) {
+      DataArray = dataArray;
+      ArgumentDataType = LookupArgumentDataType.DataArray;
+    } else {
+      //if (arg1 is ExcelDataProvider.INameInfo) arg1 = ((ExcelDataProvider.INameInfo) arg1).Value;
+      var rangeInfo = arg1 as ExcelDataProvider.IRangeInfo;
+      if (rangeInfo != null) {
+        RangeAddress = string.IsNullOrEmpty(rangeInfo.Address.WorkSheet)
+            ? rangeInfo.Address.Address
+            : "'" + rangeInfo.Address.WorkSheet + "'!" + rangeInfo.Address.Address;
+        RangeInfo = rangeInfo;
+        ArgumentDataType = LookupArgumentDataType.ExcelRange;
+      } else {
+        RangeAddress = arg1.ToString();
+        ArgumentDataType = LookupArgumentDataType.ExcelRange;
+      }
+    }
+    LookupIndex = (int)
+      _argumentParsers.GetParser(DataType.Integer).Parse(arguments.ElementAt(2).Value);
+    if (arguments.Count() > 3) {
+      RangeLookup = (bool)
+        _argumentParsers.GetParser(DataType.Boolean).Parse(arguments.ElementAt(3).Value);
+    } else {
+      RangeLookup = true;
+    }
+  }
+
+  public LookupArguments(
+      object searchedValue,
+      string rangeAddress,
+      int lookupIndex,
+      int lookupOffset,
+      bool rangeLookup) {
+    SearchedValue = searchedValue;
+    RangeAddress = rangeAddress;
+    LookupIndex = lookupIndex;
+    LookupOffset = lookupOffset;
+    RangeLookup = rangeLookup;
+  }
+
+  private readonly ArgumentParsers _argumentParsers;
+
+  public object SearchedValue { get; private set; }
+
+  public string RangeAddress { get; private set; }
+
+  public int LookupIndex { get; private set; }
+
+  public int LookupOffset { get; private set; }
+
+  public bool RangeLookup { get; private set; }
+
+  public IEnumerable<FunctionArgument> DataArray { get; private set; }
+
+  public ExcelDataProvider.IRangeInfo RangeInfo { get; private set; }
+
+  public LookupArgumentDataType ArgumentDataType { get; private set; }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/LookupDirection.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/LookupDirection.cs
new file mode 100644
index 0000000..416d087
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/LookupDirection.cs
@@ -0,0 +1,31 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public enum LookupDirection {
+  Vertical,
+  Horizontal,
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/LookupFunction.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/LookupFunction.cs
new file mode 100644
index 0000000..e376443
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/LookupFunction.cs
@@ -0,0 +1,88 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+public abstract class LookupFunction : ExcelFunction {
+  private readonly ValueMatcher _valueMatcher;
+  private readonly CompileResultFactory _compileResultFactory;
+
+  public LookupFunction()
+      : this(new LookupValueMatcher(), new()) {}
+
+  public LookupFunction(ValueMatcher valueMatcher, CompileResultFactory compileResultFactory) {
+    _valueMatcher = valueMatcher;
+    _compileResultFactory = compileResultFactory;
+  }
+
+  public override bool IsLookupFuction => true;
+
+  protected int IsMatch(object o1, object o2) {
+    return _valueMatcher.IsMatch(o1, o2);
+  }
+
+  protected LookupDirection GetLookupDirection(RangeAddress rangeAddress) {
+    var nRows = rangeAddress.ToRow - rangeAddress.FromRow;
+    var nCols = rangeAddress.ToCol - rangeAddress.FromCol;
+    return nCols > nRows ? LookupDirection.Horizontal : LookupDirection.Vertical;
+  }
+
+  protected CompileResult Lookup(LookupNavigator navigator, LookupArguments lookupArgs) {
+    object lastValue = null;
+    object lastLookupValue = null;
+    int? lastMatchResult = null;
+    if (lookupArgs.SearchedValue == null) {
+      return new(ExcelErrorValue.Create(eErrorType.Na), DataType.ExcelError);
+    }
+    do {
+      var matchResult = IsMatch(navigator.CurrentValue, lookupArgs.SearchedValue);
+      if (matchResult != 0) {
+        if (lastValue != null && navigator.CurrentValue == null) {
+          break;
+        }
+
+        if (lookupArgs.RangeLookup) {
+          if (lastValue == null && matchResult > 0) {
+            ThrowExcelErrorValueException(eErrorType.Na);
+          }
+          if (lastValue != null && matchResult > 0 && lastMatchResult < 0) {
+            return _compileResultFactory.Create(lastLookupValue);
+          }
+          lastMatchResult = matchResult;
+          lastValue = navigator.CurrentValue;
+          lastLookupValue = navigator.GetLookupValue();
+        }
+      } else {
+        return _compileResultFactory.Create(navigator.GetLookupValue());
+      }
+    } while (navigator.MoveNext());
+
+    if (lookupArgs.RangeLookup) {
+      return _compileResultFactory.Create(lastLookupValue);
+    }
+    return new(ExcelErrorValue.Create(eErrorType.Na), DataType.ExcelError);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/LookupNavigator.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/LookupNavigator.cs
new file mode 100644
index 0000000..b29eabe
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/LookupNavigator.cs
@@ -0,0 +1,56 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+public abstract class LookupNavigator {
+  protected readonly LookupDirection Direction;
+  protected readonly LookupArguments Arguments;
+  protected readonly ParsingContext ParsingContext;
+
+  public LookupNavigator(
+      LookupDirection direction,
+      LookupArguments arguments,
+      ParsingContext parsingContext) {
+    Require.That(arguments).Named("arguments").IsNotNull();
+    Require.That(parsingContext).Named("parsingContext").IsNotNull();
+    Require
+        .That(parsingContext.ExcelDataProvider)
+        .Named("parsingContext.ExcelDataProvider")
+        .IsNotNull();
+    Direction = direction;
+    Arguments = arguments;
+    ParsingContext = parsingContext;
+  }
+
+  public abstract int Index { get; }
+
+  public abstract bool MoveNext();
+
+  public abstract object CurrentValue { get; }
+
+  public abstract object GetLookupValue();
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/LookupNavigatorFactory.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/LookupNavigatorFactory.cs
new file mode 100644
index 0000000..be63cde
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/LookupNavigatorFactory.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace AppsheetEpplus;
+
+public static class LookupNavigatorFactory {
+  public static LookupNavigator Create(
+      LookupDirection direction,
+      LookupArguments args,
+      ParsingContext parsingContext) {
+    if (args.ArgumentDataType == LookupArguments.LookupArgumentDataType.ExcelRange) {
+      return new ExcelLookupNavigator(direction, args, parsingContext);
+    }
+    if (args.ArgumentDataType == LookupArguments.LookupArgumentDataType.DataArray) {
+      return new ArrayLookupNavigator(direction, args, parsingContext);
+    }
+    throw new NotSupportedException("Invalid argument datatype");
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Offset.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Offset.cs
new file mode 100644
index 0000000..9229232
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Offset.cs
@@ -0,0 +1,75 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-01-11
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Offset : LookupFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray();
+    ValidateArguments(functionArguments, 3);
+    var startRange = ArgToString(functionArguments, 0);
+    var rowOffset = ArgToInt(functionArguments, 1);
+    var colOffset = ArgToInt(functionArguments, 2);
+    int width = 0,
+        height = 0;
+    if (functionArguments.Length > 3) {
+      height = ArgToInt(functionArguments, 3);
+      ThrowExcelErrorValueExceptionIf(() => height == 0, eErrorType.Ref);
+    }
+    if (functionArguments.Length > 4) {
+      width = ArgToInt(functionArguments, 4);
+      ThrowExcelErrorValueExceptionIf(() => width == 0, eErrorType.Ref);
+    }
+
+    var adr = new ExcelAddress(startRange);
+    var ws = adr.WorkSheet;
+
+    var fromRow = adr._fromRow + rowOffset;
+    var fromCol = adr._fromCol + colOffset;
+    var toRow = (height != 0 ? height : adr._toRow) + rowOffset;
+    var toCol = (width != 0 ? width : adr._toCol) + colOffset;
+
+    var newRange = context.ExcelDataProvider.GetRange(ws, fromRow, fromCol, toRow, toCol);
+    if (!newRange.IsMulti) {
+      if (newRange.IsEmpty) {
+        return CompileResult.Empty;
+      }
+      var val = newRange.GetValue(fromRow, fromCol);
+      if (IsNumeric(val)) {
+        return CreateResult(val, DataType.Decimal);
+      }
+      if (val is ExcelErrorValue) {
+        return CreateResult(val, DataType.ExcelError);
+      }
+      return CreateResult(val, DataType.String);
+    }
+    return CreateResult(newRange, DataType.Enumerable);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Row.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Row.cs
new file mode 100644
index 0000000..2cc481f
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Row.cs
@@ -0,0 +1,47 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Row : LookupFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    if (arguments == null || arguments.Count() == 0) {
+      return CreateResult(context.Scopes.Current.Address.FromRow, DataType.Integer);
+    }
+    var rangeAddress = ArgToString(arguments, 0);
+    if (!ExcelAddressUtil.IsValidAddress(rangeAddress)) {
+      throw new ArgumentException("An invalid argument was supplied");
+    }
+    var factory = new RangeAddressFactory(context.ExcelDataProvider);
+    var address = factory.Create(rangeAddress);
+    return CreateResult(address.FromRow, DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Rows.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Rows.cs
new file mode 100644
index 0000000..31668a8
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/Rows.cs
@@ -0,0 +1,49 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Rows : LookupFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var r = arguments.ElementAt(0).ValueAsRangeInfo;
+    if (r != null) {
+      return CreateResult(r.Address._toRow - r.Address._fromRow + 1, DataType.Integer);
+    }
+    var range = ArgToString(arguments, 0);
+    if (ExcelAddressUtil.IsValidAddress(range)) {
+      var factory = new RangeAddressFactory(context.ExcelDataProvider);
+      var address = factory.Create(range);
+      return CreateResult(address.ToRow - address.FromRow + 1, DataType.Integer);
+    }
+    throw new ArgumentException("Invalid range supplied");
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/VLookup.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/VLookup.cs
new file mode 100644
index 0000000..aad86f3
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/RefAndLookup/VLookup.cs
@@ -0,0 +1,50 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace AppsheetEpplus;
+
+public class VLookup : LookupFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    Stopwatch sw = null;
+    if (context.Debug) {
+      sw = new();
+      sw.Start();
+    }
+    ValidateArguments(arguments, 3);
+    var lookupArgs = new LookupArguments(arguments);
+    var navigator = LookupNavigatorFactory.Create(LookupDirection.Vertical, lookupArgs, context);
+    var result = Lookup(navigator, lookupArgs);
+    if (context.Debug) {
+      sw.Stop();
+      context.Configuration.Logger.LogFunction("VLOOKUP", sw.ElapsedMilliseconds);
+    }
+    return result;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/CStr.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/CStr.cs
new file mode 100644
index 0000000..b95d76d
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/CStr.cs
@@ -0,0 +1,37 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class CStr : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    return CreateResult(ArgToString(arguments, 0), DataType.String);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/CharFunction.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/CharFunction.cs
new file mode 100644
index 0000000..412762b
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/CharFunction.cs
@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class CharFunction : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var number = ArgToInt(arguments, 0);
+    ThrowExcelErrorValueExceptionIf(() => number < 1 || number > 255, eErrorType.Value);
+    return CreateResult(((char)number).ToString(), DataType.String);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Concatenate.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Concatenate.cs
new file mode 100644
index 0000000..0518a1e
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Concatenate.cs
@@ -0,0 +1,47 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Text;
+
+namespace AppsheetEpplus;
+
+public class Concatenate : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    if (arguments == null) {
+      return CreateResult(string.Empty, DataType.String);
+    }
+    var sb = new StringBuilder();
+    foreach (var arg in arguments) {
+      var v = arg.ValueFirst;
+      if (v != null) {
+        sb.Append(v);
+      }
+    }
+    return CreateResult(sb.ToString(), DataType.String);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Exact.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Exact.cs
new file mode 100644
index 0000000..75d1fad
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Exact.cs
@@ -0,0 +1,53 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Exact : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var val1 = arguments.ElementAt(0).ValueFirst;
+    var val2 = arguments.ElementAt(1).ValueFirst;
+
+    if (val1 == null && val2 == null) {
+      return CreateResult(true, DataType.Boolean);
+    }
+    if ((val1 == null && val2 != null) || (val1 != null && val2 == null)) {
+      return CreateResult(false, DataType.Boolean);
+    }
+
+    var result = string.Compare(
+        val1.ToString(),
+        val2.ToString(),
+        StringComparison.InvariantCulture);
+    return CreateResult(result == 0, DataType.Boolean);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Find.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Find.cs
new file mode 100644
index 0000000..a0b7583
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Find.cs
@@ -0,0 +1,51 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Find : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray();
+    ValidateArguments(functionArguments, 2);
+    var search = ArgToString(functionArguments, 0);
+    var searchIn = ArgToString(functionArguments, 1);
+    var startIndex = 0;
+    if (functionArguments.Count() > 2) {
+      startIndex = ArgToInt(functionArguments, 2);
+    }
+    var result = searchIn.IndexOf(search, startIndex, StringComparison.Ordinal);
+    if (result == -1) {
+      throw new ExcelErrorValueException(ExcelErrorValue.Create(eErrorType.Value));
+    }
+    // Adding 1 because Excel uses 1-based index
+    return CreateResult(result + 1, DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Fixed.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Fixed.cs
new file mode 100644
index 0000000..7acf199
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Fixed.cs
@@ -0,0 +1,30 @@
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Fixed : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var number = ArgToDecimal(arguments, 0);
+    var nDecimals = 2;
+    var noCommas = false;
+    if (arguments.Count() > 1) {
+      nDecimals = ArgToInt(arguments, 1);
+    }
+    if (arguments.Count() > 2) {
+      noCommas = ArgToBool(arguments, 2);
+    }
+    var format = (noCommas ? "F" : "N") + nDecimals.ToString(CultureInfo.InvariantCulture);
+    if (nDecimals < 0) {
+      number = number - (number % (System.Math.Pow(10, nDecimals * -1)));
+      number = System.Math.Floor(number);
+      format = noCommas ? "F0" : "N0";
+    }
+    var retVal = number.ToString(format);
+    return CreateResult(retVal, DataType.String);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Hyperlink.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Hyperlink.cs
new file mode 100644
index 0000000..ccc86ed
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Hyperlink.cs
@@ -0,0 +1,41 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-01-10
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Hyperlink : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    if (arguments.Count() > 1) {
+      return CreateResult(ArgToString(arguments, 1), DataType.String);
+    }
+    return CreateResult(ArgToString(arguments, 0), DataType.String);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Left.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Left.cs
new file mode 100644
index 0000000..37c89cf
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Left.cs
@@ -0,0 +1,39 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Left : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var str = ArgToString(arguments, 0);
+    var length = ArgToInt(arguments, 1);
+    return CreateResult(str.Substring(0, length), DataType.String);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Len.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Len.cs
new file mode 100644
index 0000000..4e701f2
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Len.cs
@@ -0,0 +1,40 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Len : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var length = arguments.First().ValueFirst.ToString().Length;
+    return CreateResult(Convert.ToDouble(length), DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Lower.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Lower.cs
new file mode 100644
index 0000000..1cb9b8e
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Lower.cs
@@ -0,0 +1,38 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Lower : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    return CreateResult(arguments.First().ValueFirst.ToString().ToLower(), DataType.String);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Mid.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Mid.cs
new file mode 100644
index 0000000..92bb6bb
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Mid.cs
@@ -0,0 +1,51 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Mid : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 3);
+    var text = ArgToString(arguments, 0);
+    var startIx = ArgToInt(arguments, 1);
+    var length = ArgToInt(arguments, 2);
+    if (startIx <= 0) {
+      throw (new ArgumentException("Argument start can't be less than 1"));
+    }
+    //Allow overflowing start and length
+    if (startIx > text.Length) {
+      return CreateResult("", DataType.String);
+    }
+    var result = text.Substring(
+        startIx - 1,
+        startIx - 1 + length < text.Length ? length : text.Length - startIx + 1);
+    return CreateResult(result, DataType.String);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Proper.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Proper.cs
new file mode 100644
index 0000000..8595e4c
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Proper.cs
@@ -0,0 +1,50 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Globalization;
+using System.Text;
+
+namespace AppsheetEpplus;
+
+public class Proper : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var text = ArgToString(arguments, 0).ToLower(CultureInfo.InvariantCulture);
+    var sb = new StringBuilder();
+    var previousChar = '.';
+    foreach (var ch in text) {
+      if (!char.IsLetter(previousChar)) {
+        sb.Append(ch.ToString(CultureInfo.InvariantCulture).ToUpperInvariant());
+      } else {
+        sb.Append(ch);
+      }
+      previousChar = ch;
+    }
+    return CreateResult(sb.ToString(), DataType.String);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Replace.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Replace.cs
new file mode 100644
index 0000000..3888ab0
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Replace.cs
@@ -0,0 +1,54 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Replace : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 4);
+    var oldText = ArgToString(arguments, 0);
+    var startPos = ArgToInt(arguments, 1);
+    var nCharsToReplace = ArgToInt(arguments, 2);
+    var newText = ArgToString(arguments, 3);
+    var firstPart = GetFirstPart(oldText, startPos);
+    var lastPart = GetLastPart(oldText, startPos, nCharsToReplace);
+    var result = string.Concat(firstPart, newText, lastPart);
+    return CreateResult(result, DataType.String);
+  }
+
+  private string GetFirstPart(string text, int startPos) {
+    return text.Substring(0, startPos - 1);
+  }
+
+  private string GetLastPart(string text, int startPos, int nCharactersToReplace) {
+    int startIx = startPos - 1;
+    startIx += nCharactersToReplace;
+    return text.Substring(startIx, text.Length - startIx);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Rept.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Rept.cs
new file mode 100644
index 0000000..f31ffcf
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Rept.cs
@@ -0,0 +1,44 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2015-01-10
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Text;
+
+namespace AppsheetEpplus;
+
+public class Rept : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var str = ArgToString(arguments, 0);
+    var n = ArgToInt(arguments, 1);
+    var sb = new StringBuilder();
+    for (var x = 0; x < n; x++) {
+      sb.Append(str);
+    }
+    return CreateResult(sb.ToString(), DataType.String);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Right.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Right.cs
new file mode 100644
index 0000000..9b86495
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Right.cs
@@ -0,0 +1,40 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Right : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var str = ArgToString(arguments, 0);
+    var length = ArgToInt(arguments, 1);
+    var startIx = str.Length - length;
+    return CreateResult(str.Substring(startIx, str.Length - startIx), DataType.String);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Search.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Search.cs
new file mode 100644
index 0000000..37533a0
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Search.cs
@@ -0,0 +1,51 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2016-03-28
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Search : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray();
+    ValidateArguments(functionArguments, 2);
+    var search = ArgToString(functionArguments, 0);
+    var searchIn = ArgToString(functionArguments, 1);
+    var startIndex = 0;
+    if (functionArguments.Count() > 2) {
+      startIndex = ArgToInt(functionArguments, 2);
+    }
+    var result = searchIn.IndexOf(search, startIndex, StringComparison.OrdinalIgnoreCase);
+    if (result == -1) {
+      return CreateResult(ExcelErrorValue.Create(eErrorType.Value), DataType.ExcelError);
+    }
+    // Adding 1 because Excel uses 1-based index
+    return CreateResult(result + 1, DataType.Integer);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Substitute.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Substitute.cs
new file mode 100644
index 0000000..b6077c7
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Substitute.cs
@@ -0,0 +1,41 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class Substitute : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 3);
+    var text = ArgToString(arguments, 0);
+    var find = ArgToString(arguments, 1);
+    var replaceWith = ArgToString(arguments, 2);
+    var result = text.Replace(find, replaceWith);
+    return CreateResult(result, DataType.String);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/T.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/T.cs
new file mode 100644
index 0000000..cf6e23f
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/T.cs
@@ -0,0 +1,42 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class T : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var val = arguments.ElementAt(0).ValueFirst;
+    if (val is string) {
+      return CreateResult(val, DataType.String);
+    }
+    return CreateResult(string.Empty, DataType.String);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Text.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Text.cs
new file mode 100644
index 0000000..2116a91
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Text.cs
@@ -0,0 +1,48 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Jan Källman   		            Added		                2014-01-17
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Text : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 2);
+    var value = arguments.First().ValueFirst;
+    var format = ArgToString(arguments, 1);
+    format = format.Replace(CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator, ".");
+    format = format.Replace(
+        CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator.Replace((char)160, ' '),
+        ","); //Special handling for No-Break Space
+
+    var result = context.ExcelDataProvider.GetFormat(value, format);
+
+    return CreateResult(result, DataType.String);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Upper.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Upper.cs
new file mode 100644
index 0000000..e7fa69b
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Upper.cs
@@ -0,0 +1,38 @@
+/* Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Mats Alm   		                Added		                2013-12-03
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class Upper : ExcelFunction {
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    return CreateResult(arguments.First().ValueFirst.ToString().ToUpper(), DataType.String);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Value.cs b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Value.cs
new file mode 100644
index 0000000..5faebe7
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Functions/Text/Value.cs
@@ -0,0 +1,56 @@
+using System.Collections.Generic;
+using System.Globalization;
+using System.Text.RegularExpressions;
+
+namespace AppsheetEpplus;
+
+public class Value : ExcelFunction {
+  private readonly string _groupSeparator = CultureInfo
+      .CurrentCulture
+      .NumberFormat
+      .NumberGroupSeparator;
+  private readonly string _decimalSeparator = CultureInfo
+      .CurrentCulture
+      .NumberFormat
+      .NumberDecimalSeparator;
+  private readonly string _timeSeparator = CultureInfo.CurrentCulture.DateTimeFormat.TimeSeparator;
+  private readonly DateValue _dateValueFunc = new();
+  private readonly TimeValue _timeValueFunc = new();
+
+  public override CompileResult Execute(
+      IEnumerable<FunctionArgument> arguments,
+      ParsingContext context) {
+    ValidateArguments(arguments, 1);
+    var val = ArgToString(arguments, 0).TrimEnd(' ');
+    double result;
+    if (Regex.IsMatch(
+        val,
+        $"^[\\d]*({Regex.Escape(_groupSeparator)}?[\\d]*)?({Regex.Escape(_decimalSeparator)
+        }[\\d]*)?[ ?% ?]?$")) {
+      if (val.EndsWith("%")) {
+        val = val.TrimEnd('%');
+        result = double.Parse(val) / 100;
+      } else {
+        result = double.Parse(val);
+      }
+      return CreateResult(result, DataType.Decimal);
+    }
+    if (double.TryParse(val, NumberStyles.Float, CultureInfo.CurrentCulture, out result)) {
+      return CreateResult(result, DataType.Decimal);
+    }
+    var timeSeparator = Regex.Escape(_timeSeparator);
+    if (Regex.IsMatch(
+        val,
+        @"^[\d]{1,2}" + timeSeparator + @"[\d]{2}(" + timeSeparator + @"[\d]{2})?$")) {
+      var timeResult = _timeValueFunc.Execute(val);
+      if (timeResult.DataType == DataType.Date) {
+        return timeResult;
+      }
+    }
+    var dateResult = _dateValueFunc.Execute(val);
+    if (dateResult.DataType == DataType.Date) {
+      return dateResult;
+    }
+    return CreateResult(ExcelErrorValue.Create(eErrorType.Value), DataType.ExcelError);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Operators/IOperator.cs b/AppsheetEpplus/FormulaParsing/Excel/Operators/IOperator.cs
new file mode 100644
index 0000000..d5e8e86
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Operators/IOperator.cs
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+public interface IOperator {
+  Operators Operator { get; }
+
+  CompileResult Apply(CompileResult left, CompileResult right);
+
+  int Precedence { get; }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Operators/Operator.cs b/AppsheetEpplus/FormulaParsing/Excel/Operators/Operator.cs
new file mode 100644
index 0000000..0f8626c
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Operators/Operator.cs
@@ -0,0 +1,388 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System;
+
+namespace AppsheetEpplus;
+
+public class Operator : IOperator {
+  private const int _precedencePercent = 2;
+  private const int _precedenceExp = 4;
+  private const int _precedenceMultiplyDevide = 6;
+  private const int _precedenceAddSubtract = 12;
+  private const int _precedenceConcat = 15;
+  private const int _precedenceComparison = 25;
+
+  private Operator(
+      Operators @operator,
+      int precedence,
+      Func<CompileResult, CompileResult, CompileResult> implementation) {
+    _implementation = implementation;
+    _precedence = precedence;
+    _operator = @operator;
+  }
+
+  private readonly Func<CompileResult, CompileResult, CompileResult> _implementation;
+  private readonly int _precedence;
+  private readonly Operators _operator;
+
+  int IOperator.Precedence => _precedence;
+
+  Operators IOperator.Operator => _operator;
+
+  public CompileResult Apply(CompileResult left, CompileResult right) {
+    if (left.Result is ExcelErrorValue) {
+      return new(left.Result, DataType.ExcelError);
+      //throw(new ExcelErrorValueException((ExcelErrorValue)left.Result));
+    }
+    if (right.Result is ExcelErrorValue) {
+      return new(right.Result, DataType.ExcelError);
+      //throw(new ExcelErrorValueException((ExcelErrorValue)right.Result));
+    }
+    return _implementation(left, right);
+  }
+
+  public override string ToString() {
+    return "Operator: " + _operator;
+  }
+
+  private static IOperator _plus;
+
+  public static IOperator Plus {
+    get {
+      return _plus
+          ?? (_plus = new Operator(
+                  Operators.Plus,
+                  _precedenceAddSubtract,
+                  (l, r) => {
+                    l = l == null || l.Result == null ? new(0, DataType.Integer) : l;
+                    r = r == null || r.Result == null ? new(0, DataType.Integer) : r;
+                    if (EitherIsError(l, r, out var errorVal)) {
+                      return new(errorVal);
+                    }
+                    if (l.DataType == DataType.Integer && r.DataType == DataType.Integer) {
+                      return new(l.ResultNumeric + r.ResultNumeric, DataType.Integer);
+                    }
+                    if ((l.IsNumeric
+                                || l.IsNumericString
+                                || l.Result is ExcelDataProvider.IRangeInfo)
+                        && (r.IsNumeric
+                                || r.IsNumericString
+                                || r.Result is ExcelDataProvider.IRangeInfo)) {
+                      return new(l.ResultNumeric + r.ResultNumeric, DataType.Decimal);
+                    }
+                    return new(eErrorType.Value);
+                  }));
+    }
+  }
+
+  private static IOperator _minus;
+
+  public static IOperator Minus {
+    get {
+      return _minus
+          ?? (_minus = new Operator(
+                  Operators.Minus,
+                  _precedenceAddSubtract,
+                  (l, r) => {
+                    l = l == null || l.Result == null ? new(0, DataType.Integer) : l;
+                    r = r == null || r.Result == null ? new(0, DataType.Integer) : r;
+                    if (l.DataType == DataType.Integer && r.DataType == DataType.Integer) {
+                      return new(l.ResultNumeric - r.ResultNumeric, DataType.Integer);
+                    }
+                    if ((l.IsNumeric
+                                || l.IsNumericString
+                                || l.Result is ExcelDataProvider.IRangeInfo)
+                        && (r.IsNumeric
+                                || r.IsNumericString
+                                || r.Result is ExcelDataProvider.IRangeInfo)) {
+                      return new(l.ResultNumeric - r.ResultNumeric, DataType.Decimal);
+                    }
+
+                    return new(eErrorType.Value);
+                  }));
+    }
+  }
+
+  private static IOperator _multiply;
+
+  public static IOperator Multiply {
+    get {
+      return _multiply
+          ?? (_multiply = new Operator(
+                  Operators.Multiply,
+                  _precedenceMultiplyDevide,
+                  (l, r) => {
+                    l = l ?? new CompileResult(0, DataType.Integer);
+                    r = r ?? new CompileResult(0, DataType.Integer);
+                    if (l.DataType == DataType.Integer && r.DataType == DataType.Integer) {
+                      return new(l.ResultNumeric * r.ResultNumeric, DataType.Integer);
+                    }
+                    if ((l.IsNumeric
+                                || l.IsNumericString
+                                || l.Result is ExcelDataProvider.IRangeInfo)
+                        && (r.IsNumeric
+                                || r.IsNumericString
+                                || r.Result is ExcelDataProvider.IRangeInfo)) {
+                      return new(l.ResultNumeric * r.ResultNumeric, DataType.Decimal);
+                    }
+                    return new(eErrorType.Value);
+                  }));
+    }
+  }
+
+  private static IOperator _divide;
+
+  public static IOperator Divide {
+    get {
+      return _divide
+          ?? (_divide = new Operator(
+                  Operators.Divide,
+                  _precedenceMultiplyDevide,
+                  (l, r) => {
+                    if (!(l.IsNumeric
+                                || l.IsNumericString
+                                || l.Result is ExcelDataProvider.IRangeInfo)
+                        || !(r.IsNumeric
+                                || r.IsNumericString
+                                || r.Result is ExcelDataProvider.IRangeInfo)) {
+                      return new(eErrorType.Value);
+                    }
+                    var left = l.ResultNumeric;
+                    var right = r.ResultNumeric;
+                    if (Math.Abs(right - 0d) < double.Epsilon) {
+                      return new(eErrorType.Div0);
+                    }
+                    if ((l.IsNumeric
+                                || l.IsNumericString
+                                || l.Result is ExcelDataProvider.IRangeInfo)
+                        && (r.IsNumeric
+                                || r.IsNumericString
+                                || r.Result is ExcelDataProvider.IRangeInfo)) {
+                      return new(left / right, DataType.Decimal);
+                    }
+                    return new(eErrorType.Value);
+                  }));
+    }
+  }
+
+  public static IOperator Exp {
+    get {
+      return new Operator(
+          Operators.Exponentiation,
+          _precedenceExp,
+          (l, r) => {
+            if (l == null && r == null) {
+              return new(eErrorType.Value);
+            }
+            l = l ?? new CompileResult(0, DataType.Integer);
+            r = r ?? new CompileResult(0, DataType.Integer);
+            if ((l.IsNumeric || l.Result is ExcelDataProvider.IRangeInfo)
+                && (r.IsNumeric || r.Result is ExcelDataProvider.IRangeInfo)) {
+              return new(Math.Pow(l.ResultNumeric, r.ResultNumeric), DataType.Decimal);
+            }
+            return new(0d, DataType.Decimal);
+          });
+    }
+  }
+
+  public static IOperator Concat {
+    get {
+      return new Operator(
+          Operators.Concat,
+          _precedenceConcat,
+          (l, r) => {
+            l = l ?? new CompileResult(string.Empty, DataType.String);
+            r = r ?? new CompileResult(string.Empty, DataType.String);
+            var lStr = l.Result != null ? l.ResultValue.ToString() : string.Empty;
+            var rStr = r.Result != null ? r.ResultValue.ToString() : string.Empty;
+            return new(string.Concat(lStr, rStr), DataType.String);
+          });
+    }
+  }
+
+  private static IOperator _greaterThan;
+
+  public static IOperator GreaterThan {
+    get {
+      //return new Operator(Operators.GreaterThan, PrecedenceComparison, (l, r) => new CompileResult(Compare(l, r) > 0, DataType.Boolean));
+      return _greaterThan
+          ?? (_greaterThan = new Operator(
+                  Operators.LessThanOrEqual,
+                  _precedenceComparison,
+                  (l, r) => Compare(l, r, compRes => compRes > 0)));
+    }
+  }
+
+  private static IOperator _eq;
+
+  public static IOperator Eq {
+    get {
+      //return new Operator(Operators.Equals, PrecedenceComparison, (l, r) => new CompileResult(Compare(l, r) == 0, DataType.Boolean));
+      return _eq
+          ?? (_eq = new Operator(
+                  Operators.LessThanOrEqual,
+                  _precedenceComparison,
+                  (l, r) => Compare(l, r, compRes => compRes == 0)));
+    }
+  }
+
+  private static IOperator _notEqualsTo;
+
+  public static IOperator NotEqualsTo {
+    get {
+      //return new Operator(Operators.NotEqualTo, PrecedenceComparison, (l, r) => new CompileResult(Compare(l, r) != 0, DataType.Boolean));
+      return _notEqualsTo
+          ?? (_notEqualsTo = new Operator(
+                  Operators.LessThanOrEqual,
+                  _precedenceComparison,
+                  (l, r) => Compare(l, r, compRes => compRes != 0)));
+    }
+  }
+
+  private static IOperator _greaterThanOrEqual;
+
+  public static IOperator GreaterThanOrEqual {
+    get {
+      //return new Operator(Operators.GreaterThanOrEqual, PrecedenceComparison, (l, r) => new CompileResult(Compare(l, r) >= 0, DataType.Boolean));
+      return _greaterThanOrEqual
+          ?? (_greaterThanOrEqual = new Operator(
+                  Operators.LessThanOrEqual,
+                  _precedenceComparison,
+                  (l, r) => Compare(l, r, compRes => compRes >= 0)));
+    }
+  }
+
+  private static IOperator _lessThan;
+
+  public static IOperator LessThan {
+    get {
+      //return new Operator(Operators.LessThan, PrecedenceComparison, (l, r) => new CompileResult(Compare(l, r) < 0, DataType.Boolean));
+      return _lessThan
+          ?? (_lessThan = new Operator(
+                  Operators.LessThanOrEqual,
+                  _precedenceComparison,
+                  (l, r) => Compare(l, r, compRes => compRes < 0)));
+    }
+  }
+
+  public static IOperator LessThanOrEqual {
+    get {
+      //return new Operator(Operators.LessThanOrEqual, PrecedenceComparison, (l, r) => new CompileResult(Compare(l, r) <= 0, DataType.Boolean));
+      return new Operator(
+          Operators.LessThanOrEqual,
+          _precedenceComparison,
+          (l, r) => Compare(l, r, compRes => compRes <= 0));
+    }
+  }
+
+  private static IOperator _percent;
+
+  public static IOperator Percent {
+    get {
+      if (_percent == null) {
+        _percent = new Operator(
+            Operators.Percent,
+            _precedencePercent,
+            (l, r) => {
+              l = l ?? new CompileResult(0, DataType.Integer);
+              r = r ?? new CompileResult(0, DataType.Integer);
+              if (l.DataType == DataType.Integer && r.DataType == DataType.Integer) {
+                return new(l.ResultNumeric * r.ResultNumeric, DataType.Integer);
+              }
+              if ((l.IsNumeric || l.Result is ExcelDataProvider.IRangeInfo)
+                  && (r.IsNumeric || r.Result is ExcelDataProvider.IRangeInfo)) {
+                return new(l.ResultNumeric * r.ResultNumeric, DataType.Decimal);
+              }
+              return new(eErrorType.Value);
+            });
+      }
+      return _percent;
+    }
+  }
+
+  private static object GetObjFromOther(CompileResult obj, CompileResult other) {
+    if (obj.Result == null) {
+      if (other.DataType == DataType.String) {
+        return string.Empty;
+      }
+      return 0d;
+    }
+    return obj.ResultValue;
+  }
+
+  private static CompileResult Compare(
+      CompileResult l,
+      CompileResult r,
+      Func<int, bool> comparison) {
+    if (EitherIsError(l, r, out var errorVal)) {
+      return new(errorVal);
+    }
+    object left,
+        right;
+    left = GetObjFromOther(l, r);
+    right = GetObjFromOther(r, l);
+    if (ConvertUtil.IsNumeric(left) && ConvertUtil.IsNumeric(right)) {
+      var lnum = ConvertUtil.GetValueDouble(left);
+      var rnum = ConvertUtil.GetValueDouble(right);
+      if (Math.Abs(lnum - rnum) < double.Epsilon) {
+        return new(comparison(0), DataType.Boolean);
+      }
+      var comparisonResult = lnum.CompareTo(rnum);
+      return new(comparison(comparisonResult), DataType.Boolean);
+    } else {
+      var comparisonResult = CompareString(left, right);
+      return new(comparison(comparisonResult), DataType.Boolean);
+    }
+  }
+
+  private static int CompareString(object l, object r) {
+    var sl = (l ?? "").ToString();
+    var sr = (r ?? "").ToString();
+    return String.Compare(sl, sr, StringComparison.Ordinal);
+  }
+
+  private static bool EitherIsError(
+      CompileResult l,
+      CompileResult r,
+      out ExcelErrorValue errorVal) {
+    if (l.DataType == DataType.ExcelError) {
+      errorVal = (ExcelErrorValue)l.Result;
+      return true;
+    }
+    if (r.DataType == DataType.ExcelError) {
+      errorVal = (ExcelErrorValue)r.Result;
+      return true;
+    }
+    errorVal = null;
+    return false;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Operators/Operators.cs b/AppsheetEpplus/FormulaParsing/Excel/Operators/Operators.cs
new file mode 100644
index 0000000..cd26312
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Operators/Operators.cs
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public enum Operators {
+  Undefined,
+  Concat,
+  Plus,
+  Minus,
+  Multiply,
+  Divide,
+  Modulus,
+  Percent,
+  Equals,
+  GreaterThan,
+  GreaterThanOrEqual,
+  LessThan,
+  LessThanOrEqual,
+  NotEqualTo,
+  IntegerDivision,
+  Exponentiation,
+}
diff --git a/AppsheetEpplus/FormulaParsing/Excel/Operators/OperatorsDict.cs b/AppsheetEpplus/FormulaParsing/Excel/Operators/OperatorsDict.cs
new file mode 100644
index 0000000..9b063f6
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Excel/Operators/OperatorsDict.cs
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class OperatorsDict : Dictionary<string, IOperator> {
+  public OperatorsDict() {
+    Add("+", Operator.Plus);
+    Add("-", Operator.Minus);
+    Add("*", Operator.Multiply);
+    Add("/", Operator.Divide);
+    Add("^", Operator.Exp);
+    Add("=", Operator.Eq);
+    Add(">", Operator.GreaterThan);
+    Add(">=", Operator.GreaterThanOrEqual);
+    Add("<", Operator.LessThan);
+    Add("<=", Operator.LessThanOrEqual);
+    Add("<>", Operator.NotEqualsTo);
+    Add("&", Operator.Concat);
+  }
+
+  private static IDictionary<string, IOperator> _instance;
+
+  public static IDictionary<string, IOperator> Instance {
+    get {
+      if (_instance == null) {
+        _instance = new OperatorsDict();
+      }
+      return _instance;
+    }
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExcelCalculationOption.cs b/AppsheetEpplus/FormulaParsing/ExcelCalculationOption.cs
new file mode 100644
index 0000000..d6d94a7
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExcelCalculationOption.cs
@@ -0,0 +1,5 @@
+namespace AppsheetEpplus;
+
+public class ExcelCalculationOption {
+  public bool AllowCirculareReferences { get; set; } = false;
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExcelDataProvider.cs b/AppsheetEpplus/FormulaParsing/ExcelDataProvider.cs
new file mode 100644
index 0000000..1400caf
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExcelDataProvider.cs
@@ -0,0 +1,152 @@
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// This class should be implemented to be able to deliver excel data
+/// to the formula parser.
+/// </summary>
+public abstract class ExcelDataProvider {
+  /// <summary>
+  /// A range of cells in a worksheet.
+  /// </summary>
+  public interface IRangeInfo : IEnumerator<ICellInfo>, IEnumerable<ICellInfo> {
+    bool IsEmpty { get; }
+
+    bool IsMulti { get; }
+
+    int GetNCells();
+
+    ExcelAddressBase Address { get; }
+
+    object GetValue(int row, int col);
+
+    object GetOffset(int rowOffset, int colOffset);
+
+    ExcelWorksheet Worksheet { get; }
+  }
+
+  /// <summary>
+  /// Information and help methods about a cell
+  /// </summary>
+  public interface ICellInfo {
+    string Address { get; }
+
+    int Row { get; }
+
+    int Column { get; }
+
+    string Formula { get; }
+
+    object Value { get; }
+
+    double ValueDouble { get; }
+
+    double ValueDoubleLogical { get; }
+
+    bool IsHiddenRow { get; }
+
+    bool IsExcelError { get; }
+
+    IList<Token> Tokens { get; }
+  }
+
+  public interface INameInfo {
+    ulong Id { get; set; }
+
+    string Worksheet { get; set; }
+
+    string Name { get; set; }
+
+    string Formula { get; set; }
+
+    IList<Token> Tokens { get; }
+
+    object Value { get; set; }
+  }
+
+  /// <summary>
+  /// Returns the names of all worksheet names
+  /// </summary>
+  /// <returns></returns>
+  public abstract ExcelNamedRangeCollection GetWorksheetNames(string worksheet);
+
+  /// <summary>
+  /// Returns all defined names in a workbook
+  /// </summary>
+  /// <returns></returns>
+  public abstract ExcelNamedRangeCollection GetWorkbookNameValues();
+
+  /// <summary>
+  /// Returns values from the required range.
+  /// </summary>
+  /// <param name="worksheetName">The name of the worksheet</param>
+  /// <param name="row">Row</param>
+  /// <param name="column">Column</param>
+  /// <param name="address">The reference address</param>
+  /// <returns></returns>
+  public abstract IRangeInfo GetRange(string worksheetName, int row, int column, string address);
+
+  public abstract INameInfo GetName(string worksheet, string name);
+
+  public abstract IEnumerable<object> GetRangeValues(string address);
+
+  public abstract string GetRangeFormula(string worksheetName, int row, int column);
+
+  public abstract List<Token> GetRangeFormulaTokens(string worksheetName, int row, int column);
+
+  public abstract bool IsRowHidden(string worksheetName, int row);
+
+  ///// <summary>
+  ///// Returns a single cell value
+  ///// </summary>
+  ///// <param name="address"></param>
+  ///// <returns></returns>
+  //public abstract object GetCellValue(int sheetID, string address);
+
+  /// <summary>
+  /// Returns a single cell value
+  /// </summary>
+  /// <param name="sheetName"></param>
+  /// <param name="row"></param>
+  /// <param name="col"></param>
+  /// <returns></returns>
+  public abstract object GetCellValue(string sheetName, int row, int col);
+
+  ///// <summary>
+  ///// Sets the value on the cell
+  ///// </summary>
+  ///// <param name="address"></param>
+  ///// <param name="value"></param>
+  //public abstract void SetCellValue(string address, object value);
+
+  /// <summary>
+  /// Returns the address of the lowest rightmost cell on the worksheet.
+  /// </summary>
+  /// <param name="worksheet"></param>
+  /// <returns></returns>
+  public abstract ExcelCellAddress GetDimensionEnd(string worksheet);
+
+  /// <summary>
+  /// Max number of columns in a worksheet that the Excel data provider can handle.
+  /// </summary>
+  public abstract int ExcelMaxColumns { get; }
+
+  /// <summary>
+  /// Max number of rows in a worksheet that the Excel data provider can handle
+  /// </summary>
+  public abstract int ExcelMaxRows { get; }
+
+  public abstract object GetRangeValue(string worksheetName, int row, int column);
+
+  public abstract string GetFormat(object value, string format);
+
+  public abstract void Reset();
+
+  public abstract IRangeInfo GetRange(
+      string worksheet,
+      int fromRow,
+      int fromCol,
+      int toRow,
+      int toCol);
+}
diff --git a/EPPlus/FormulaParsing/ExcelDataProvider.cs.orig b/AppsheetEpplus/FormulaParsing/ExcelDataProvider.cs.orig
similarity index 100%
rename from EPPlus/FormulaParsing/ExcelDataProvider.cs.orig
rename to AppsheetEpplus/FormulaParsing/ExcelDataProvider.cs.orig
diff --git a/AppsheetEpplus/FormulaParsing/ExcelUtilities/AddressTranslator.cs b/AppsheetEpplus/FormulaParsing/ExcelUtilities/AddressTranslator.cs
new file mode 100644
index 0000000..70e548e
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExcelUtilities/AddressTranslator.cs
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Globalization;
+using System.Text.RegularExpressions;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Handles translations from Spreadsheet addresses to 0-based numeric index.
+/// </summary>
+public class AddressTranslator {
+  public enum RangeCalculationBehaviour {
+    FirstPart,
+    LastPart,
+  }
+
+  private readonly ExcelDataProvider _excelDataProvider;
+
+  public AddressTranslator(ExcelDataProvider excelDataProvider) {
+    Require.That(excelDataProvider).Named("excelDataProvider").IsNotNull();
+    _excelDataProvider = excelDataProvider;
+  }
+
+  /// <summary>
+  /// Translates an address in format "A1" to col- and rowindex.
+  ///
+  /// If the supplied address is a range, the address of the first part will be calculated.
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="col"></param>
+  /// <param name="row"></param>
+  public virtual void ToColAndRow(string address, out int col, out int row) {
+    ToColAndRow(address, out col, out row, RangeCalculationBehaviour.FirstPart);
+  }
+
+  /// <summary>
+  /// Translates an address in format "A1" to col- and rowindex.
+  /// </summary>
+  /// <param name="address"></param>
+  /// <param name="col"></param>
+  /// <param name="row"></param>
+  /// <param name="behaviour"></param>
+  public virtual void ToColAndRow(
+      string address,
+      out int col,
+      out int row,
+      RangeCalculationBehaviour behaviour) {
+    address = address.ToUpper(CultureInfo.InvariantCulture);
+    var alphaPart = GetAlphaPart(address);
+    col = 0;
+    var nLettersInAlphabet = 26;
+    for (int x = 0; x < alphaPart.Length; x++) {
+      var pos = alphaPart.Length - x - 1;
+      var currentNumericValue = GetNumericAlphaValue(alphaPart[x]);
+      col += (nLettersInAlphabet * pos * currentNumericValue);
+      if (pos == 0) {
+        col += currentNumericValue;
+      }
+    }
+    //col--;
+    //row = GetIntPart(address) - 1 ?? GetRowIndexByBehaviour(behaviour);
+    row = GetIntPart(address) ?? GetRowIndexByBehaviour(behaviour);
+  }
+
+  private int GetRowIndexByBehaviour(RangeCalculationBehaviour behaviour) {
+    if (behaviour == RangeCalculationBehaviour.FirstPart) {
+      return 1;
+    }
+    return _excelDataProvider.ExcelMaxRows;
+  }
+
+  private int GetNumericAlphaValue(char c) {
+    return c - 64;
+  }
+
+  private string GetAlphaPart(string address) {
+    return Regex.Match(address, "[A-Z]+").Value;
+  }
+
+  private int? GetIntPart(string address) {
+    if (Regex.IsMatch(address, "[0-9]+")) {
+      return int.Parse(Regex.Match(address, "[0-9]+").Value);
+    }
+    return null;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExcelUtilities/CellReferenceProvider.cs b/AppsheetEpplus/FormulaParsing/ExcelUtilities/CellReferenceProvider.cs
new file mode 100644
index 0000000..071c43a
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExcelUtilities/CellReferenceProvider.cs
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class CellReferenceProvider {
+  public virtual IEnumerable<string> GetReferencedAddresses(
+      string cellFormula,
+      ParsingContext context) {
+    var resultCells = new List<string>();
+    var r = context.Configuration.Lexer.Tokenize(
+        cellFormula,
+        context.Scopes.Current.Address.Worksheet);
+    var toAddresses = r.Where(x => x.TokenType == TokenType.ExcelAddress);
+    foreach (var toAddress in toAddresses) {
+      var rangeAddress = context.RangeAddressFactory.Create(toAddress.Value);
+      var rangeCells = new List<string>();
+      if (rangeAddress.FromRow < rangeAddress.ToRow || rangeAddress.FromCol < rangeAddress.ToCol) {
+        for (var col = rangeAddress.FromCol; col <= rangeAddress.ToCol; col++) {
+          for (var row = rangeAddress.FromRow; row <= rangeAddress.ToRow; row++) {
+            resultCells.Add(context.RangeAddressFactory.Create(col, row).Address);
+          }
+        }
+      } else {
+        rangeCells.Add(toAddress.Value);
+      }
+      resultCells.AddRange(rangeCells);
+    }
+    return resultCells;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExcelUtilities/ExcelAddressInfo.cs b/AppsheetEpplus/FormulaParsing/ExcelUtilities/ExcelAddressInfo.cs
new file mode 100644
index 0000000..e481f4c
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExcelUtilities/ExcelAddressInfo.cs
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+public class ExcelAddressInfo {
+  private ExcelAddressInfo(string address) {
+    var addressOnSheet = address;
+    if (address.Contains("!")) {
+      var worksheetArr = address.Split('!');
+      Worksheet = worksheetArr[0];
+      addressOnSheet = worksheetArr[1];
+    }
+    if (addressOnSheet.Contains(":")) {
+      var rangeArr = addressOnSheet.Split(':');
+      StartCell = rangeArr[0];
+      EndCell = rangeArr[1];
+    } else {
+      StartCell = addressOnSheet;
+    }
+    AddressOnSheet = addressOnSheet;
+  }
+
+  public static ExcelAddressInfo Parse(string address) {
+    Require.That(address).Named("address").IsNotNullOrEmpty();
+    return new(address);
+  }
+
+  public string Worksheet { get; private set; } = string.Empty;
+
+  public bool WorksheetIsSpecified => !string.IsNullOrEmpty(Worksheet);
+
+  public bool IsMultipleCells => !string.IsNullOrEmpty(EndCell);
+
+  public string StartCell { get; private set; }
+
+  public string EndCell { get; private set; }
+
+  public string AddressOnSheet { get; private set; }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExcelUtilities/ExcelAddressUtil.cs b/AppsheetEpplus/FormulaParsing/ExcelUtilities/ExcelAddressUtil.cs
new file mode 100644
index 0000000..6fd5fe6
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExcelUtilities/ExcelAddressUtil.cs
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public static class ExcelAddressUtil {
+  private static readonly char[] SheetNameInvalidChars = ['?', ':', '*', '/', '\\'];
+
+  public static bool IsValidAddress(string token) {
+    int ix;
+    if (token[0] == '\'') {
+      ix = token.LastIndexOf('\'');
+      if (ix > 0 && ix < token.Length - 1 && token[ix + 1] == '!') {
+        if (token.IndexOfAny(SheetNameInvalidChars, 1, ix - 1) > 0) {
+          return false;
+        }
+        token = token.Substring(ix + 2);
+      } else {
+        return false;
+      }
+    } else if ((ix = token.IndexOf('!')) > 1) {
+      if (token.IndexOfAny(SheetNameInvalidChars, 0, token.IndexOf('!')) > 0) {
+        return false;
+      }
+      token = token.Substring(token.IndexOf('!') + 1);
+    }
+    return ExcelCellBase.IsValidAddress(token);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExcelUtilities/ExcelReferenceType.cs b/AppsheetEpplus/FormulaParsing/ExcelUtilities/ExcelReferenceType.cs
new file mode 100644
index 0000000..0b33171
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExcelUtilities/ExcelReferenceType.cs
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public enum ExcelReferenceType {
+  AbsoluteRowAndColumn = 1,
+  AbsoluteRowRelativeColumn = 2,
+  RelativeRowAbsolutColumn = 3,
+  RelativeRowAndColumn = 4,
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExcelUtilities/ExpressionEvaluator.cs b/AppsheetEpplus/FormulaParsing/ExcelUtilities/ExpressionEvaluator.cs
new file mode 100644
index 0000000..3377ef6
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExcelUtilities/ExpressionEvaluator.cs
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System;
+using System.Text.RegularExpressions;
+
+namespace AppsheetEpplus;
+
+public class ExpressionEvaluator {
+  private readonly WildCardValueMatcher _wildCardValueMatcher;
+  private readonly CompileResultFactory _compileResultFactory;
+
+  public ExpressionEvaluator()
+      : this(new(), new()) {}
+
+  public ExpressionEvaluator(
+      WildCardValueMatcher wildCardValueMatcher,
+      CompileResultFactory compileResultFactory) {
+    _wildCardValueMatcher = wildCardValueMatcher;
+    _compileResultFactory = compileResultFactory;
+  }
+
+  private string GetNonAlphanumericStartChars(string expression) {
+    if (!string.IsNullOrEmpty(expression)) {
+      if (Regex.IsMatch(expression, "^([^a-zA-Z0-9]{2})")) {
+        return expression.Substring(0, 2);
+      }
+      if (Regex.IsMatch(expression, "^([^a-zA-Z0-9]{1})")) {
+        return expression.Substring(0, 1);
+      }
+    }
+    return null;
+  }
+
+  private bool EvaluateOperator(object left, object right, IOperator op) {
+    var leftResult = _compileResultFactory.Create(left);
+    var rightResult = _compileResultFactory.Create(right);
+    var result = op.Apply(leftResult, rightResult);
+    if (result.DataType != DataType.Boolean) {
+      throw new ArgumentException("Illegal operator in expression");
+    }
+    return (bool)result.Result;
+  }
+
+  public bool TryConvertToDouble(object op, out double d) {
+    if (op is double || op is int) {
+      d = Convert.ToDouble(op);
+      return true;
+    }
+    if (op is DateTime time) {
+      d = time.ToOADate();
+      return true;
+    }
+    if (op != null) {
+      if (double.TryParse(op.ToString(), out d)) {
+        return true;
+      }
+    }
+    d = 0;
+    return false;
+  }
+
+  public bool Evaluate(object left, string expression) {
+    if (expression == string.Empty) {
+      return left == null;
+    }
+    var operatorCandidate = GetNonAlphanumericStartChars(expression);
+    if (!string.IsNullOrEmpty(operatorCandidate) && operatorCandidate != "-") {
+      if (OperatorsDict.Instance.TryGetValue(operatorCandidate, out var op)) {
+        var right = expression.Replace(operatorCandidate, string.Empty);
+        if (left == null && right == string.Empty) {
+          return op.Operator == Operators.Equals;
+        }
+        if (left == null ^ right == string.Empty) {
+          return op.Operator == Operators.NotEqualTo;
+        }
+        bool leftIsNumeric = TryConvertToDouble(left, out var leftNum);
+        bool rightIsNumeric = double.TryParse(right, out var rightNum);
+        bool rightIsDate = DateTime.TryParse(right, out var date);
+        if (leftIsNumeric && rightIsNumeric) {
+          return EvaluateOperator(leftNum, rightNum, op);
+        }
+        if (leftIsNumeric && rightIsDate) {
+          return EvaluateOperator(leftNum, date.ToOADate(), op);
+        }
+        if (leftIsNumeric != rightIsNumeric) {
+          return op.Operator == Operators.NotEqualTo;
+        }
+        return EvaluateOperator(left, right, op);
+      }
+    }
+    return _wildCardValueMatcher.IsMatch(expression, left) == 0;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExcelUtilities/FormulaDependencies.cs b/AppsheetEpplus/FormulaParsing/ExcelUtilities/FormulaDependencies.cs
new file mode 100644
index 0000000..1e41ab7
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExcelUtilities/FormulaDependencies.cs
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class FormulaDependencies {
+  public FormulaDependencies()
+      : this(new()) {}
+
+  public FormulaDependencies(FormulaDependencyFactory formulaDependencyFactory) {
+    _formulaDependencyFactory = formulaDependencyFactory;
+  }
+
+  private readonly FormulaDependencyFactory _formulaDependencyFactory;
+  private readonly Dictionary<string, FormulaDependency> _dependencies = new();
+
+  public IEnumerable<KeyValuePair<string, FormulaDependency>> Dependencies => _dependencies;
+
+  public void AddFormulaScope(ParsingScope parsingScope) {
+    //var dependency = _formulaDependencyFactory.Create(parsingScope);
+    //var address = parsingScope.Address.ToString();
+    //if (!_dependencies.ContainsKey(address))
+    //{
+    //    _dependencies.Add(address, dependency);
+    //}
+    //if (parsingScope.Parent != null)
+    //{
+    //    var parentAddress = parsingScope.Parent.Address.ToString();
+    //    if (_dependencies.ContainsKey(parentAddress))
+    //    {
+    //        var parent = _dependencies[parentAddress];
+    //        parent.AddReferenceTo(parsingScope.Address);
+    //        dependency.AddReferenceFrom(parent.Address);
+    //    }
+    //}
+  }
+
+  public void Clear() {
+    _dependencies.Clear();
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExcelUtilities/FormulaDependency.cs b/AppsheetEpplus/FormulaParsing/ExcelUtilities/FormulaDependency.cs
new file mode 100644
index 0000000..8c5d9cc
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExcelUtilities/FormulaDependency.cs
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class FormulaDependency {
+  public FormulaDependency(ParsingScope scope) {
+    ScopeId = scope.ScopeId;
+    Address = scope.Address;
+  }
+
+  public Guid ScopeId { get; private set; }
+
+  public RangeAddress Address { get; private set; }
+
+  private readonly List<RangeAddress> _referencedBy = new();
+
+  private readonly List<RangeAddress> _references = new();
+
+  public virtual void AddReferenceFrom(RangeAddress rangeAddress) {
+    if (Address.CollidesWith(rangeAddress)
+        || _references.Exists(x => x.CollidesWith(rangeAddress))) {
+      throw new CircularReferenceException("Circular reference detected at " + rangeAddress);
+    }
+    _referencedBy.Add(rangeAddress);
+  }
+
+  public virtual void AddReferenceTo(RangeAddress rangeAddress) {
+    if (Address.CollidesWith(rangeAddress)
+        || _referencedBy.Exists(x => x.CollidesWith(rangeAddress))) {
+      throw new CircularReferenceException("Circular reference detected at " + rangeAddress);
+    }
+    _references.Add(rangeAddress);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExcelUtilities/FormulaDependencyFactory.cs b/AppsheetEpplus/FormulaParsing/ExcelUtilities/FormulaDependencyFactory.cs
new file mode 100644
index 0000000..54bc1c5
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExcelUtilities/FormulaDependencyFactory.cs
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public class FormulaDependencyFactory {
+  public virtual FormulaDependency Create(ParsingScope scope) {
+    return new(scope);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExcelUtilities/IndexToAddressTranslator.cs b/AppsheetEpplus/FormulaParsing/ExcelUtilities/IndexToAddressTranslator.cs
new file mode 100644
index 0000000..5f702e9
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExcelUtilities/IndexToAddressTranslator.cs
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+public class IndexToAddressTranslator {
+  public IndexToAddressTranslator(ExcelDataProvider excelDataProvider)
+      : this(excelDataProvider, ExcelReferenceType.AbsoluteRowAndColumn) {}
+
+  public IndexToAddressTranslator(
+      ExcelDataProvider excelDataProvider,
+      ExcelReferenceType referenceType) {
+    Require.That(excelDataProvider).Named("excelDataProvider").IsNotNull();
+    _excelDataProvider = excelDataProvider;
+    _excelReferenceType = referenceType;
+  }
+
+  private readonly ExcelDataProvider _excelDataProvider;
+  private readonly ExcelReferenceType _excelReferenceType;
+
+  protected internal static string GetColumnLetter(int iColumnNumber, bool fixedCol) {
+    if (iColumnNumber < 1) {
+      //throw new Exception("Column number is out of range");
+      return "#REF!";
+    }
+
+    string sCol = "";
+    do {
+      sCol = ((char)('A' + ((iColumnNumber - 1) % 26))) + sCol;
+      iColumnNumber = (iColumnNumber - ((iColumnNumber - 1) % 26)) / 26;
+    } while (iColumnNumber > 0);
+    return fixedCol ? "$" + sCol : sCol;
+  }
+
+  public string ToAddress(int col, int row) {
+    var fixedCol =
+        _excelReferenceType == ExcelReferenceType.AbsoluteRowAndColumn
+            || _excelReferenceType == ExcelReferenceType.RelativeRowAbsolutColumn;
+    var colString = GetColumnLetter(col, fixedCol);
+    return colString + GetRowNumber(row);
+  }
+
+  private string GetRowNumber(int rowNo) {
+    var retVal = rowNo < (_excelDataProvider.ExcelMaxRows) ? rowNo.ToString() : string.Empty;
+    if (!string.IsNullOrEmpty(retVal)) {
+      switch (_excelReferenceType) {
+        case ExcelReferenceType.AbsoluteRowAndColumn:
+        case ExcelReferenceType.AbsoluteRowRelativeColumn:
+          return "$" + retVal;
+        default:
+          return retVal;
+      }
+    }
+    return retVal;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExcelUtilities/LookupValueMatcher.cs b/AppsheetEpplus/FormulaParsing/ExcelUtilities/LookupValueMatcher.cs
new file mode 100644
index 0000000..b2c8828
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExcelUtilities/LookupValueMatcher.cs
@@ -0,0 +1,7 @@
+namespace AppsheetEpplus;
+
+public class LookupValueMatcher : ValueMatcher {
+  protected override int CompareObjectToString(object o1, string o2) {
+    return IncompatibleOperands;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExcelUtilities/NumericExpressionEvaluator.cs b/AppsheetEpplus/FormulaParsing/ExcelUtilities/NumericExpressionEvaluator.cs
new file mode 100644
index 0000000..2591948
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExcelUtilities/NumericExpressionEvaluator.cs
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System;
+using System.Text.RegularExpressions;
+
+namespace AppsheetEpplus;
+
+public class NumericExpressionEvaluator {
+  private readonly ValueMatcher _valueMatcher;
+  private readonly CompileResultFactory _compileResultFactory;
+
+  public NumericExpressionEvaluator()
+      : this(new(), new()) {}
+
+  public NumericExpressionEvaluator(
+      ValueMatcher valueMatcher,
+      CompileResultFactory compileResultFactory) {
+    _valueMatcher = valueMatcher;
+    _compileResultFactory = compileResultFactory;
+  }
+
+  private string GetNonNumericStartChars(string expression) {
+    if (!string.IsNullOrEmpty(expression)) {
+      if (Regex.IsMatch(expression, @"^([^\d]{2})")) {
+        return expression.Substring(0, 2);
+      }
+      if (Regex.IsMatch(expression, @"^([^\d]{1})")) {
+        return expression.Substring(0, 1);
+      }
+    }
+    return null;
+  }
+
+  public double? OperandAsDouble(object op) {
+    if (op is double || op is int) {
+      return Convert.ToDouble(op);
+    }
+    if (op != null) {
+      if (double.TryParse(op.ToString(), out var output)) {
+        return output;
+      }
+    }
+    return null;
+  }
+
+  public bool Evaluate(object left, string expression) {
+    var operatorCandidate = GetNonNumericStartChars(expression);
+    var leftNum = OperandAsDouble(left);
+    if (!string.IsNullOrEmpty(operatorCandidate) && leftNum != null) {
+      if (OperatorsDict.Instance.TryGetValue(operatorCandidate, out var op)) {
+        var numericCandidate = expression.Replace(operatorCandidate, string.Empty);
+        if (double.TryParse(numericCandidate, out var d)) {
+          var leftResult = _compileResultFactory.Create(leftNum);
+          var rightResult = _compileResultFactory.Create(d);
+          var result = op.Apply(leftResult, rightResult);
+          if (result.DataType != DataType.Boolean) {
+            throw new ArgumentException("Illegal operator in expression");
+          }
+          return (bool)result.Result;
+        }
+      }
+    }
+    return _valueMatcher.IsMatch(left, expression) == 0;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExcelUtilities/RangeAddress.cs b/AppsheetEpplus/FormulaParsing/ExcelUtilities/RangeAddress.cs
new file mode 100644
index 0000000..77e6e89
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExcelUtilities/RangeAddress.cs
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public class RangeAddress {
+  internal string Address { get; set; } = string.Empty;
+
+  public string Worksheet { get; internal set; }
+
+  public int FromCol { get; internal set; }
+
+  public int ToCol { get; internal set; }
+
+  public int FromRow { get; internal set; }
+
+  public int ToRow { get; internal set; }
+
+  public override string ToString() {
+    return Address;
+  }
+
+  private static readonly RangeAddress _empty = new();
+
+  public static RangeAddress Empty => _empty;
+
+  /// <summary>
+  /// Returns true if this range collides (full or partly) with the supplied range
+  /// </summary>
+  /// <param name="other">The range to check</param>
+  /// <returns></returns>
+  public bool CollidesWith(RangeAddress other) {
+    if (other.Worksheet != Worksheet) {
+      return false;
+    }
+    if (other.FromRow > ToRow
+        || other.FromCol > ToCol
+        || FromRow > other.ToRow
+        || FromCol > other.ToCol) {
+      return false;
+    }
+    return true;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExcelUtilities/RangeAddressFactory.cs b/AppsheetEpplus/FormulaParsing/ExcelUtilities/RangeAddressFactory.cs
new file mode 100644
index 0000000..af9362e
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExcelUtilities/RangeAddressFactory.cs
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+public class RangeAddressFactory {
+  private readonly ExcelDataProvider _excelDataProvider;
+  private readonly IndexToAddressTranslator _indexToAddressTranslator;
+
+  public RangeAddressFactory(ExcelDataProvider excelDataProvider)
+      : this(
+          excelDataProvider,
+          new(excelDataProvider),
+          new(excelDataProvider, ExcelReferenceType.RelativeRowAndColumn)) {}
+
+  public RangeAddressFactory(
+      ExcelDataProvider excelDataProvider,
+      AddressTranslator addressTranslator,
+      IndexToAddressTranslator indexToAddressTranslator) {
+    Require.That(excelDataProvider).Named("excelDataProvider").IsNotNull();
+    Require.That(addressTranslator).Named("addressTranslator").IsNotNull();
+    Require.That(indexToAddressTranslator).Named("indexToAddressTranslator").IsNotNull();
+    _excelDataProvider = excelDataProvider;
+    _indexToAddressTranslator = indexToAddressTranslator;
+  }
+
+  public RangeAddress Create(int col, int row) {
+    return Create(string.Empty, col, row);
+  }
+
+  public RangeAddress Create(string worksheetName, int col, int row) {
+    return new() {
+      Address = _indexToAddressTranslator.ToAddress(col, row),
+      Worksheet = worksheetName,
+      FromCol = col,
+      ToCol = col,
+      FromRow = row,
+      ToRow = row,
+    };
+  }
+
+  /// <summary>
+  ///
+  /// </summary>
+  /// <param name="worksheetName">will be used if no worksheet name is specified in <paramref name="address"/></param>
+  /// <param name="address">address of a range</param>
+  /// <returns></returns>
+  public RangeAddress Create(string worksheetName, string address) {
+    Require.That(address).Named("range").IsNotNullOrEmpty();
+    //var addressInfo = ExcelAddressInfo.Parse(address);
+    var adr = new ExcelAddressBase(address);
+    var sheet = string.IsNullOrEmpty(adr.WorkSheet) ? worksheetName : adr.WorkSheet;
+    var dim = _excelDataProvider.GetDimensionEnd(adr.WorkSheet);
+    var rangeAddress = new RangeAddress {
+      Address = adr.Address,
+      Worksheet = sheet,
+      FromRow = adr._fromRow,
+      FromCol = adr._fromCol,
+      ToRow = (dim != null && adr._toRow > dim.Row) ? dim.Row : adr._toRow,
+      ToCol = adr._toCol,
+    };
+    return rangeAddress;
+  }
+
+  public RangeAddress Create(string range) {
+    Require.That(range).Named("range").IsNotNullOrEmpty();
+    //var addressInfo = ExcelAddressInfo.Parse(range);
+    var adr = new ExcelAddressBase(range);
+    var rangeAddress = new RangeAddress {
+      Address = adr.Address,
+      Worksheet = adr.WorkSheet ?? "",
+      FromRow = adr._fromRow,
+      FromCol = adr._fromCol,
+      ToRow = adr._toRow,
+      ToCol = adr._toCol,
+    };
+    return rangeAddress;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExcelUtilities/ValueMatcher.cs b/AppsheetEpplus/FormulaParsing/ExcelUtilities/ValueMatcher.cs
new file mode 100644
index 0000000..f9b6063
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExcelUtilities/ValueMatcher.cs
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System;
+
+namespace AppsheetEpplus;
+
+public class ValueMatcher {
+  public const int IncompatibleOperands = -2;
+
+  public virtual int IsMatch(object o1, object o2) {
+    if (o1 != null && o2 == null) {
+      return 1;
+    }
+    if (o1 == null && o2 != null) {
+      return -1;
+    }
+    if (o1 == null && o2 == null) {
+      return 0;
+    }
+    //Handle ranges and defined names
+    o1 = CheckGetRange(o1);
+    o2 = CheckGetRange(o2);
+
+    if (o1 is string && o2 is string) {
+      return CompareStringToString(o1.ToString().ToLower(), o2.ToString().ToLower());
+    }
+    if (o1.GetType() == typeof(string)) {
+      return CompareStringToObject(o1.ToString(), o2);
+    }
+    if (o2.GetType() == typeof(string)) {
+      return CompareObjectToString(o1, o2.ToString());
+    }
+    return Convert.ToDouble(o1).CompareTo(Convert.ToDouble(o2));
+  }
+
+  private static object CheckGetRange(object v) {
+    if (v is ExcelDataProvider.IRangeInfo info) {
+      if (info.GetNCells() > 1) {
+        v = ExcelErrorValue.Create(eErrorType.Na);
+      }
+      v = info.GetOffset(0, 0);
+    } else if (v is ExcelDataProvider.INameInfo nameInfo) {
+      v = CheckGetRange(nameInfo);
+    }
+    return v;
+  }
+
+  protected virtual int CompareStringToString(string s1, string s2) {
+    return s1.CompareTo(s2);
+  }
+
+  protected virtual int CompareStringToObject(string o1, object o2) {
+    if (double.TryParse(o1, out var d1)) {
+      return d1.CompareTo(Convert.ToDouble(o2));
+    }
+    return IncompatibleOperands;
+  }
+
+  protected virtual int CompareObjectToString(object o1, string o2) {
+    if (double.TryParse(o2, out var d2)) {
+      return Convert.ToDouble(o1).CompareTo(d2);
+    }
+    return IncompatibleOperands;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExcelUtilities/WildCardValueMatcher.cs b/AppsheetEpplus/FormulaParsing/ExcelUtilities/WildCardValueMatcher.cs
new file mode 100644
index 0000000..fce2374
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExcelUtilities/WildCardValueMatcher.cs
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Text.RegularExpressions;
+
+namespace AppsheetEpplus;
+
+public class WildCardValueMatcher : ValueMatcher {
+  protected override int CompareStringToString(string s1, string s2) {
+    if (s1.Contains("*") || s1.Contains("?")) {
+      var regexPattern = Regex.Escape(s1);
+      regexPattern = string.Format("^{0}$", regexPattern);
+      regexPattern = regexPattern.Replace(@"\*", ".*");
+      regexPattern = regexPattern.Replace(@"\?", ".");
+      if (Regex.IsMatch(s2, regexPattern)) {
+        return 0;
+      }
+    }
+    return base.CompareStringToString(s1, s2);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExcelValues.cs b/AppsheetEpplus/FormulaParsing/ExcelValues.cs
new file mode 100644
index 0000000..248068e
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExcelValues.cs
@@ -0,0 +1,206 @@
+using System;
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Represents the errortypes in excel
+/// </summary>
+public enum eErrorType {
+  /// <summary>
+  /// Division by zero
+  /// </summary>
+  Div0,
+
+  /// <summary>
+  /// Not applicable
+  /// </summary>
+  Na,
+
+  /// <summary>
+  /// Name error
+  /// </summary>
+  Name,
+
+  /// <summary>
+  /// Null error
+  /// </summary>
+  Null,
+
+  /// <summary>
+  /// Num error
+  /// </summary>
+  Num,
+
+  /// <summary>
+  /// Reference error
+  /// </summary>
+  Ref,
+
+  /// <summary>
+  /// Value error
+  /// </summary>
+  Value,
+
+  // Bug G0004
+  /// <summary>
+  /// Error error  // Google Bug G0004
+  /// </summary>
+  Error,
+
+  // Bug G0005
+  /// <summary>
+  /// ErrorValueIsNullOrEmpty error  // Google Bug G0005
+  /// </summary>
+  ErrorValueIsNullOrEmpty,
+}
+
+/// <summary>
+/// Represents an Excel error.
+/// </summary>
+/// <seealso cref="eErrorType"/>
+public class ExcelErrorValue {
+  /// <summary>
+  /// Handles the convertion between <see cref="eErrorType"/> and the string values
+  /// used by Excel.
+  /// </summary>
+  public static class Values {
+    public const string Div0 = "#DIV/0!";
+    public const string Na = "#N/A";
+    public const string Name = "#NAME?";
+    public const string Null = "#NULL!";
+    public const string Num = "#NUM!";
+    public const string Ref = "#REF!";
+    public const string Value = "#VALUE!";
+    public const string Error = "#ERROR!"; // Bug G0004
+    public const string ErrorValueIsNullOrEmpty = "#ERRORVALUEISNULLOREMPTY!"; // Bug G0005
+
+    private static readonly Dictionary<string, eErrorType> _values = new() {
+      { Div0, eErrorType.Div0 },
+      { Na, eErrorType.Na },
+      { Name, eErrorType.Name },
+      { Null, eErrorType.Null },
+      { Num, eErrorType.Num },
+      { Ref, eErrorType.Ref },
+      { Value, eErrorType.Value },
+      { Error, eErrorType.Error }, // Bug G0004
+      {
+        ErrorValueIsNullOrEmpty,
+        eErrorType.ErrorValueIsNullOrEmpty
+      } // Bug G0005
+      ,
+    };
+
+    /// <summary>
+    /// Returns true if the supplied <paramref name="candidate"/> is an excel error.
+    /// </summary>
+    /// <param name="candidate"></param>
+    /// <returns></returns>
+    public static bool IsErrorValue(object candidate) {
+      if (candidate == null || !(candidate is ExcelErrorValue)) {
+        return false;
+      }
+      var candidateString = candidate.ToString();
+      return (!string.IsNullOrEmpty(candidateString) && _values.ContainsKey(candidateString));
+    }
+
+    /// <summary>
+    /// Returns true if the supplied <paramref name="candidate"/> is an excel error.
+    /// </summary>
+    /// <param name="candidate"></param>
+    /// <returns></returns>
+    public static bool StringIsErrorValue(string candidate) {
+      return (!string.IsNullOrEmpty(candidate) && _values.ContainsKey(candidate));
+    }
+
+    /// <summary>
+    /// Converts a string to an <see cref="eErrorType"/>
+    /// </summary>
+    /// <param name="val"></param>
+    /// <returns></returns>
+    /// <exception cref="ArgumentException">Thrown if the supplied value is not an Excel error</exception>
+    public static eErrorType ToErrorType(string val) {
+      if (string.IsNullOrEmpty(val) || !_values.ContainsKey(val)) {
+        throw new ArgumentException("Invalid error code " + (val ?? "<empty>"));
+      }
+      return _values[val];
+    }
+  }
+
+  internal static ExcelErrorValue Create(eErrorType errorType) {
+    return new(errorType);
+  }
+
+  internal static ExcelErrorValue Parse(string val) {
+    if (string.IsNullOrEmpty(
+        val)) // Google Bug G0005
+    {
+      val = Values.ErrorValueIsNullOrEmpty;
+    }
+
+    if (Values.StringIsErrorValue(val)) {
+      return new(Values.ToErrorType(val));
+    }
+    if (string.IsNullOrEmpty(val)) {
+      throw new ArgumentNullException("val");
+    }
+    throw new ArgumentException("Not a valid error value: " + val);
+  }
+
+  private ExcelErrorValue(eErrorType type) {
+    Type = type;
+  }
+
+  /// <summary>
+  /// The error type
+  /// </summary>
+  public eErrorType Type { get; private set; }
+
+  /// <summary>
+  /// Returns the string representation of the error type
+  /// </summary>
+  /// <returns></returns>
+  public override string ToString() {
+    switch (Type) {
+      case eErrorType.Div0:
+        return Values.Div0;
+      case eErrorType.Na:
+        return Values.Na;
+      case eErrorType.Name:
+        return Values.Name;
+      case eErrorType.Null:
+        return Values.Null;
+      case eErrorType.Num:
+        return Values.Num;
+      case eErrorType.Ref:
+        return Values.Ref;
+      case eErrorType.Value:
+        return Values.Value;
+      case eErrorType.Error: // Bug G0004
+        return Values.Error;
+      case eErrorType.ErrorValueIsNullOrEmpty: // Bug G0005
+        return Values.ErrorValueIsNullOrEmpty;
+      default:
+        throw (new ArgumentException("Invalid errortype"));
+    }
+  }
+
+  public static ExcelErrorValue operator +(object v1, ExcelErrorValue v2) {
+    return v2;
+  }
+
+  public static ExcelErrorValue operator +(ExcelErrorValue v1, ExcelErrorValue v2) {
+    return v1;
+  }
+
+  public override int GetHashCode() {
+    return base.GetHashCode();
+  }
+
+  public override bool Equals(object obj) {
+    if (!(obj is ExcelErrorValue value)) {
+      return false;
+    }
+    return value.ToString() == ToString();
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Exceptions/CircularReferenceException.cs b/AppsheetEpplus/FormulaParsing/Exceptions/CircularReferenceException.cs
new file mode 100644
index 0000000..47b68f0
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Exceptions/CircularReferenceException.cs
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System;
+
+namespace AppsheetEpplus;
+
+public class CircularReferenceException : Exception {
+  public CircularReferenceException(string message)
+      : base(message) {}
+}
diff --git a/AppsheetEpplus/FormulaParsing/Exceptions/ExcelErrorCodes.cs b/AppsheetEpplus/FormulaParsing/Exceptions/ExcelErrorCodes.cs
new file mode 100644
index 0000000..d045649
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Exceptions/ExcelErrorCodes.cs
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class ExcelErrorCodes {
+  private ExcelErrorCodes(string code) {
+    Code = code;
+  }
+
+  public string Code { get; private set; }
+
+  public override int GetHashCode() {
+    return Code.GetHashCode();
+  }
+
+  public override bool Equals(object obj) {
+    if (obj is ExcelErrorCodes codes) {
+      return codes.Code.Equals(Code);
+    }
+    return false;
+  }
+
+  public static bool operator ==(ExcelErrorCodes c1, ExcelErrorCodes c2) {
+    return c1.Code.Equals(c2.Code);
+  }
+
+  public static bool operator !=(ExcelErrorCodes c1, ExcelErrorCodes c2) {
+    return !c1.Code.Equals(c2.Code);
+  }
+
+  private static readonly IEnumerable<string> Codes = new List<string> {
+    Value.Code,
+    Name.Code,
+    NoValueAvaliable.Code,
+  };
+
+  public static bool IsErrorCode(object valueToTest) {
+    if (valueToTest == null) {
+      return false;
+    }
+    var candidate = valueToTest.ToString();
+    if (Codes.FirstOrDefault(x => x == candidate) != null) {
+      return true;
+    }
+    return false;
+  }
+
+  public static ExcelErrorCodes Value => new("#VALUE!");
+
+  public static ExcelErrorCodes Name => new("#NAME?");
+
+  public static ExcelErrorCodes NoValueAvaliable => new("#N/A");
+}
diff --git a/AppsheetEpplus/FormulaParsing/Exceptions/ExcelErrorValueException.cs b/AppsheetEpplus/FormulaParsing/Exceptions/ExcelErrorValueException.cs
new file mode 100644
index 0000000..335680d
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Exceptions/ExcelErrorValueException.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// This Exception represents an Excel error. When this exception is thrown
+/// from an Excel function, the ErrorValue code will be set as the value of the
+/// parsed cell.
+/// </summary>
+/// <seealso cref="ExcelErrorValue"/>
+public class ExcelErrorValueException : Exception {
+  public ExcelErrorValueException(ExcelErrorValue error)
+      : this(error.ToString(), error) {}
+
+  public ExcelErrorValueException(string message, ExcelErrorValue error)
+      : base(message) {
+    ErrorValue = error;
+  }
+
+  public ExcelErrorValueException(eErrorType errorType)
+      : this(ExcelErrorValue.Create(errorType)) {}
+
+  /// <summary>
+  /// The error value
+  /// </summary>
+  public ExcelErrorValue ErrorValue { get; private set; }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Exceptions/UnrecognizedTokenException.cs b/AppsheetEpplus/FormulaParsing/Exceptions/UnrecognizedTokenException.cs
new file mode 100644
index 0000000..0bc07dd
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Exceptions/UnrecognizedTokenException.cs
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System;
+
+namespace AppsheetEpplus;
+
+public class UnrecognizedTokenException : Exception {
+  public UnrecognizedTokenException(Token token)
+      : base("Unrecognized token: " + token.Value) {}
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/AtomicExpression.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/AtomicExpression.cs
new file mode 100644
index 0000000..d3c3cb6
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/AtomicExpression.cs
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public abstract class AtomicExpression : Expression {
+  public AtomicExpression(string expression)
+      : base(expression) {}
+
+  public override bool IsGroupedExpression => false;
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/BooleanExpression.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/BooleanExpression.cs
new file mode 100644
index 0000000..0e85b26
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/BooleanExpression.cs
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public class BooleanExpression : AtomicExpression {
+  private readonly bool? _precompiledValue;
+
+  public BooleanExpression(string expression)
+      : base(expression) {}
+
+  public BooleanExpression(bool value)
+      : base(value ? "true" : "false") {
+    _precompiledValue = value;
+  }
+
+  public override CompileResult Compile() {
+    var result = _precompiledValue ?? bool.Parse(ExpressionString);
+    return new(result, DataType.Boolean);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/CompileResult.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/CompileResult.cs
new file mode 100644
index 0000000..3546544
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/CompileResult.cs
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System;
+using System.Globalization;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class CompileResult {
+  private static readonly CompileResult _empty = new(null, DataType.Empty);
+
+  public static CompileResult Empty => _empty;
+
+  public CompileResult(object result, DataType dataType) {
+    Result = result;
+    DataType = dataType;
+  }
+
+  public CompileResult(eErrorType errorType) {
+    Result = ExcelErrorValue.Create(errorType);
+    DataType = DataType.ExcelError;
+  }
+
+  public CompileResult(ExcelErrorValue errorValue) {
+    ArgumentNullException.ThrowIfNull(errorValue);
+    Result = errorValue;
+    DataType = DataType.ExcelError;
+  }
+
+  public object Result { get; private set; }
+
+  public object ResultValue {
+    get {
+      var r = Result as ExcelDataProvider.IRangeInfo;
+      if (r == null) {
+        return Result;
+      }
+      return r.GetValue(r.Address._fromRow, r.Address._fromCol);
+    }
+  }
+
+  public double ResultNumeric {
+    get {
+      if (IsNumeric) {
+        return Result == null ? 0 : Convert.ToDouble(Result);
+      }
+      if (Result is DateTime time) {
+        return time.ToOADate();
+      }
+      if (Result is TimeSpan span) {
+        return new DateTime(span.Ticks).ToOADate();
+      }
+      if (IsNumericString) {
+        try {
+          return double.Parse(Result.ToString(), NumberStyles.Float, CultureInfo.InvariantCulture);
+        } catch (Exception) {
+          return 0;
+        }
+      }
+      if (Result is ExcelDataProvider.IRangeInfo info) {
+        var c = info.FirstOrDefault();
+        if (c == null) {
+          return 0;
+        }
+        return c.ValueDoubleLogical;
+      }
+      return 0;
+    }
+  }
+
+  public DataType DataType { get; private set; }
+
+  public bool IsNumeric =>
+    DataType == DataType.Decimal
+        || DataType == DataType.Integer
+        || DataType == DataType.Empty
+        || DataType == DataType.Boolean
+        || DataType == DataType.Date;
+
+  public bool IsNumericString => DataType == DataType.String && ConvertUtil.IsNumericString(Result);
+
+  public bool IsResultOfSubtotal { get; set; }
+
+  public bool IsHiddenCell { get; set; }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/CompileResultFactory.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/CompileResultFactory.cs
new file mode 100644
index 0000000..724e72e
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/CompileResultFactory.cs
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System;
+
+namespace AppsheetEpplus;
+
+public class CompileResultFactory {
+  public virtual CompileResult Create(object obj) {
+    if ((obj is ExcelDataProvider.INameInfo info)) {
+      obj = info.Value;
+    }
+    if (obj is ExcelDataProvider.IRangeInfo rangeInfo) {
+      obj = rangeInfo.GetOffset(0, 0);
+    }
+    if (obj == null) {
+      return new(null, DataType.Empty);
+    }
+    if (obj.GetType().Equals(typeof(string))) {
+      return new(obj, DataType.String);
+    }
+    if (obj.GetType().Equals(typeof(double)) || obj is decimal) {
+      return new(obj, DataType.Decimal);
+    }
+    if (obj.GetType().Equals(typeof(int)) || obj is long || obj is short) {
+      return new(obj, DataType.Integer);
+    }
+    if (obj.GetType().Equals(typeof(bool))) {
+      return new(obj, DataType.Boolean);
+    }
+    if (obj.GetType().Equals(typeof(ExcelErrorValue))) {
+      return new(obj, DataType.ExcelError);
+    }
+    if (obj.GetType().Equals(typeof(DateTime))) {
+      return new(((DateTime)obj).ToOADate(), DataType.Date);
+    }
+    throw new ArgumentException("Non supported type " + obj.GetType().FullName);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/CompileStrategy/CompileStrategy.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/CompileStrategy/CompileStrategy.cs
new file mode 100644
index 0000000..8abf262
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/CompileStrategy/CompileStrategy.cs
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public abstract class CompileStrategy {
+  protected readonly Expression _expression;
+
+  public CompileStrategy(Expression expression) {
+    _expression = expression;
+  }
+
+  public abstract Expression Compile();
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/CompileStrategy/CompileStrategyFactory.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/CompileStrategy/CompileStrategyFactory.cs
new file mode 100644
index 0000000..cb7e10c
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/CompileStrategy/CompileStrategyFactory.cs
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+public class CompileStrategyFactory : ICompileStrategyFactory {
+  public CompileStrategy Create(Expression expression) {
+    if (expression.Operator.Operator == Operators.Concat) {
+      return new StringConcatStrategy(expression);
+    }
+    return new DefaultCompileStrategy(expression);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/CompileStrategy/DefaultCompileStrategy.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/CompileStrategy/DefaultCompileStrategy.cs
new file mode 100644
index 0000000..52e2726
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/CompileStrategy/DefaultCompileStrategy.cs
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public class DefaultCompileStrategy : CompileStrategy {
+  public DefaultCompileStrategy(Expression expression)
+      : base(expression) {}
+
+  public override Expression Compile() {
+    return _expression.MergeWithNext();
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/CompileStrategy/ICompileStrategyFactory.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/CompileStrategy/ICompileStrategyFactory.cs
new file mode 100644
index 0000000..b89e794
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/CompileStrategy/ICompileStrategyFactory.cs
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public interface ICompileStrategyFactory {
+  CompileStrategy Create(Expression expression);
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/CompileStrategy/StringConcatStrategy.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/CompileStrategy/StringConcatStrategy.cs
new file mode 100644
index 0000000..53422ce
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/CompileStrategy/StringConcatStrategy.cs
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public class StringConcatStrategy : CompileStrategy {
+  public StringConcatStrategy(Expression expression)
+      : base(expression) {}
+
+  public override Expression Compile() {
+    var newExp =
+        _expression is ExcelAddressExpression
+            ? _expression
+            : ExpressionConverter.Instance.ToStringExpression(_expression);
+    newExp.Prev = _expression.Prev;
+    newExp.Next = _expression.Next;
+    if (_expression.Prev != null) {
+      _expression.Prev.Next = newExp;
+    }
+    if (_expression.Next != null) {
+      _expression.Next.Prev = newExp;
+    }
+    return newExp.MergeWithNext();
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/ConstantExpressions.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/ConstantExpressions.cs
new file mode 100644
index 0000000..cb86b67
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/ConstantExpressions.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace AppsheetEpplus;
+
+public static class ConstantExpressions {
+  public static Expression Percent {
+    get { return new ConstantExpression("Percent", () => new(0.01, DataType.Decimal)); }
+  }
+}
+
+public class ConstantExpression : AtomicExpression {
+  private readonly Func<CompileResult> _factoryMethod;
+
+  public ConstantExpression(string title, Func<CompileResult> factoryMethod)
+      : base(title) {
+    _factoryMethod = factoryMethod;
+  }
+
+  public override CompileResult Compile() {
+    return _factoryMethod();
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/DataType.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/DataType.cs
new file mode 100644
index 0000000..30302d2
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/DataType.cs
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public enum DataType {
+  Integer,
+  Decimal,
+  String,
+  Boolean,
+  Date,
+  Time,
+  Enumerable,
+  LookupArray,
+  ExcelAddress,
+  ExcelError,
+  Empty,
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/DateExpression.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/DateExpression.cs
new file mode 100644
index 0000000..c5a0bb8
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/DateExpression.cs
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System;
+using System.Globalization;
+
+namespace AppsheetEpplus;
+
+public class DateExpression : AtomicExpression {
+  public DateExpression(string expression)
+      : base(expression) {}
+
+  public override CompileResult Compile() {
+    var date = double.Parse(ExpressionString, CultureInfo.InvariantCulture);
+    return new(DateTime.FromOADate(date), DataType.Date);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/DecimalExpression.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/DecimalExpression.cs
new file mode 100644
index 0000000..8bcd36c
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/DecimalExpression.cs
@@ -0,0 +1,60 @@
+using System.Globalization;
+
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public class DecimalExpression : AtomicExpression {
+  private readonly double? _compiledValue;
+  private readonly bool _negate;
+
+  public DecimalExpression(string expression)
+      : this(expression, false) {}
+
+  public DecimalExpression(string expression, bool negate)
+      : base(expression) {
+    _negate = negate;
+  }
+
+  public DecimalExpression(double compiledValue)
+      : base(compiledValue.ToString(CultureInfo.InvariantCulture)) {
+    _compiledValue = compiledValue;
+  }
+
+  public override CompileResult Compile() {
+    double result = _compiledValue ?? double.Parse(ExpressionString, CultureInfo.InvariantCulture);
+    result = _negate ? result * -1 : result;
+    return new(result, DataType.Decimal);
+  }
+
+  public bool IsNegated => _negate;
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/EnumerableExpression.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/EnumerableExpression.cs
new file mode 100644
index 0000000..654e95b
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/EnumerableExpression.cs
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class EnumerableExpression : Expression {
+  public EnumerableExpression()
+      : this(new ExpressionCompiler()) {}
+
+  public EnumerableExpression(IExpressionCompiler expressionCompiler) {
+    _expressionCompiler = expressionCompiler;
+  }
+
+  private readonly IExpressionCompiler _expressionCompiler;
+
+  public override bool IsGroupedExpression => false;
+
+  public override Expression PrepareForNextChild() {
+    return this;
+  }
+
+  public override CompileResult Compile() {
+    var result = new List<object>();
+    foreach (var childExpression in Children) {
+      result.Add(_expressionCompiler.Compile(new List<Expression> { childExpression }).Result);
+    }
+    return new(result, DataType.Enumerable);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/ExcelAddressExpression.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/ExcelAddressExpression.cs
new file mode 100644
index 0000000..825040d
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/ExcelAddressExpression.cs
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class ExcelAddressExpression : AtomicExpression {
+  private readonly ExcelDataProvider _excelDataProvider;
+  private readonly ParsingContext _parsingContext;
+  private readonly RangeAddressFactory _rangeAddressFactory;
+  private readonly bool _negate;
+
+  public ExcelAddressExpression(
+      string expression,
+      ExcelDataProvider excelDataProvider,
+      ParsingContext parsingContext)
+      : this(expression, excelDataProvider, parsingContext, new(excelDataProvider), false) {}
+
+  public ExcelAddressExpression(
+      string expression,
+      ExcelDataProvider excelDataProvider,
+      ParsingContext parsingContext,
+      bool negate)
+      : this(expression, excelDataProvider, parsingContext, new(excelDataProvider), negate) {}
+
+  public ExcelAddressExpression(
+      string expression,
+      ExcelDataProvider excelDataProvider,
+      ParsingContext parsingContext,
+      RangeAddressFactory rangeAddressFactory,
+      bool negate)
+      : base(expression) {
+    Require.That(excelDataProvider).Named("excelDataProvider").IsNotNull();
+    Require.That(parsingContext).Named("parsingContext").IsNotNull();
+    Require.That(rangeAddressFactory).Named("rangeAddressFactory").IsNotNull();
+    _excelDataProvider = excelDataProvider;
+    _parsingContext = parsingContext;
+    _rangeAddressFactory = rangeAddressFactory;
+    _negate = negate;
+  }
+
+  public override bool IsGroupedExpression => false;
+
+  public override CompileResult Compile() {
+    if (ParentIsLookupFunction) {
+      return new(ExpressionString, DataType.ExcelAddress);
+    }
+    return CompileRangeValues();
+  }
+
+  private CompileResult CompileRangeValues() {
+    var c = _parsingContext.Scopes.Current;
+    var result = _excelDataProvider.GetRange(
+        c.Address.Worksheet,
+        c.Address.FromRow,
+        c.Address.FromCol,
+        ExpressionString);
+
+    if (result == null || result.IsEmpty) {
+      return CompileResult.Empty;
+    }
+    if (result.Address.Rows > 1 || result.Address.Columns > 1) {
+      return new(result, DataType.Enumerable);
+    }
+    return CompileSingleCell(result);
+  }
+
+  private CompileResult CompileSingleCell(ExcelDataProvider.IRangeInfo result) {
+    var cell = result.First();
+    var factory = new CompileResultFactory();
+    var compileResult = factory.Create(cell.Value);
+    if (_negate && compileResult.IsNumeric) {
+      compileResult = new(compileResult.ResultNumeric * -1, compileResult.DataType);
+    }
+    compileResult.IsHiddenCell = cell.IsHiddenRow;
+    return compileResult;
+  }
+
+  public bool IsNegated => _negate;
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/ExcelErrorExpression.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/ExcelErrorExpression.cs
new file mode 100644
index 0000000..ce530ee
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/ExcelErrorExpression.cs
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public class ExcelErrorExpression : Expression {
+  private readonly ExcelErrorValue _error;
+
+  public ExcelErrorExpression(string expression, ExcelErrorValue error)
+      : base(expression) {
+    _error = error;
+  }
+
+  public ExcelErrorExpression(ExcelErrorValue error)
+      : this(error.ToString(), error) {}
+
+  public override bool IsGroupedExpression => false;
+
+  public override CompileResult Compile() {
+    return new(_error, DataType.ExcelError);
+    //if (ParentIsLookupFunction)
+    //{
+    //    return new CompileResult(ExpressionString, DataType.ExcelError);
+    //}
+    //else
+    //{
+    //    return CompileRangeValues();
+    //}
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/Expression.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/Expression.cs
new file mode 100644
index 0000000..791b074
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/Expression.cs
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public abstract class Expression {
+  public string ExpressionString { get; private set; }
+
+  private readonly List<Expression> _children = new();
+
+  public IEnumerable<Expression> Children => _children;
+
+  public Expression Next { get; set; }
+
+  public Expression Prev { get; set; }
+
+  public IOperator Operator { get; set; }
+
+  public abstract bool IsGroupedExpression { get; }
+
+  public Expression() {}
+
+  public Expression(string expression) {
+    ExpressionString = expression;
+    Operator = null;
+  }
+
+  public virtual bool ParentIsLookupFunction { get; set; }
+
+  public virtual bool HasChildren => _children.Any();
+
+  public virtual Expression PrepareForNextChild() {
+    return this;
+  }
+
+  public virtual Expression AddChild(Expression child) {
+    if (_children.Any()) {
+      var last = _children.Last();
+      child.Prev = last;
+      last.Next = child;
+    }
+    _children.Add(child);
+    return child;
+  }
+
+  public virtual Expression MergeWithNext() {
+    Expression expression;
+    if (Next != null && Operator != null) {
+      var result = Operator.Apply(Compile(), Next.Compile());
+      expression = ExpressionConverter.Instance.FromCompileResult(result);
+      if (expression is ExcelErrorExpression) {
+        expression.Next = null;
+        expression.Prev = null;
+        return expression;
+      }
+      if (Next != null) {
+        expression.Operator = Next.Operator;
+      } else {
+        expression.Operator = null;
+      }
+      expression.Next = Next.Next;
+      if (expression.Next != null) {
+        expression.Next.Prev = expression;
+      }
+      expression.Prev = Prev;
+    } else {
+      throw (new FormatException("Invalid formula syntax. Operator missing expression."));
+    }
+    if (Prev != null) {
+      Prev.Next = expression;
+    }
+    return expression;
+  }
+
+  public abstract CompileResult Compile();
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/ExpressionCompiler.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/ExpressionCompiler.cs
new file mode 100644
index 0000000..33e0d52
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/ExpressionCompiler.cs
@@ -0,0 +1,144 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class ExpressionCompiler : IExpressionCompiler {
+  private IEnumerable<Expression> _expressions;
+  private readonly IExpressionConverter _expressionConverter;
+  private readonly ICompileStrategyFactory _compileStrategyFactory;
+
+  public ExpressionCompiler()
+      : this(new ExpressionConverter(), new CompileStrategyFactory()) {}
+
+  public ExpressionCompiler(
+      IExpressionConverter expressionConverter,
+      ICompileStrategyFactory compileStrategyFactory) {
+    _expressionConverter = expressionConverter;
+    _compileStrategyFactory = compileStrategyFactory;
+  }
+
+  public CompileResult Compile(IEnumerable<Expression> expressions) {
+    _expressions = expressions;
+    return PerformCompilation();
+  }
+
+  public CompileResult Compile(
+      string worksheet,
+      int row,
+      int column,
+      IEnumerable<Expression> expressions) {
+    _expressions = expressions;
+    return PerformCompilation(worksheet, row, column);
+  }
+
+  private CompileResult PerformCompilation(string worksheet = "", int row = -1, int column = -1) {
+    var compiledExpressions = HandleGroupedExpressions();
+    while (compiledExpressions.Any(x => x.Operator != null)) {
+      var prec = FindLowestPrecedence();
+      compiledExpressions = HandlePrecedenceLevel(prec);
+    }
+    if (_expressions.Any()) {
+      return compiledExpressions.First().Compile();
+    }
+    return CompileResult.Empty;
+  }
+
+  private IEnumerable<Expression> HandleGroupedExpressions() {
+    if (!_expressions.Any()) {
+      return [];
+    }
+    var first = _expressions.First();
+    var groupedExpressions = _expressions.Where(x => x.IsGroupedExpression);
+    foreach (var groupedExpression in groupedExpressions) {
+      var result = groupedExpression.Compile();
+      if (result == CompileResult.Empty) {
+        continue;
+      }
+      var newExp = _expressionConverter.FromCompileResult(result);
+      newExp.Operator = groupedExpression.Operator;
+      newExp.Prev = groupedExpression.Prev;
+      newExp.Next = groupedExpression.Next;
+      if (groupedExpression.Prev != null) {
+        groupedExpression.Prev.Next = newExp;
+      }
+      if (groupedExpression.Next != null) {
+        groupedExpression.Next.Prev = newExp;
+      }
+      if (groupedExpression == first) {
+        first = newExp;
+      }
+    }
+    return RefreshList(first);
+  }
+
+  private IEnumerable<Expression> HandlePrecedenceLevel(int precedence) {
+    var first = _expressions.First();
+    var expressionsToHandle = _expressions.Where(x =>
+        x.Operator != null && x.Operator.Precedence == precedence);
+    var last = expressionsToHandle.Last();
+    var expression = expressionsToHandle.First();
+    do {
+      var strategy = _compileStrategyFactory.Create(expression);
+      var compiledExpression = strategy.Compile();
+      if (compiledExpression is ExcelErrorExpression) {
+        return RefreshList(compiledExpression);
+      }
+      if (expression == first) {
+        first = compiledExpression;
+      }
+
+      expression = compiledExpression;
+    } while (expression != null
+            && expression.Operator != null
+            && expression.Operator.Precedence == precedence);
+    return RefreshList(first);
+  }
+
+  private int FindLowestPrecedence() {
+    return _expressions.Where(x => x.Operator != null).Min(x => x.Operator.Precedence);
+  }
+
+  private IEnumerable<Expression> RefreshList(Expression first) {
+    var resultList = new List<Expression>();
+    var exp = first;
+    resultList.Add(exp);
+    while (exp.Next != null) {
+      resultList.Add(exp.Next);
+      exp = exp.Next;
+    }
+    _expressions = resultList;
+    return resultList;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/ExpressionConverter.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/ExpressionConverter.cs
new file mode 100644
index 0000000..9e27c63
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/ExpressionConverter.cs
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System;
+
+namespace AppsheetEpplus;
+
+public class ExpressionConverter : IExpressionConverter {
+  public StringExpression ToStringExpression(Expression expression) {
+    var result = expression.Compile();
+    var newExp = new StringExpression(result.Result.ToString());
+    newExp.Operator = expression.Operator;
+    return newExp;
+  }
+
+  public Expression FromCompileResult(CompileResult compileResult) {
+    switch (compileResult.DataType) {
+      case DataType.Integer:
+        return compileResult.Result is string
+            ? new(compileResult.Result.ToString())
+            : new IntegerExpression(Convert.ToDouble(compileResult.Result));
+      case DataType.String:
+        return new StringExpression(compileResult.Result.ToString());
+      case DataType.Decimal:
+        return compileResult.Result is string
+            ? new(compileResult.Result.ToString())
+            : new DecimalExpression(((double)compileResult.Result));
+      case DataType.Boolean:
+        return compileResult.Result is string
+            ? new(compileResult.Result.ToString())
+            : new BooleanExpression((bool)compileResult.Result);
+      //case DataType.Enumerable:
+      //    return
+      case DataType.ExcelError:
+        //throw (new OfficeOpenXml.FormulaParsing.Exceptions.ExcelErrorValueException((ExcelErrorValue)compileResult.Result)); //Added JK
+        return compileResult.Result is string
+            ? new(
+                compileResult.Result.ToString(),
+                ExcelErrorValue.Parse(compileResult.Result.ToString()))
+            : new ExcelErrorExpression((ExcelErrorValue)compileResult.Result);
+      case DataType.Empty:
+        return new IntegerExpression(0); //Added JK
+    }
+    return null;
+  }
+
+  private static IExpressionConverter _instance;
+
+  public static IExpressionConverter Instance {
+    get {
+      if (_instance == null) {
+        _instance = new ExpressionConverter();
+      }
+      return _instance;
+    }
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/ExpressionFactory.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/ExpressionFactory.cs
new file mode 100644
index 0000000..66b3426
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/ExpressionFactory.cs
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+public class ExpressionFactory : IExpressionFactory {
+  private readonly ExcelDataProvider _excelDataProvider;
+  private readonly ParsingContext _parsingContext;
+
+  public ExpressionFactory(ExcelDataProvider excelDataProvider, ParsingContext context) {
+    _excelDataProvider = excelDataProvider;
+    _parsingContext = context;
+  }
+
+  public Expression Create(Token token) {
+    switch (token.TokenType) {
+      case TokenType.Integer:
+        return new IntegerExpression(token.Value, token.IsNegated);
+      case TokenType.String:
+        return new StringExpression(token.Value);
+      case TokenType.Decimal:
+        return new DecimalExpression(token.Value, token.IsNegated);
+      case TokenType.Boolean:
+        return new BooleanExpression(token.Value);
+      case TokenType.ExcelAddress:
+        return new ExcelAddressExpression(
+            token.Value,
+            _excelDataProvider,
+            _parsingContext,
+            token.IsNegated);
+      case TokenType.InvalidReference:
+        return new ExcelErrorExpression(token.Value, ExcelErrorValue.Create(eErrorType.Ref));
+      case TokenType.NumericError:
+        return new ExcelErrorExpression(token.Value, ExcelErrorValue.Create(eErrorType.Num));
+      case TokenType.ValueDataTypeError:
+        return new ExcelErrorExpression(token.Value, ExcelErrorValue.Create(eErrorType.Value));
+      case TokenType.Null:
+        return new ExcelErrorExpression(token.Value, ExcelErrorValue.Create(eErrorType.Null));
+      case TokenType.NameValue:
+        return new NamedValueExpression(token.Value, _parsingContext);
+      default:
+        return new StringExpression(token.Value);
+    }
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/ExpressionGraph.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/ExpressionGraph.cs
new file mode 100644
index 0000000..dbb1bd6
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/ExpressionGraph.cs
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class ExpressionGraph {
+  private readonly List<Expression> _expressions = new();
+
+  public IEnumerable<Expression> Expressions => _expressions;
+
+  public Expression Current { get; private set; }
+
+  public Expression Add(Expression expression) {
+    _expressions.Add(expression);
+    if (Current != null) {
+      Current.Next = expression;
+      expression.Prev = Current;
+    }
+    Current = expression;
+    return expression;
+  }
+
+  public void Reset() {
+    _expressions.Clear();
+    Current = null;
+  }
+
+  public void Remove(Expression item) {
+    if (item == Current) {
+      Current = item.Prev ?? item.Next;
+    }
+    _expressions.Remove(item);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/ExpressionGraphBuilder.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/ExpressionGraphBuilder.cs
new file mode 100644
index 0000000..f8c1677
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/ExpressionGraphBuilder.cs
@@ -0,0 +1,193 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class ExpressionGraphBuilder : IExpressionGraphBuilder {
+  private readonly ExpressionGraph _graph = new();
+  private readonly IExpressionFactory _expressionFactory;
+  private readonly ParsingContext _parsingContext;
+  private int _tokenIndex;
+  private bool _negateNextExpression;
+
+  public ExpressionGraphBuilder(ExcelDataProvider excelDataProvider, ParsingContext parsingContext)
+      : this(new ExpressionFactory(excelDataProvider, parsingContext), parsingContext) {}
+
+  public ExpressionGraphBuilder(
+      IExpressionFactory expressionFactory,
+      ParsingContext parsingContext) {
+    _expressionFactory = expressionFactory;
+    _parsingContext = parsingContext;
+  }
+
+  public ExpressionGraph Build(IEnumerable<Token> tokens) {
+    _tokenIndex = 0;
+    _graph.Reset();
+    var tokensArr = tokens != null ? tokens.ToArray() : [];
+    BuildUp(tokensArr, null);
+    return _graph;
+  }
+
+  private void BuildUp(Token[] tokens, Expression parent) {
+    while (_tokenIndex < tokens.Length) {
+      var token = tokens[_tokenIndex];
+      if (token.TokenType == TokenType.Operator
+          && OperatorsDict.Instance.TryGetValue(token.Value, out var op)) {
+        SetOperatorOnExpression(parent, op);
+      } else if (token.TokenType == TokenType.Function) {
+        BuildFunctionExpression(tokens, parent, token.Value);
+      } else if (token.TokenType == TokenType.OpeningEnumerable) {
+        _tokenIndex++;
+        BuildEnumerableExpression(tokens, parent);
+      } else if (token.TokenType == TokenType.OpeningParenthesis) {
+        _tokenIndex++;
+        BuildGroupExpression(tokens, parent);
+        //if (parent is FunctionExpression)
+        //{
+        //    return;
+        //}
+      } else if (token.TokenType == TokenType.ClosingParenthesis
+          || token.TokenType == TokenType.ClosingEnumerable) {
+        break;
+      } else if (token.TokenType == TokenType.Negator) {
+        _negateNextExpression = true;
+      } else if (token.TokenType == TokenType.Percent) {
+        SetOperatorOnExpression(parent, Operator.Percent);
+        if (parent == null) {
+          _graph.Add(ConstantExpressions.Percent);
+        } else {
+          parent.AddChild(ConstantExpressions.Percent);
+        }
+      } else {
+        CreateAndAppendExpression(ref parent, token);
+      }
+      _tokenIndex++;
+    }
+  }
+
+  private void BuildEnumerableExpression(Token[] tokens, Expression parent) {
+    if (parent == null) {
+      _graph.Add(new EnumerableExpression());
+      BuildUp(tokens, _graph.Current);
+    } else {
+      var enumerableExpression = new EnumerableExpression();
+      parent.AddChild(enumerableExpression);
+      BuildUp(tokens, enumerableExpression);
+    }
+  }
+
+  private void CreateAndAppendExpression(ref Expression parent, Token token) {
+    if (IsWaste(token)) {
+      return;
+    }
+    if (parent != null
+        && (token.TokenType == TokenType.Comma || token.TokenType == TokenType.SemiColon)) {
+      parent = parent.PrepareForNextChild();
+      return;
+    }
+    if (_negateNextExpression) {
+      token.Negate();
+      _negateNextExpression = false;
+    }
+    var expression = _expressionFactory.Create(token);
+    if (parent == null) {
+      _graph.Add(expression);
+    } else {
+      parent.AddChild(expression);
+    }
+  }
+
+  private bool IsWaste(Token token) {
+    if (token.TokenType == TokenType.String) {
+      return true;
+    }
+    return false;
+  }
+
+  private void BuildFunctionExpression(Token[] tokens, Expression parent, string funcName) {
+    if (parent == null) {
+      _graph.Add(new FunctionExpression(funcName, _parsingContext, _negateNextExpression));
+      _negateNextExpression = false;
+      HandleFunctionArguments(tokens, _graph.Current);
+    } else {
+      var func = new FunctionExpression(funcName, _parsingContext, _negateNextExpression);
+      _negateNextExpression = false;
+      parent.AddChild(func);
+      HandleFunctionArguments(tokens, func);
+    }
+  }
+
+  private void HandleFunctionArguments(Token[] tokens, Expression function) {
+    _tokenIndex++;
+    var token = tokens.ElementAt(_tokenIndex);
+    if (token.TokenType != TokenType.OpeningParenthesis) {
+      throw new ExcelErrorValueException(eErrorType.Value);
+    }
+    _tokenIndex++;
+    BuildUp(tokens, function.Children.First());
+  }
+
+  private void BuildGroupExpression(Token[] tokens, Expression parent) {
+    if (parent == null) {
+      _graph.Add(new GroupExpression(_negateNextExpression));
+      _negateNextExpression = false;
+      BuildUp(tokens, _graph.Current);
+    } else {
+      if (parent.IsGroupedExpression || parent is FunctionArgumentExpression) {
+        var newGroupExpression = new GroupExpression(_negateNextExpression);
+        _negateNextExpression = false;
+        parent.AddChild(newGroupExpression);
+        BuildUp(tokens, newGroupExpression);
+      }
+      BuildUp(tokens, parent);
+    }
+  }
+
+  private void SetOperatorOnExpression(Expression parent, IOperator op) {
+    if (parent == null) {
+      _graph.Current.Operator = op;
+    } else {
+      Expression candidate;
+      if (parent is FunctionArgumentExpression) {
+        candidate = parent.Children.Last();
+      } else {
+        candidate = parent.Children.Last();
+        if (candidate is FunctionArgumentExpression) {
+          candidate = candidate.Children.Last();
+        }
+      }
+      candidate.Operator = op;
+    }
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionArgumentExpression.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionArgumentExpression.cs
new file mode 100644
index 0000000..94e48c0
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionArgumentExpression.cs
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public class FunctionArgumentExpression : GroupExpression {
+  private readonly Expression _function;
+
+  public FunctionArgumentExpression(Expression function)
+      : base(false) {
+    _function = function;
+  }
+
+  public override bool ParentIsLookupFunction {
+    get => base.ParentIsLookupFunction;
+    set {
+      base.ParentIsLookupFunction = value;
+      foreach (var child in Children) {
+        child.ParentIsLookupFunction = value;
+      }
+    }
+  }
+
+  public override bool IsGroupedExpression => false;
+
+  public override Expression PrepareForNextChild() {
+    return _function.PrepareForNextChild();
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionCompilers/DefaultCompiler.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionCompilers/DefaultCompiler.cs
new file mode 100644
index 0000000..4b885b4
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionCompilers/DefaultCompiler.cs
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class DefaultCompiler : FunctionCompiler {
+  public DefaultCompiler(ExcelFunction function)
+      : base(function) {}
+
+  public override CompileResult Compile(IEnumerable<Expression> children, ParsingContext context) {
+    var args = new List<FunctionArgument>();
+    Function.BeforeInvoke(context);
+    foreach (var child in children) {
+      var compileResult = child.Compile();
+      if (compileResult.IsResultOfSubtotal) {
+        var arg = new FunctionArgument(compileResult.Result);
+        arg.SetExcelStateFlag(ExcelCellState.IsResultOfSubtotal);
+        args.Add(arg);
+      } else {
+        BuildFunctionArguments(compileResult.Result, args);
+      }
+    }
+    return Function.Execute(args, context);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionCompilers/ErrorHandlingFunctionCompiler.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionCompilers/ErrorHandlingFunctionCompiler.cs
new file mode 100644
index 0000000..c23bba4
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionCompilers/ErrorHandlingFunctionCompiler.cs
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class ErrorHandlingFunctionCompiler : FunctionCompiler {
+  public ErrorHandlingFunctionCompiler(ExcelFunction function)
+      : base(function) {}
+
+  public override CompileResult Compile(IEnumerable<Expression> children, ParsingContext context) {
+    var args = new List<FunctionArgument>();
+    Function.BeforeInvoke(context);
+    foreach (var child in children) {
+      try {
+        var arg = child.Compile();
+        BuildFunctionArguments(arg?.Result, args);
+      } catch (ExcelErrorValueException efe) {
+        return ((ErrorHandlingFunction)Function).HandleError(efe.ErrorValue.ToString());
+      } catch // (Exception e)
+      {
+        return ((ErrorHandlingFunction)Function).HandleError(ExcelErrorValue.Values.Value);
+      }
+    }
+    return Function.Execute(args, context);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionCompilers/FunctionCompiler.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionCompilers/FunctionCompiler.cs
new file mode 100644
index 0000000..e6c0996
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionCompilers/FunctionCompiler.cs
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public abstract class FunctionCompiler {
+  protected ExcelFunction Function { get; private set; }
+
+  public FunctionCompiler(ExcelFunction function) {
+    Require.That(function).Named("function").IsNotNull();
+    Function = function;
+  }
+
+  protected void BuildFunctionArguments(object result, List<FunctionArgument> args) {
+    if (result is IEnumerable<object> objects && !(objects is ExcelDataProvider.IRangeInfo)) {
+      var argList = new List<FunctionArgument>();
+      foreach (var arg in objects) {
+        BuildFunctionArguments(arg, argList);
+      }
+      args.Add(new(argList));
+    } else {
+      args.Add(new(result));
+    }
+  }
+
+  public abstract CompileResult Compile(IEnumerable<Expression> children, ParsingContext context);
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionCompilers/FunctionCompilerFactory.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionCompilers/FunctionCompilerFactory.cs
new file mode 100644
index 0000000..af9c099
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionCompilers/FunctionCompilerFactory.cs
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class FunctionCompilerFactory {
+  private readonly Dictionary<Type, FunctionCompiler> _specialCompilers = new();
+
+  public FunctionCompilerFactory(FunctionRepository repository) {
+    _specialCompilers.Add(typeof(If), new IfFunctionCompiler(repository.GetFunction("if")));
+    _specialCompilers.Add(
+        typeof(IfError),
+        new IfErrorFunctionCompiler(repository.GetFunction("iferror")));
+    _specialCompilers.Add(typeof(IfNa), new IfNaFunctionCompiler(repository.GetFunction("ifna")));
+  }
+
+  private FunctionCompiler GetCompilerByType(ExcelFunction function) {
+    var funcType = function.GetType();
+    if (_specialCompilers.ContainsKey(funcType)) {
+      return _specialCompilers[funcType];
+    }
+    return new DefaultCompiler(function);
+  }
+
+  public virtual FunctionCompiler Create(ExcelFunction function) {
+    if (function.IsLookupFuction) {
+      return new LookupFunctionCompiler(function);
+    }
+    if (function.IsErrorHandlingFunction) {
+      return new ErrorHandlingFunctionCompiler(function);
+    }
+    return GetCompilerByType(function);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfErrorFunctionCompiler.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfErrorFunctionCompiler.cs
new file mode 100644
index 0000000..e5bb7ab
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfErrorFunctionCompiler.cs
@@ -0,0 +1,32 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class IfErrorFunctionCompiler : FunctionCompiler {
+  public IfErrorFunctionCompiler(ExcelFunction function)
+      : base(function) {
+    Require.That(function).Named("function").IsNotNull();
+  }
+
+  public override CompileResult Compile(IEnumerable<Expression> children, ParsingContext context) {
+    if (children.Count() != 2) {
+      throw new ExcelErrorValueException(eErrorType.Value);
+    }
+    var args = new List<FunctionArgument>();
+    Function.BeforeInvoke(context);
+    var firstChild = children.First();
+    var lastChild = children.ElementAt(1);
+    try {
+      var result = firstChild.Compile();
+      if (result.DataType == DataType.ExcelError) {
+        args.Add(new(lastChild.Compile().Result));
+      } else {
+        args.Add(new(result.Result));
+      }
+    } catch (ExcelErrorValueException) {
+      args.Add(new(lastChild.Compile().Result));
+    }
+    return Function.Execute(args, context);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfFunctionCompiler.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfFunctionCompiler.cs
new file mode 100644
index 0000000..e2b884b
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfFunctionCompiler.cs
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2014-01-27
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Why do the If function require a compiler of its own you might ask;)
+///
+/// It is because it only needs to evaluate one of the two last expressions. This
+/// compiler handles this - it ignores the irrelevant expression.
+/// </summary>
+public class IfFunctionCompiler : FunctionCompiler {
+  public IfFunctionCompiler(ExcelFunction function)
+      : base(function) {
+    Require.That(function).Named("function").IsNotNull();
+    if (!(function is If)) {
+      throw new ArgumentException("function must be of type If");
+    }
+  }
+
+  public override CompileResult Compile(IEnumerable<Expression> children, ParsingContext context) {
+    if (children.Count() < 3) {
+      throw new ExcelErrorValueException(eErrorType.Value);
+    }
+    var args = new List<FunctionArgument>();
+    Function.BeforeInvoke(context);
+    var firstChild = children.ElementAt(0);
+    var v = firstChild.Compile().Result;
+
+    /****  Handle names and ranges ****/
+    if (v is ExcelDataProvider.INameInfo info) {
+      v = info.Value;
+    }
+
+    if (v is ExcelDataProvider.IRangeInfo rangeInfo) {
+      if (rangeInfo.GetNCells() > 1) {
+        throw (new ArgumentException("Logical can't be more than one cell"));
+      }
+      v = rangeInfo.GetOffset(0, 0);
+    }
+    bool boolVal;
+    if (v is bool b) {
+      boolVal = b;
+    } else {
+      if (ConvertUtil.IsNumeric(v)) {
+        boolVal = ConvertUtil.GetValueDouble(v) != 0;
+      } else {
+        throw (new ArgumentException("Invalid logical test"));
+      }
+    }
+    /****  End Handle names and ranges ****/
+
+    args.Add(new(boolVal));
+    if (boolVal) {
+      var val = children.ElementAt(1).Compile().Result;
+      args.Add(new(val));
+      args.Add(new(null));
+    } else {
+      var val = children.ElementAt(2).Compile().Result;
+      args.Add(new(null));
+      args.Add(new(val));
+    }
+    return Function.Execute(args, context);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfNaFunctionCompiler.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfNaFunctionCompiler.cs
new file mode 100644
index 0000000..1e5075a
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfNaFunctionCompiler.cs
@@ -0,0 +1,31 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class IfNaFunctionCompiler : FunctionCompiler {
+  public IfNaFunctionCompiler(ExcelFunction function)
+      : base(function) {}
+
+  public override CompileResult Compile(IEnumerable<Expression> children, ParsingContext context) {
+    if (children.Count() != 2) {
+      throw new ExcelErrorValueException(eErrorType.Value);
+    }
+    var args = new List<FunctionArgument>();
+    Function.BeforeInvoke(context);
+    var firstChild = children.First();
+    var lastChild = children.ElementAt(1);
+    try {
+      var result = firstChild.Compile();
+      if (result.DataType == DataType.ExcelError
+          && (Equals(result.Result, ExcelErrorValue.Create(eErrorType.Na)))) {
+        args.Add(new(lastChild.Compile().Result));
+      } else {
+        args.Add(new(result.Result));
+      }
+    } catch (ExcelErrorValueException) {
+      args.Add(new(lastChild.Compile().Result));
+    }
+    return Function.Execute(args, context);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionCompilers/LookupFunctionCompiler.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionCompilers/LookupFunctionCompiler.cs
new file mode 100644
index 0000000..883fd75
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionCompilers/LookupFunctionCompiler.cs
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class LookupFunctionCompiler : FunctionCompiler {
+  public LookupFunctionCompiler(ExcelFunction function)
+      : base(function) {}
+
+  public override CompileResult Compile(IEnumerable<Expression> children, ParsingContext context) {
+    var args = new List<FunctionArgument>();
+    Function.BeforeInvoke(context);
+    var firstChild = true;
+    foreach (var child in children) {
+      if (!firstChild || Function.SkipArgumentEvaluation) {
+        child.ParentIsLookupFunction = Function.IsLookupFuction;
+      } else {
+        firstChild = false;
+      }
+      var arg = child.Compile();
+      BuildFunctionArguments(arg?.Result, args);
+    }
+    return Function.Execute(args, context);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionExpression.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionExpression.cs
new file mode 100644
index 0000000..88cc7cc
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/FunctionExpression.cs
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Expression that handles execution of a function.
+/// </summary>
+public class FunctionExpression : AtomicExpression {
+  /// <summary>
+  /// Constructor
+  /// </summary>
+  /// <param name="expression">should be the of the function</param>
+  /// <param name="parsingContext"></param>
+  /// <param name="isNegated">True if the numeric result of the function should be negated.</param>
+  public FunctionExpression(string expression, ParsingContext parsingContext, bool isNegated)
+      : base(expression) {
+    _parsingContext = parsingContext;
+    _functionCompilerFactory = new(parsingContext.Configuration.FunctionRepository);
+    _isNegated = isNegated;
+    base.AddChild(new FunctionArgumentExpression(this));
+  }
+
+  private readonly ParsingContext _parsingContext;
+  private readonly FunctionCompilerFactory _functionCompilerFactory;
+  private readonly bool _isNegated;
+
+  public override CompileResult Compile() {
+    try {
+      var function = _parsingContext.Configuration.FunctionRepository.GetFunction(ExpressionString);
+      if (function == null) {
+        if (_parsingContext.Debug) {
+          _parsingContext.Configuration.Logger.Log(
+              _parsingContext,
+              string.Format("'{0}' is not a supported function", ExpressionString));
+        }
+        return new(ExcelErrorValue.Create(eErrorType.Name), DataType.ExcelError);
+      }
+      if (_parsingContext.Debug) {
+        _parsingContext.Configuration.Logger.LogFunction(ExpressionString);
+      }
+      var compiler = _functionCompilerFactory.Create(function);
+      var result = compiler.Compile(HasChildren ? Children : [], _parsingContext);
+      if (_isNegated) {
+        if (!result.IsNumeric) {
+          if (_parsingContext.Debug) {
+            var msg = string.Format(
+                "Trying to negate a non-numeric value ({0}) in function '{1}'",
+                result.Result,
+                ExpressionString);
+            _parsingContext.Configuration.Logger.Log(_parsingContext, msg);
+          }
+          return new(ExcelErrorValue.Create(eErrorType.Value), DataType.ExcelError);
+        }
+        return new(result.ResultNumeric * -1, result.DataType);
+      }
+      return result;
+    } catch (ExcelErrorValueException e) {
+      if (_parsingContext.Debug) {
+        _parsingContext.Configuration.Logger.Log(_parsingContext, e);
+      }
+      return new(e.ErrorValue, DataType.ExcelError);
+    }
+  }
+
+  public override Expression PrepareForNextChild() {
+    return base.AddChild(new FunctionArgumentExpression(this));
+  }
+
+  public override bool HasChildren => (Children.Any() && Children.First().Children.Any());
+
+  public override Expression AddChild(Expression child) {
+    Children.Last().AddChild(child);
+    return child;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/GroupExpression.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/GroupExpression.cs
new file mode 100644
index 0000000..6fc8152
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/GroupExpression.cs
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public class GroupExpression : Expression {
+  public GroupExpression(bool isNegated)
+      : this(isNegated, new ExpressionCompiler()) {}
+
+  public GroupExpression(bool isNegated, IExpressionCompiler expressionCompiler) {
+    _expressionCompiler = expressionCompiler;
+    _isNegated = isNegated;
+  }
+
+  private readonly IExpressionCompiler _expressionCompiler;
+  private readonly bool _isNegated;
+
+  public override CompileResult Compile() {
+    var result = _expressionCompiler.Compile(Children);
+    if (result.IsNumeric && _isNegated) {
+      return new(result.ResultNumeric * -1, result.DataType);
+    }
+    return result;
+  }
+
+  public override bool IsGroupedExpression => true;
+
+  public bool IsNegated => _isNegated;
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/IExpressionCompiler.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/IExpressionCompiler.cs
new file mode 100644
index 0000000..cdfbc64
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/IExpressionCompiler.cs
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public interface IExpressionCompiler {
+  CompileResult Compile(IEnumerable<Expression> expressions);
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/IExpressionConverter.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/IExpressionConverter.cs
new file mode 100644
index 0000000..737ca8e
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/IExpressionConverter.cs
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public interface IExpressionConverter {
+  StringExpression ToStringExpression(Expression expression);
+
+  Expression FromCompileResult(CompileResult compileResult);
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/IExpressionFactory.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/IExpressionFactory.cs
new file mode 100644
index 0000000..3b0015f
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/IExpressionFactory.cs
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+public interface IExpressionFactory {
+  Expression Create(Token token);
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/IExpressionGraphBuilder.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/IExpressionGraphBuilder.cs
new file mode 100644
index 0000000..d514970
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/IExpressionGraphBuilder.cs
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public interface IExpressionGraphBuilder {
+  ExpressionGraph Build(IEnumerable<Token> tokens);
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/IntegerExpression.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/IntegerExpression.cs
new file mode 100644
index 0000000..90afbc8
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/IntegerExpression.cs
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System;
+using System.Globalization;
+
+namespace AppsheetEpplus;
+
+public class IntegerExpression : AtomicExpression {
+  private readonly double? _compiledValue;
+  private readonly bool _negate;
+
+  public IntegerExpression(string expression)
+      : this(expression, false) {}
+
+  public IntegerExpression(string expression, bool negate)
+      : base(expression) {
+    _negate = negate;
+  }
+
+  public IntegerExpression(double val)
+      : base(val.ToString(CultureInfo.InvariantCulture)) {
+    _compiledValue = Math.Floor(val);
+  }
+
+  public override CompileResult Compile() {
+    double result = _compiledValue ?? double.Parse(ExpressionString, CultureInfo.InvariantCulture);
+    result = _negate ? result * -1 : result;
+    return new(result, DataType.Integer);
+  }
+
+  public bool IsNegated => _negate;
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/NamedValueExpression.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/NamedValueExpression.cs
new file mode 100644
index 0000000..0416b0d
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/NamedValueExpression.cs
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class NamedValueExpression : AtomicExpression {
+  public NamedValueExpression(string expression, ParsingContext parsingContext)
+      : base(expression) {
+    _parsingContext = parsingContext;
+  }
+
+  private readonly ParsingContext _parsingContext;
+
+  public override CompileResult Compile() {
+    var c = _parsingContext.Scopes.Current;
+    var name = _parsingContext.ExcelDataProvider.GetName(c.Address.Worksheet, ExpressionString);
+    //var result = _parsingContext.Parser.Parse(value.ToString());
+
+    if (name == null) {
+      throw (new ExcelErrorValueException(ExcelErrorValue.Create(eErrorType.Name)));
+    }
+    if (name.Value == null) {
+      return null;
+    }
+    if (name.Value is ExcelDataProvider.IRangeInfo range) {
+      if (range.IsMulti) {
+        return new(range, DataType.Enumerable);
+      }
+      if (range.IsEmpty) {
+        return null;
+      }
+      var factory = new CompileResultFactory();
+      return factory.Create(range.First().Value);
+    }
+    {
+      var factory = new CompileResultFactory();
+      return factory.Create(name.Value);
+    }
+
+    //return new CompileResultFactory().Create(result);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ExpressionGraph/StringExpression.cs b/AppsheetEpplus/FormulaParsing/ExpressionGraph/StringExpression.cs
new file mode 100644
index 0000000..623dd53
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ExpressionGraph/StringExpression.cs
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public class StringExpression : AtomicExpression {
+  public StringExpression(string expression)
+      : base(expression) {}
+
+  public override CompileResult Compile() {
+    return new(ExpressionString, DataType.String);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/FormulaParser.cs b/AppsheetEpplus/FormulaParsing/FormulaParser.cs
new file mode 100644
index 0000000..9988be8
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/FormulaParser.cs
@@ -0,0 +1,191 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+public class FormulaParser {
+  private readonly ParsingContext _parsingContext;
+  private readonly ExcelDataProvider _excelDataProvider;
+
+  public FormulaParser(ExcelDataProvider excelDataProvider)
+      : this(excelDataProvider, ParsingContext.Create()) {}
+
+  public FormulaParser(ExcelDataProvider excelDataProvider, ParsingContext parsingContext) {
+    parsingContext.Parser = this;
+    parsingContext.ExcelDataProvider = excelDataProvider;
+    parsingContext.NameValueProvider = new EpplusNameValueProvider(excelDataProvider);
+    parsingContext.RangeAddressFactory = new(excelDataProvider);
+    _parsingContext = parsingContext;
+    _excelDataProvider = excelDataProvider;
+    Configure(configuration => {
+      configuration
+          .SetLexer(
+              new Lexer(
+                  _parsingContext.Configuration.FunctionRepository,
+                  _parsingContext.NameValueProvider))
+          .SetGraphBuilder(new ExpressionGraphBuilder(excelDataProvider, _parsingContext))
+          .SetExpresionCompiler(new ExpressionCompiler())
+          .FunctionRepository.LoadModule(new BuiltInFunctions());
+    });
+  }
+
+  public void Configure(Action<ParsingConfiguration> configMethod) {
+    configMethod.Invoke(_parsingContext.Configuration);
+    _lexer = _parsingContext.Configuration.Lexer ?? _lexer;
+    _graphBuilder = _parsingContext.Configuration.GraphBuilder ?? _graphBuilder;
+    _compiler = _parsingContext.Configuration.ExpressionCompiler ?? _compiler;
+  }
+
+  private ILexer _lexer;
+  private IExpressionGraphBuilder _graphBuilder;
+  private IExpressionCompiler _compiler;
+
+  public ILexer Lexer => _lexer;
+
+  public IEnumerable<string> FunctionNames =>
+    _parsingContext.Configuration.FunctionRepository.FunctionNames;
+
+  internal virtual object Parse(string formula, RangeAddress rangeAddress) {
+    using (var scope = _parsingContext.Scopes.NewScope(rangeAddress)) {
+      var tokens = _lexer.Tokenize(formula);
+      var graph = _graphBuilder.Build(tokens);
+      if (graph.Expressions.Count() == 0) {
+        return null;
+      }
+      return _compiler.Compile(graph.Expressions).Result;
+    }
+  }
+
+  internal virtual object Parse(IEnumerable<Token> tokens, string worksheet, string address) {
+    var rangeAddress = _parsingContext.RangeAddressFactory.Create(address);
+    using (var scope = _parsingContext.Scopes.NewScope(rangeAddress)) {
+      var graph = _graphBuilder.Build(tokens);
+      if (graph.Expressions.Count() == 0) {
+        return null;
+      }
+      return _compiler.Compile(graph.Expressions).Result;
+    }
+  }
+
+  internal virtual object ParseCell(
+      IEnumerable<Token> tokens,
+      string worksheet,
+      int row,
+      int column) {
+    var rangeAddress = _parsingContext.RangeAddressFactory.Create(worksheet, column, row);
+    using (var scope = _parsingContext.Scopes.NewScope(rangeAddress)) {
+      //    _parsingContext.Dependencies.AddFormulaScope(scope);
+      var graph = _graphBuilder.Build(tokens);
+      if (graph.Expressions.Count() == 0) {
+        return 0d;
+      }
+      try {
+        var compileResult = _compiler.Compile(graph.Expressions);
+        // quick solution for the fact that an excelrange can be returned.
+        var rangeInfo = compileResult.Result as ExcelDataProvider.IRangeInfo;
+        if (rangeInfo == null) {
+          return compileResult.Result ?? 0d;
+        }
+        if (rangeInfo.IsEmpty) {
+          return 0d;
+        }
+        if (!rangeInfo.IsMulti) {
+          return rangeInfo.First().Value ?? 0d;
+        }
+        // ok to return multicell if it is a workbook scoped name.
+        if (string.IsNullOrEmpty(worksheet)) {
+          return rangeInfo;
+        }
+        if (_parsingContext.Debug) {
+          var msg = string.Format(
+              "A range with multiple cell was returned at row {0}, column {1}",
+              row,
+              column);
+          _parsingContext.Configuration.Logger.Log(_parsingContext, msg);
+        }
+        return ExcelErrorValue.Create(eErrorType.Value);
+      } catch (ExcelErrorValueException ex) {
+        if (_parsingContext.Debug) {
+          _parsingContext.Configuration.Logger.Log(_parsingContext, ex);
+        }
+        return ex.ErrorValue;
+      }
+    }
+  }
+
+  public virtual object Parse(string formula, string address) {
+    return Parse(formula, _parsingContext.RangeAddressFactory.Create(address));
+  }
+
+  public virtual object Parse(string formula) {
+    return Parse(formula, RangeAddress.Empty);
+  }
+
+  public virtual object ParseAt(string address) {
+    Require.That(address).Named("address").IsNotNullOrEmpty();
+    var rangeAddress = _parsingContext.RangeAddressFactory.Create(address);
+    return ParseAt(rangeAddress.Worksheet, rangeAddress.FromRow, rangeAddress.FromCol);
+  }
+
+  public virtual object ParseAt(string worksheetName, int row, int col) {
+    var f = _excelDataProvider.GetRangeFormula(worksheetName, row, col);
+    if (string.IsNullOrEmpty(f)) {
+      return _excelDataProvider.GetRangeValue(worksheetName, row, col);
+    }
+    return Parse(f, _parsingContext.RangeAddressFactory.Create(worksheetName, col, row));
+    //var dataItem = _excelDataProvider.GetRangeValues(address).FirstOrDefault();
+    //if (dataItem == null /*|| (dataItem.Value == null && dataItem.Formula == null)*/) return null;
+    //if (!string.IsNullOrEmpty(dataItem.Formula))
+    //{
+    //    return Parse(dataItem.Formula, _parsingContext.RangeAddressFactory.Create(address));
+    //}
+    //return Parse(dataItem.Value.ToString(), _parsingContext.RangeAddressFactory.Create(address));
+  }
+
+  internal void InitNewCalc() {
+    if (_excelDataProvider != null) {
+      _excelDataProvider.Reset();
+    }
+  }
+
+  // Praveen's Formula Parser
+  public ExpressionGraph ParseToGraph(string formula) {
+    using (var scope = _parsingContext.Scopes.NewScope(RangeAddress.Empty)) {
+      var tokens = _lexer.Tokenize(formula);
+      var graph = _graphBuilder.Build(tokens);
+      return graph;
+    }
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/FormulaParserManager.cs b/AppsheetEpplus/FormulaParsing/FormulaParserManager.cs
new file mode 100644
index 0000000..9b5b6f5
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/FormulaParserManager.cs
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Provides access to various functionality regarding
+/// excel formula evaluation.
+/// </summary>
+public class FormulaParserManager {
+  private readonly FormulaParser _parser;
+
+  internal FormulaParserManager(FormulaParser parser) {
+    Require.That(parser).Named("parser").IsNotNull();
+    _parser = parser;
+  }
+
+  /// <summary>
+  /// Loads a module containing custom functions to the formula parser. By using
+  /// this method you can add your own implementations of Excel functions, by
+  /// implementing a <see cref="IFunctionModule"/>.
+  /// </summary>
+  /// <param name="module">A <see cref="IFunctionModule"/> containing <see cref="ExcelFunction"/>s.</param>
+  public void LoadFunctionModule(IFunctionModule module) {
+    _parser.Configure(x => x.FunctionRepository.LoadModule(module));
+  }
+
+  /// <summary>
+  /// If the supplied <paramref name="functionName"/> does not exist, the supplied
+  /// <paramref name="functionImpl"/> implementation will be added to the formula parser.
+  /// If it exists, the existing function will be replaced by the supplied <paramref name="functionImpl">function implementation</paramref>
+  /// </summary>
+  /// <param name="functionName"></param>
+  /// <param name="functionImpl"></param>
+  public void AddOrReplaceFunction(string functionName, ExcelFunction functionImpl) {
+    _parser.Configure(x => x.FunctionRepository.AddOrReplaceFunction(functionName, functionImpl));
+  }
+
+  /// <summary>
+  /// Returns an enumeration of all functions implemented, both the built in functions
+  /// and functions added using the LoadFunctionModule method of this class.
+  /// </summary>
+  /// <returns>Function names in lower case</returns>
+  public IEnumerable<string> GetImplementedFunctionNames() {
+    var fnList = _parser.FunctionNames.ToList();
+    fnList.Sort((x, y) => String.Compare(x, y, StringComparison.Ordinal));
+    return fnList;
+  }
+
+  /// <summary>
+  /// Parses the supplied <paramref name="formula"/> and returns the result.
+  /// </summary>
+  /// <param name="formula"></param>
+  /// <returns></returns>
+  public object Parse(string formula) {
+    return _parser.Parse(formula);
+  }
+
+  // Praveen's Parser Support
+  public ExpressionGraph ParseToGraph(string formula) {
+    return _parser.ParseToGraph(formula);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/INameValueProvider.cs b/AppsheetEpplus/FormulaParsing/INameValueProvider.cs
new file mode 100644
index 0000000..e4c59b5
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/INameValueProvider.cs
@@ -0,0 +1,9 @@
+namespace AppsheetEpplus;
+
+public interface INameValueProvider {
+  bool IsNamedValue(string key, string worksheet);
+
+  object GetNamedValue(string key);
+
+  void Reload();
+}
diff --git a/AppsheetEpplus/FormulaParsing/IParsingLifetimeEventHandler.cs b/AppsheetEpplus/FormulaParsing/IParsingLifetimeEventHandler.cs
new file mode 100644
index 0000000..f4eeed6
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/IParsingLifetimeEventHandler.cs
@@ -0,0 +1,5 @@
+namespace AppsheetEpplus;
+
+public interface IParsingLifetimeEventHandler {
+  void ParsingCompleted();
+}
diff --git a/AppsheetEpplus/FormulaParsing/LexicalAnalysis/ILexer.cs b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/ILexer.cs
new file mode 100644
index 0000000..b765128
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/ILexer.cs
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public interface ILexer {
+  IEnumerable<Token> Tokenize(string input);
+
+  IEnumerable<Token> Tokenize(string input, string worksheet);
+}
diff --git a/AppsheetEpplus/FormulaParsing/LexicalAnalysis/ISourceCodeTokenizer.cs b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/ISourceCodeTokenizer.cs
new file mode 100644
index 0000000..1d16343
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/ISourceCodeTokenizer.cs
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public interface ISourceCodeTokenizer {
+  IEnumerable<Token> Tokenize(string input, string worksheet);
+}
diff --git a/AppsheetEpplus/FormulaParsing/LexicalAnalysis/ISyntacticAnalyzer.cs b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/ISyntacticAnalyzer.cs
new file mode 100644
index 0000000..bf24a33
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/ISyntacticAnalyzer.cs
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public interface ISyntacticAnalyzer {
+  void Analyze(IEnumerable<Token> tokens);
+}
diff --git a/AppsheetEpplus/FormulaParsing/LexicalAnalysis/ITokenFactory.cs b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/ITokenFactory.cs
new file mode 100644
index 0000000..e5c2e4d
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/ITokenFactory.cs
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public interface ITokenFactory {
+  Token Create(IEnumerable<Token> tokens, string token);
+
+  Token Create(IEnumerable<Token> tokens, string token, string worksheet);
+
+  Token Create(string token, TokenType explicitTokenType);
+}
diff --git a/AppsheetEpplus/FormulaParsing/LexicalAnalysis/ITokenIndexProvider.cs b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/ITokenIndexProvider.cs
new file mode 100644
index 0000000..3c203d7
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/ITokenIndexProvider.cs
@@ -0,0 +1,7 @@
+namespace AppsheetEpplus;
+
+public interface ITokenIndexProvider {
+  int Index { get; }
+
+  void MoveIndexPointerForward();
+}
diff --git a/AppsheetEpplus/FormulaParsing/LexicalAnalysis/ITokenSeparatorProvider.cs b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/ITokenSeparatorProvider.cs
new file mode 100644
index 0000000..48b7efa
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/ITokenSeparatorProvider.cs
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public interface ITokenSeparatorProvider {
+  IDictionary<string, Token> Tokens { get; }
+
+  bool IsOperator(string item);
+
+  bool IsPossibleLastPartOfMultipleCharOperator(string part);
+}
diff --git a/AppsheetEpplus/FormulaParsing/LexicalAnalysis/Lexer.cs b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/Lexer.cs
new file mode 100644
index 0000000..0dc1cef
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/Lexer.cs
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+//
+namespace AppsheetEpplus;
+
+public class Lexer : ILexer {
+  public Lexer(FunctionRepository functionRepository, INameValueProvider nameValueProvider)
+      : this(
+          new SourceCodeTokenizer(functionRepository, nameValueProvider),
+          new SyntacticAnalyzer()) {}
+
+  public Lexer(ISourceCodeTokenizer tokenizer, ISyntacticAnalyzer analyzer) {
+    _tokenizer = tokenizer;
+    _analyzer = analyzer;
+  }
+
+  private readonly ISourceCodeTokenizer _tokenizer;
+  private readonly ISyntacticAnalyzer _analyzer;
+
+  public IEnumerable<Token> Tokenize(string input) {
+    return Tokenize(input, null);
+  }
+
+  public IEnumerable<Token> Tokenize(string input, string worksheet) {
+    var tokens = _tokenizer.Tokenize(input, worksheet);
+    _analyzer.Analyze(tokens);
+    return tokens;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/LexicalAnalysis/SourceCodeTokenizer.cs b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/SourceCodeTokenizer.cs
new file mode 100644
index 0000000..3a6a006
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/SourceCodeTokenizer.cs
@@ -0,0 +1,296 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text.RegularExpressions;
+
+namespace AppsheetEpplus;
+
+public class SourceCodeTokenizer : ISourceCodeTokenizer {
+  public static ISourceCodeTokenizer Default =>
+    new SourceCodeTokenizer(FunctionNameProvider.Empty, NameValueProvider.Empty);
+
+  public SourceCodeTokenizer(
+      IFunctionNameProvider functionRepository,
+      INameValueProvider nameValueProvider)
+      : this(
+          new TokenFactory(functionRepository, nameValueProvider),
+          new TokenSeparatorProvider()) {}
+
+  public SourceCodeTokenizer(ITokenFactory tokenFactory, ITokenSeparatorProvider tokenProvider) {
+    _tokenFactory = tokenFactory;
+    _tokenProvider = tokenProvider;
+  }
+
+  private readonly ITokenSeparatorProvider _tokenProvider;
+  private readonly ITokenFactory _tokenFactory;
+
+  public IEnumerable<Token> Tokenize(string input) {
+    return Tokenize(input, null);
+  }
+
+  public IEnumerable<Token> Tokenize(string input, string worksheet) {
+    if (string.IsNullOrEmpty(input)) {
+      return [];
+    }
+    // MA 1401: Ignore leading plus in formula.
+    input = input.TrimStart('+');
+    var context = new TokenizerContext(input);
+
+    bool isSingleQuoteString = false;
+    for (int i = 0; i < context.FormulaChars.Length; i++) {
+      var c = context.FormulaChars[i];
+      if (CharIsTokenSeparator(c, out var tokenSeparator)) {
+        if (context.IsInString) {
+          if (IsDoubleQuote(tokenSeparator, i, context)) {
+            i++;
+            context.AppendToCurrentToken(c);
+            continue;
+          }
+          if (tokenSeparator.TokenType != TokenType.String) {
+            context.AppendToCurrentToken(c);
+            continue;
+          }
+          // CHANGE 2
+          if ((isSingleQuoteString && c != '\'') || (!isSingleQuoteString && c != '"')) {
+            context.AppendToCurrentToken(c);
+            continue;
+          }
+        }
+        if (tokenSeparator.TokenType == TokenType.OpeningBracket) {
+          context.AppendToCurrentToken(c);
+          context.BracketCount++;
+          continue;
+        }
+        if (tokenSeparator.TokenType == TokenType.ClosingBracket) {
+          context.AppendToCurrentToken(c);
+          context.BracketCount--;
+          continue;
+        }
+        if (context.BracketCount > 0) {
+          context.AppendToCurrentToken(c);
+          continue;
+        }
+        // two operators in sequence could be "<=" or ">="
+        if (IsPartOfMultipleCharSeparator(context, c)) {
+          var sOp = context.LastToken.Value + c.ToString(CultureInfo.InvariantCulture);
+          var op = _tokenProvider.Tokens[sOp];
+          context.ReplaceLastToken(op);
+          context.NewToken();
+          continue;
+        }
+        if (tokenSeparator.TokenType == TokenType.String) {
+          // CHANGE3 :
+          isSingleQuoteString = (c == '\'');
+          if (context.LastToken != null
+              && context.LastToken.TokenType == TokenType.OpeningEnumerable) {
+            // context.AppendToCurrentToken(c);  // Praveen's change of 10/28/2015
+            context.ToggleIsInString();
+            continue;
+          }
+          if (context.LastToken != null && context.LastToken.TokenType == TokenType.String) {
+            context.AddToken(
+                !context.CurrentTokenHasValue
+                    ? new(string.Empty, TokenType.StringContent)
+                    : new Token(context.CurrentToken, TokenType.StringContent));
+          }
+          context.AddToken(new("\"", TokenType.String));
+          context.ToggleIsInString();
+          context.NewToken();
+          continue;
+        }
+        if (context.CurrentTokenHasValue) {
+          if (Regex.IsMatch(context.CurrentToken, "^\"*$")) {
+            context.AddToken(_tokenFactory.Create(context.CurrentToken, TokenType.StringContent));
+          } else {
+            context.AddToken(CreateToken(context, worksheet));
+          }
+
+          //If the a next token is an opening parantheses and the previous token is interpeted as an address or name, then the currenct token is a function
+          if (tokenSeparator.TokenType == TokenType.OpeningParenthesis
+              && (context.LastToken.TokenType == TokenType.ExcelAddress
+                      || context.LastToken.TokenType == TokenType.NameValue)) {
+            context.LastToken.TokenType = TokenType.Function;
+          }
+        }
+        if (tokenSeparator.Value == "-") {
+          if (TokenIsNegator(context)) {
+            context.AddToken(new("-", TokenType.Negator));
+            continue;
+          }
+        }
+        context.AddToken(tokenSeparator);
+        context.NewToken();
+        continue;
+      }
+      context.AppendToCurrentToken(c);
+    }
+    if (context.CurrentTokenHasValue) {
+      context.AddToken(CreateToken(context, worksheet));
+    }
+
+    CleanupTokens(context, _tokenProvider.Tokens);
+
+    return context.Result;
+  }
+
+  private static bool IsDoubleQuote(
+      Token tokenSeparator,
+      int formulaCharIndex,
+      TokenizerContext context) {
+    return tokenSeparator.TokenType == TokenType.String
+        && formulaCharIndex + 1 < context.FormulaChars.Length
+        && context.FormulaChars[formulaCharIndex + 1] == '\"';
+  }
+
+  private static void CleanupTokens(TokenizerContext context, IDictionary<string, Token> tokens) {
+    for (int i = 0; i < context.Result.Count; i++) {
+      var token = context.Result[i];
+      if (token.TokenType == TokenType.Unrecognized) {
+        if (i < context.Result.Count - 1) {
+          if (context.Result[i + 1].TokenType == TokenType.OpeningParenthesis) {
+            token.TokenType = TokenType.Function;
+          } else {
+            token.TokenType = TokenType.NameValue;
+          }
+        } else {
+          token.TokenType = TokenType.NameValue;
+        }
+      } else if (token.TokenType == TokenType.Function) {
+        if (i < context.Result.Count - 1) {
+          if (context.Result[i + 1].TokenType == TokenType.OpeningParenthesis) {
+            token.TokenType = TokenType.Function;
+          } else {
+            token.TokenType = TokenType.Unrecognized;
+          }
+        } else {
+          token.TokenType = TokenType.Unrecognized;
+        }
+      } else if ((token.TokenType == TokenType.Operator || token.TokenType == TokenType.Negator)
+          && i < context.Result.Count - 1
+          && (token.Value == "+" || token.Value == "-")) {
+        if (i > 0
+            && token.Value
+                == "+") //Remove any + with an opening parenthesis before.
+        {
+          if (context.Result[i - 1].TokenType == TokenType.OpeningParenthesis) {
+            context.Result.RemoveAt(i);
+            SetNegatorOperator(context, i, tokens);
+            i--;
+            continue;
+          }
+        }
+
+        var nextToken = context.Result[i + 1];
+        if (nextToken.TokenType == TokenType.Operator || nextToken.TokenType == TokenType.Negator) {
+          if (token.Value == "+" && (nextToken.Value == "+" || nextToken.Value == "-")) {
+            //Remove first
+            context.Result.RemoveAt(i);
+            SetNegatorOperator(context, i, tokens);
+            i--;
+          } else if (token.Value == "-" && nextToken.Value == "+") {
+            //Remove second
+            context.Result.RemoveAt(i + 1);
+            SetNegatorOperator(context, i, tokens);
+            i--;
+          } else if (token.Value == "-" && nextToken.Value == "-") {
+            //Remove first and set operator to +
+            context.Result.RemoveAt(i);
+            if (i == 0) {
+              context.Result.RemoveAt(i + 1);
+              i += 2;
+            } else {
+              //context.Result[i].TokenType = TokenType.Operator;
+              //context.Result[i].Value = "+";
+              context.Result[i] = tokens["+"];
+              SetNegatorOperator(context, i, tokens);
+              i--;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  private static void SetNegatorOperator(
+      TokenizerContext context,
+      int i,
+      IDictionary<string, Token> tokens) {
+    if (context.Result[i].Value == "-"
+        && i > 0
+        && (context.Result[i].TokenType == TokenType.Operator
+                || context.Result[i].TokenType == TokenType.Negator)) {
+      if (TokenIsNegator(context.Result[i - 1])) {
+        context.Result[i] = new("-", TokenType.Negator);
+      } else {
+        context.Result[i] = tokens["-"];
+      }
+    }
+  }
+
+  private static bool TokenIsNegator(TokenizerContext context) {
+    return TokenIsNegator(context.LastToken);
+  }
+
+  private static bool TokenIsNegator(Token t) {
+    return t == null
+        || t.TokenType == TokenType.Operator
+        || t.TokenType == TokenType.OpeningParenthesis
+        || t.TokenType == TokenType.Comma
+        || t.TokenType == TokenType.SemiColon
+        || t.TokenType == TokenType.OpeningEnumerable;
+  }
+
+  private bool IsPartOfMultipleCharSeparator(TokenizerContext context, char c) {
+    var lastToken = context.LastToken != null ? context.LastToken.Value : string.Empty;
+    return _tokenProvider.IsOperator(lastToken)
+        && _tokenProvider.IsPossibleLastPartOfMultipleCharOperator(
+            c.ToString(CultureInfo.InvariantCulture))
+        && !context.CurrentTokenHasValue;
+  }
+
+  private Token CreateToken(TokenizerContext context, string worksheet) {
+    if (context.CurrentToken == "-") {
+      if (context.LastToken == null && context.LastToken.TokenType == TokenType.Operator) {
+        return new("-", TokenType.Negator);
+      }
+    }
+    return _tokenFactory.Create(context.Result, context.CurrentToken, worksheet);
+  }
+
+  private bool CharIsTokenSeparator(char c, out Token token) {
+    var result = _tokenProvider.Tokens.ContainsKey(c.ToString());
+    token = result ? token = _tokenProvider.Tokens[c.ToString()] : null;
+    return result;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/LexicalAnalysis/SyntacticAnalyzer.cs b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/SyntacticAnalyzer.cs
new file mode 100644
index 0000000..fe25778
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/SyntacticAnalyzer.cs
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class SyntacticAnalyzer : ISyntacticAnalyzer {
+  private class AnalyzingContext {
+    public int NumberOfOpenedParentheses { get; set; }
+
+    public int NumberOfClosedParentheses { get; set; }
+
+    public int OpenedStrings { get; set; }
+
+    public int ClosedStrings { get; set; }
+
+    public bool IsInString { get; set; }
+  }
+
+  public void Analyze(IEnumerable<Token> tokens) {
+    var context = new AnalyzingContext();
+    foreach (var token in tokens) {
+      if (token.TokenType == TokenType.Unrecognized) {
+        throw new UnrecognizedTokenException(token);
+      }
+      EnsureParenthesesAreWellFormed(token, context);
+      EnsureStringsAreWellFormed(token, context);
+    }
+    Validate(context);
+  }
+
+  private static void Validate(AnalyzingContext context) {
+    if (context.NumberOfOpenedParentheses != context.NumberOfClosedParentheses) {
+      throw new FormatException("Number of opened and closed parentheses does not match");
+    }
+    if (context.OpenedStrings != context.ClosedStrings) {
+      throw new FormatException("Unterminated string");
+    }
+  }
+
+  private void EnsureParenthesesAreWellFormed(Token token, AnalyzingContext context) {
+    if (token.TokenType == TokenType.OpeningParenthesis) {
+      context.NumberOfOpenedParentheses++;
+    } else if (token.TokenType == TokenType.ClosingParenthesis) {
+      context.NumberOfClosedParentheses++;
+    }
+  }
+
+  private void EnsureStringsAreWellFormed(Token token, AnalyzingContext context) {
+    if (!context.IsInString && token.TokenType == TokenType.String) {
+      context.IsInString = true;
+      context.OpenedStrings++;
+    } else if (context.IsInString && token.TokenType == TokenType.String) {
+      context.IsInString = false;
+      context.ClosedStrings++;
+    }
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/LexicalAnalysis/Token.cs b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/Token.cs
new file mode 100644
index 0000000..c4d1977
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/Token.cs
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public class Token {
+  public Token(string token, TokenType tokenType) {
+    Value = token;
+    TokenType = tokenType;
+  }
+
+  public string Value { get; internal set; }
+
+  public TokenType TokenType { get; internal set; }
+
+  public void Append(string stringToAppend) {
+    Value += stringToAppend;
+  }
+
+  public bool IsNegated { get; private set; }
+
+  public void Negate() {
+    if (TokenType == TokenType.Decimal
+        || TokenType == TokenType.Integer
+        || TokenType == TokenType.ExcelAddress) {
+      IsNegated = true;
+    }
+  }
+
+  public override string ToString() {
+    return TokenType + ", " + Value;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/LexicalAnalysis/TokenFactory.cs b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/TokenFactory.cs
new file mode 100644
index 0000000..1dd3084
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/TokenFactory.cs
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ * Jan Källman                      Replaced Adress validate    2013-03-01
+ * *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text.RegularExpressions;
+
+namespace AppsheetEpplus;
+
+public class TokenFactory : ITokenFactory {
+  public TokenFactory(
+      IFunctionNameProvider functionRepository,
+      INameValueProvider nameValueProvider)
+      : this(new TokenSeparatorProvider(), nameValueProvider, functionRepository) {}
+
+  public TokenFactory(
+      ITokenSeparatorProvider tokenSeparatorProvider,
+      INameValueProvider nameValueProvider,
+      IFunctionNameProvider functionNameProvider) {
+    _tokenSeparatorProvider = tokenSeparatorProvider;
+    _functionNameProvider = functionNameProvider;
+    _nameValueProvider = nameValueProvider;
+  }
+
+  private readonly ITokenSeparatorProvider _tokenSeparatorProvider;
+  private readonly IFunctionNameProvider _functionNameProvider;
+  private readonly INameValueProvider _nameValueProvider;
+
+  public Token Create(IEnumerable<Token> tokens, string token) {
+    return Create(tokens, token, null);
+  }
+
+  public Token Create(IEnumerable<Token> tokens, string token, string worksheet) {
+    if (_tokenSeparatorProvider.Tokens.TryGetValue(token, out var tokenSeparator)) {
+      return tokenSeparator;
+    }
+    var tokenList = (IList<Token>)tokens;
+    //Address with worksheet-string before  /JK
+    if (token.StartsWith("!") && tokenList[tokenList.Count - 1].TokenType == TokenType.String) {
+      var i = tokenList.Count - 2;
+      if (i > 0) {
+        string addr;
+        if (tokenList[i].TokenType == TokenType.StringContent) {
+          addr = "'" + tokenList[i].Value.Replace("'", "''") + "'";
+        } else {
+          throw (new ArgumentException(
+                  string.Format("Invalid formula token sequence near {0}", token)));
+        }
+        //Remove the string tokens and content
+        tokenList.RemoveAt(tokenList.Count - 1);
+        tokenList.RemoveAt(tokenList.Count - 1);
+        tokenList.RemoveAt(tokenList.Count - 1);
+
+        return new(addr + token, TokenType.ExcelAddress);
+      }
+      throw (new ArgumentException(
+              string.Format("Invalid formula token sequence near {0}", token)));
+    }
+
+    if (tokens.Any() && tokens.Last().TokenType == TokenType.String) {
+      return new(token, TokenType.StringContent);
+    }
+    if (!string.IsNullOrEmpty(token)) {
+      token = token.Trim();
+    }
+    if (Regex.IsMatch(token, RegexConstants.Decimal)) {
+      return new(token, TokenType.Decimal);
+    }
+    if (Regex.IsMatch(token, RegexConstants.Integer)) {
+      return new(token, TokenType.Integer);
+    }
+    if (Regex.IsMatch(token, RegexConstants.Boolean, RegexOptions.IgnoreCase)) {
+      return new(token, TokenType.Boolean);
+    }
+    if (token.ToUpper(CultureInfo.InvariantCulture).Contains("#REF!")) {
+      return new(token, TokenType.InvalidReference);
+    }
+    if (token.ToUpper(CultureInfo.InvariantCulture) == "#NUM!") {
+      return new(token, TokenType.NumericError);
+    }
+    if (token.ToUpper(CultureInfo.InvariantCulture) == "#VALUE!") {
+      return new(token, TokenType.ValueDataTypeError);
+    }
+    if (token.ToUpper(CultureInfo.InvariantCulture) == "#NULL!") {
+      return new(token, TokenType.Null);
+    }
+    if (_nameValueProvider != null && _nameValueProvider.IsNamedValue(token, worksheet)) {
+      return new(token, TokenType.NameValue);
+    }
+    if (_functionNameProvider.IsFunctionName(token)) {
+      return new(token, TokenType.Function);
+    }
+    if (tokenList.Count > 0
+        && tokenList[tokenList.Count - 1].TokenType == TokenType.OpeningEnumerable) {
+      return new(token, TokenType.Enumerable);
+    }
+    var at = ExcelAddressBase.IsValid(token);
+    if (at == ExcelAddressBase.AddressType.InternalAddress) {
+      return new(token.ToUpper(CultureInfo.InvariantCulture), TokenType.ExcelAddress);
+    }
+    return new(token, TokenType.Unrecognized);
+  }
+
+  public Token Create(string token, TokenType explicitTokenType) {
+    return new(token, explicitTokenType);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/LexicalAnalysis/TokenSeparatorProvider.cs b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/TokenSeparatorProvider.cs
new file mode 100644
index 0000000..ceeb6a8
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/TokenSeparatorProvider.cs
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+public class TokenSeparatorProvider : ITokenSeparatorProvider {
+  private static readonly Dictionary<string, Token> _tokens = new();
+
+  static TokenSeparatorProvider() {
+    _tokens.Add("+", new("+", TokenType.Operator));
+    _tokens.Add("-", new("-", TokenType.Operator));
+    _tokens.Add("*", new("*", TokenType.Operator));
+    _tokens.Add("/", new("/", TokenType.Operator));
+    _tokens.Add("^", new("^", TokenType.Operator));
+    _tokens.Add("&", new("&", TokenType.Operator));
+    _tokens.Add(">", new(">", TokenType.Operator));
+    _tokens.Add("<", new("<", TokenType.Operator));
+    _tokens.Add("=", new("=", TokenType.Operator));
+    _tokens.Add("<=", new("<=", TokenType.Operator));
+    _tokens.Add(">=", new(">=", TokenType.Operator));
+    _tokens.Add("<>", new("<>", TokenType.Operator));
+    _tokens.Add("(", new("(", TokenType.OpeningParenthesis));
+    _tokens.Add(")", new(")", TokenType.ClosingParenthesis));
+    _tokens.Add("{", new("{", TokenType.OpeningEnumerable));
+    _tokens.Add("}", new("}", TokenType.ClosingEnumerable));
+    _tokens.Add("'", new("'", TokenType.String));
+    _tokens.Add("\"", new("\"", TokenType.String));
+    _tokens.Add(",", new(",", TokenType.Comma));
+    _tokens.Add(";", new(";", TokenType.SemiColon));
+    _tokens.Add("[", new("[", TokenType.OpeningBracket));
+    _tokens.Add("]", new("]", TokenType.ClosingBracket));
+    _tokens.Add("%", new("%", TokenType.Percent));
+  }
+
+  IDictionary<string, Token> ITokenSeparatorProvider.Tokens => _tokens;
+
+  public bool IsOperator(string item) {
+    if (_tokens.TryGetValue(item, out var token)) {
+      if (token.TokenType == TokenType.Operator) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  public bool IsPossibleLastPartOfMultipleCharOperator(string part) {
+    return part == "=" || part == ">";
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/LexicalAnalysis/TokenType.cs b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/TokenType.cs
new file mode 100644
index 0000000..0d0e1ff
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/TokenType.cs
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public enum TokenType {
+  Operator,
+  Negator,
+  OpeningParenthesis,
+  ClosingParenthesis,
+  OpeningEnumerable,
+  ClosingEnumerable,
+  OpeningBracket,
+  ClosingBracket,
+  Enumerable,
+  Comma,
+  SemiColon,
+  String,
+  StringContent,
+  Integer,
+  Boolean,
+  Decimal,
+  Percent,
+  Function,
+  ExcelAddress,
+  NameValue,
+  InvalidReference,
+  NumericError,
+  ValueDataTypeError,
+  Null,
+  Unrecognized,
+}
diff --git a/AppsheetEpplus/FormulaParsing/LexicalAnalysis/TokenizerContext.cs b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/TokenizerContext.cs
new file mode 100644
index 0000000..04ee516
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/LexicalAnalysis/TokenizerContext.cs
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace AppsheetEpplus;
+
+public class TokenizerContext {
+  public TokenizerContext(string formula) {
+    if (!string.IsNullOrEmpty(formula)) {
+      _chars = formula.ToArray();
+    }
+  }
+
+  private readonly char[] _chars;
+  private readonly List<Token> _result = new();
+  private StringBuilder _currentToken = new();
+
+  public char[] FormulaChars => _chars;
+
+  public IList<Token> Result => _result;
+
+  public bool IsInString { get; private set; }
+
+  public void ToggleIsInString() {
+    IsInString = !IsInString;
+  }
+
+  internal int BracketCount { get; set; }
+
+  public string CurrentToken => _currentToken.ToString();
+
+  public bool CurrentTokenHasValue =>
+    !string.IsNullOrEmpty(IsInString ? CurrentToken : CurrentToken.Trim());
+
+  public void NewToken() {
+    _currentToken = new();
+  }
+
+  public void AddToken(Token token) {
+    _result.Add(token);
+  }
+
+  public void AppendToCurrentToken(char c) {
+    _currentToken.Append(c.ToString());
+  }
+
+  public void AppendToLastToken(string stringToAppend) {
+    _result.Last().Append(stringToAppend);
+  }
+
+  public void SetLastTokenType(TokenType type) {
+    _result.Last().TokenType = type;
+  }
+
+  public void ReplaceLastToken(Token newToken) {
+    var count = _result.Count;
+    if (count > 0) {
+      _result.RemoveAt(count - 1);
+    }
+    _result.Add(newToken);
+  }
+
+  public Token LastToken => _result.Count > 0 ? _result.Last() : null;
+}
diff --git a/AppsheetEpplus/FormulaParsing/Logging/IFormulaParserLogger.cs b/AppsheetEpplus/FormulaParsing/Logging/IFormulaParserLogger.cs
new file mode 100644
index 0000000..26d5eb2
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Logging/IFormulaParserLogger.cs
@@ -0,0 +1,46 @@
+using System;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Used for logging during FormulaParsing
+/// </summary>
+public interface IFormulaParserLogger : IDisposable {
+  /// <summary>
+  /// Called each time an exception occurs during formula parsing.
+  /// </summary>
+  /// <param name="context"></param>
+  /// <param name="ex"></param>
+  void Log(ParsingContext context, Exception ex);
+
+  /// <summary>
+  /// Called each time information should be logged during formula parsing.
+  /// </summary>
+  /// <param name="context"></param>
+  /// <param name="message"></param>
+  void Log(ParsingContext context, string message);
+
+  /// <summary>
+  /// Called to log a message outside the parsing context.
+  /// </summary>
+  /// <param name="message"></param>
+  void Log(string message);
+
+  /// <summary>
+  /// Called each time a cell within the calc chain is accessed during formula parsing.
+  /// </summary>
+  void LogCellCounted();
+
+  /// <summary>
+  /// Called each time a function is called during formula parsing.
+  /// </summary>
+  /// <param name="func"></param>
+  void LogFunction(string func);
+
+  /// <summary>
+  /// Some functions measure performance, if so this function will be called.
+  /// </summary>
+  /// <param name="func"></param>
+  /// <param name="milliseconds"></param>
+  void LogFunction(string func, long milliseconds);
+}
diff --git a/AppsheetEpplus/FormulaParsing/NameValueProvider.cs b/AppsheetEpplus/FormulaParsing/NameValueProvider.cs
new file mode 100644
index 0000000..6716063
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/NameValueProvider.cs
@@ -0,0 +1,17 @@
+namespace AppsheetEpplus;
+
+public class NameValueProvider : INameValueProvider {
+  private NameValueProvider() {}
+
+  public static INameValueProvider Empty => new NameValueProvider();
+
+  public bool IsNamedValue(string key, string worksheet) {
+    return false;
+  }
+
+  public object GetNamedValue(string key) {
+    return null;
+  }
+
+  public void Reload() {}
+}
diff --git a/AppsheetEpplus/FormulaParsing/ParsedValue.cs b/AppsheetEpplus/FormulaParsing/ParsedValue.cs
new file mode 100644
index 0000000..9671d80
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ParsedValue.cs
@@ -0,0 +1,15 @@
+namespace AppsheetEpplus;
+
+public class ParsedValue {
+  public ParsedValue(object val, int rowIndex, int colIndex) {
+    Value = val;
+    RowIndex = rowIndex;
+    ColIndex = colIndex;
+  }
+
+  public object Value { get; private set; }
+
+  public int RowIndex { get; private set; }
+
+  public int ColIndex { get; private set; }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ParsingConfiguration.cs b/AppsheetEpplus/FormulaParsing/ParsingConfiguration.cs
new file mode 100644
index 0000000..e28f9df
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ParsingConfiguration.cs
@@ -0,0 +1,54 @@
+namespace AppsheetEpplus;
+
+public class ParsingConfiguration {
+  public virtual ILexer Lexer { get; private set; }
+
+  public IFormulaParserLogger Logger { get; private set; }
+
+  public IExpressionGraphBuilder GraphBuilder { get; private set; }
+
+  public IExpressionCompiler ExpressionCompiler { get; private set; }
+
+  public FunctionRepository FunctionRepository { get; private set; } = FunctionRepository.Create();
+
+  private ParsingConfiguration() {}
+
+  internal static ParsingConfiguration Create() {
+    return new();
+  }
+
+  public ParsingConfiguration SetLexer(ILexer lexer) {
+    Lexer = lexer;
+    return this;
+  }
+
+  public ParsingConfiguration SetGraphBuilder(IExpressionGraphBuilder graphBuilder) {
+    GraphBuilder = graphBuilder;
+    return this;
+  }
+
+  public ParsingConfiguration SetExpresionCompiler(IExpressionCompiler expressionCompiler) {
+    ExpressionCompiler = expressionCompiler;
+    return this;
+  }
+
+  /// <summary>
+  /// Attaches a logger, errors and log entries will be written to the logger during the parsing process.
+  /// </summary>
+  /// <param name="logger"></param>
+  /// <returns></returns>
+  public ParsingConfiguration AttachLogger(IFormulaParserLogger logger) {
+    Require.That(logger).Named("logger").IsNotNull();
+    Logger = logger;
+    return this;
+  }
+
+  /// <summary>
+  /// if a logger is attached it will be removed.
+  /// </summary>
+  /// <returns></returns>
+  public ParsingConfiguration DetachLogger() {
+    Logger = null;
+    return this;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ParsingContext.cs b/AppsheetEpplus/FormulaParsing/ParsingContext.cs
new file mode 100644
index 0000000..629ea91
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ParsingContext.cs
@@ -0,0 +1,57 @@
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Parsing context
+/// </summary>
+public class ParsingContext : IParsingLifetimeEventHandler {
+  private ParsingContext() {}
+
+  /// <summary>
+  /// The <see cref="FormulaParser"/> of the current context.
+  /// </summary>
+  public FormulaParser Parser { get; set; }
+
+  /// <summary>
+  /// The <see cref="ExcelDataProvider"/> is an abstraction on top of
+  /// Excel, in this case EPPlus.
+  /// </summary>
+  public ExcelDataProvider ExcelDataProvider { get; set; }
+
+  /// <summary>
+  /// Utility for handling addresses
+  /// </summary>
+  public RangeAddressFactory RangeAddressFactory { get; set; }
+
+  /// <summary>
+  /// <see cref="INameValueProvider"/> of the current context
+  /// </summary>
+  public INameValueProvider NameValueProvider { get; set; }
+
+  /// <summary>
+  /// Configuration
+  /// </summary>
+  public ParsingConfiguration Configuration { get; set; }
+
+  /// <summary>
+  /// Scopes, a scope represents the parsing of a cell or a value.
+  /// </summary>
+  public ParsingScopes Scopes { get; private set; }
+
+  /// <summary>
+  /// Returns true if a <see cref="IFormulaParserLogger"/> is attached to the parser.
+  /// </summary>
+  public bool Debug => Configuration.Logger != null;
+
+  /// <summary>
+  /// Factory method.
+  /// </summary>
+  /// <returns></returns>
+  public static ParsingContext Create() {
+    var context = new ParsingContext();
+    context.Configuration = ParsingConfiguration.Create();
+    context.Scopes = new(context);
+    return context;
+  }
+
+  void IParsingLifetimeEventHandler.ParsingCompleted() {}
+}
diff --git a/AppsheetEpplus/FormulaParsing/ParsingScope.cs b/AppsheetEpplus/FormulaParsing/ParsingScope.cs
new file mode 100644
index 0000000..9b4783f
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ParsingScope.cs
@@ -0,0 +1,43 @@
+using System;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Represents a parsing of a single input or workbook addrses.
+/// </summary>
+public class ParsingScope : IDisposable {
+  private readonly ParsingScopes _parsingScopes;
+
+  public ParsingScope(ParsingScopes parsingScopes, RangeAddress address)
+      : this(parsingScopes, null, address) {}
+
+  public ParsingScope(ParsingScopes parsingScopes, ParsingScope parent, RangeAddress address) {
+    _parsingScopes = parsingScopes;
+    Parent = parent;
+    Address = address;
+  }
+
+  /// <summary>
+  /// Id of the scope.
+  /// </summary>
+  public Guid ScopeId { get; private set; } = Guid.NewGuid();
+
+  /// <summary>
+  /// The calling scope.
+  /// </summary>
+  public ParsingScope Parent { get; private set; }
+
+  /// <summary>
+  /// The address of the cell currently beeing parsed.
+  /// </summary>
+  public RangeAddress Address { get; private set; }
+
+  /// <summary>
+  /// True if the current scope is a Subtotal function beeing executed.
+  /// </summary>
+  public bool IsSubtotal { get; set; }
+
+  public void Dispose() {
+    _parsingScopes.KillScope(this);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/ParsingScopes.cs b/AppsheetEpplus/FormulaParsing/ParsingScopes.cs
new file mode 100644
index 0000000..b500902
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/ParsingScopes.cs
@@ -0,0 +1,50 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// This class implements a stack on which instances of <see cref="ParsingScope"/>
+/// are put. Each ParsingScope represents the parsing of an address in the workbook.
+/// </summary>
+public class ParsingScopes {
+  private readonly IParsingLifetimeEventHandler _lifetimeEventHandler;
+
+  public ParsingScopes(IParsingLifetimeEventHandler lifetimeEventHandler) {
+    _lifetimeEventHandler = lifetimeEventHandler;
+  }
+
+  private readonly Stack<ParsingScope> _scopes = new();
+
+  /// <summary>
+  /// Creates a new <see cref="ParsingScope"/> and puts it on top of the stack.
+  /// </summary>
+  /// <param name="address"></param>
+  /// <returns></returns>
+  public virtual ParsingScope NewScope(RangeAddress address) {
+    ParsingScope scope;
+    if (_scopes.Count() > 0) {
+      scope = new(this, _scopes.Peek(), address);
+    } else {
+      scope = new(this, address);
+    }
+    _scopes.Push(scope);
+    return scope;
+  }
+
+  /// <summary>
+  /// The current parsing scope.
+  /// </summary>
+  public virtual ParsingScope Current => _scopes.Count() > 0 ? _scopes.Peek() : null;
+
+  /// <summary>
+  /// Removes the current scope, setting the calling scope to current.
+  /// </summary>
+  /// <param name="parsingScope"></param>
+  public virtual void KillScope(ParsingScope parsingScope) {
+    _scopes.Pop();
+    if (_scopes.Count() == 0) {
+      _lifetimeEventHandler.ParsingCompleted();
+    }
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Utilities/ArgumentInfo.cs b/AppsheetEpplus/FormulaParsing/Utilities/ArgumentInfo.cs
new file mode 100644
index 0000000..a06f5c9
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Utilities/ArgumentInfo.cs
@@ -0,0 +1,16 @@
+namespace AppsheetEpplus;
+
+public class ArgumentInfo<T> {
+  public ArgumentInfo(T val) {
+    Value = val;
+  }
+
+  public T Value { get; private set; }
+
+  public string Name { get; private set; }
+
+  public ArgumentInfo<T> Named(string argName) {
+    Name = argName;
+    return this;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Utilities/ExtensionMethods.cs b/AppsheetEpplus/FormulaParsing/Utilities/ExtensionMethods.cs
new file mode 100644
index 0000000..5afb886
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Utilities/ExtensionMethods.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace AppsheetEpplus;
+
+public static class ExtensionMethods {
+  public static void IsNotNullOrEmpty(this ArgumentInfo<string> val) {
+    if (string.IsNullOrEmpty(val.Value)) {
+      throw new ArgumentException(val.Name + " cannot be null or empty");
+    }
+  }
+
+  public static void IsNotNull<T>(this ArgumentInfo<T> val)
+      where T : class {
+    if (val.Value == null) {
+      throw new ArgumentNullException(val.Name);
+    }
+  }
+
+  public static bool IsNumeric(this object obj) {
+    if (obj == null) {
+      return false;
+    }
+    return (obj.GetType().IsPrimitive
+            || obj is double
+            || obj is decimal
+            || obj is DateTime
+            || obj is TimeSpan);
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Utilities/IdProvider.cs b/AppsheetEpplus/FormulaParsing/Utilities/IdProvider.cs
new file mode 100644
index 0000000..53bcbdf
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Utilities/IdProvider.cs
@@ -0,0 +1,5 @@
+namespace AppsheetEpplus;
+
+public abstract class IdProvider {
+  public abstract object NewId();
+}
diff --git a/AppsheetEpplus/FormulaParsing/Utilities/IntegerIdProvider.cs b/AppsheetEpplus/FormulaParsing/Utilities/IntegerIdProvider.cs
new file mode 100644
index 0000000..76eab29
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Utilities/IntegerIdProvider.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace AppsheetEpplus;
+
+public class IntegerIdProvider : IdProvider {
+  private int _lastId = int.MinValue;
+
+  public override object NewId() {
+    if (_lastId >= int.MaxValue) {
+      throw new InvalidOperationException("IdProvider run out of id:s");
+    }
+    return _lastId++;
+  }
+}
diff --git a/AppsheetEpplus/FormulaParsing/Utilities/RegexConstants.cs b/AppsheetEpplus/FormulaParsing/Utilities/RegexConstants.cs
new file mode 100644
index 0000000..ca515a7
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Utilities/RegexConstants.cs
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+public static class RegexConstants {
+  public const string SingleCellAddress =
+      @"^(('[^/\\?*\[\]]{1,31}'|[A-Za-z_]{1,31})!)?[A-Z]{1,3}[1-9]{1}[0-9]{0,7}$";
+
+  //Changed JK 26/2-2013
+  public const string ExcelAddress =
+      @"^(('[^/\\?*\[\]]{1,31}'|[A-Za-z_]{1,31})!)?[\$]{0,1}([A-Z]|[A-Z]{1,3}[\$]{0,1}[1-9]{1}[0-9]{0,7})(\:({0,1}[A-Z]|[A-Z]{1,3}[\$]{0,1}[1-9]{1}[0-9]{0,7})){0,1}$";
+
+  //public const string ExcelAddress = @"^([\$]{0,1}([A-Z]{1,3}[\$]{0,1}[0-9]{1,7})(\:([\$]{0,1}[A-Z]{1,3}[\$]{0,1}[0-9]{1,7}){0,1})|([\$]{0,1}[A-Z]{1,3}\:[\$]{0,1}[A-Z]{1,3})|([\$]{0,1}[0-9]{1,7}\:[\$]{0,1}[0-9]{1,7}))$";
+  public const string Boolean = "^(true|false)$";
+  public const string Decimal = @"^[0-9]+\.[0-9]+$";
+  public const string Integer = "^[0-9]+$";
+}
diff --git a/AppsheetEpplus/FormulaParsing/Utilities/Require.cs b/AppsheetEpplus/FormulaParsing/Utilities/Require.cs
new file mode 100644
index 0000000..732bd27
--- /dev/null
+++ b/AppsheetEpplus/FormulaParsing/Utilities/Require.cs
@@ -0,0 +1,7 @@
+namespace AppsheetEpplus;
+
+public static class Require {
+  public static ArgumentInfo<T> That<T>(T arg) {
+    return new(arg);
+  }
+}
diff --git a/AppsheetEpplus/IRangeID.cs b/AppsheetEpplus/IRangeID.cs
new file mode 100644
index 0000000..f100426
--- /dev/null
+++ b/AppsheetEpplus/IRangeID.cs
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman          Added       		        2010-02-04
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Id from a cell, column or row.
+/// </summary>
+internal interface IRangeId {
+  /// <summary>
+  /// This is the id for a cell, row or column.
+  /// The id is a composit of the SheetID, the row number and the column number.
+  /// Bit 1-14 SheetID, Bit 15-28 Column number (0 if entire column), Bit 29- Row number (0 if entire row).
+  /// </summary>
+  ulong RangeID { get; set; }
+}
diff --git a/AppsheetEpplus/OfficeProperties.cs b/AppsheetEpplus/OfficeProperties.cs
new file mode 100644
index 0000000..95e30c1
--- /dev/null
+++ b/AppsheetEpplus/OfficeProperties.cs
@@ -0,0 +1,265 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan K�llman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan K�llman		                Initial Release		        2009-10-01
+ * Jan K�llman                      Total rewrite               2010-03-01
+ * Jan K�llman		    License changed GPL-->LGPL  2011-12-27
+ * Raziq York                       Added Created & Modified    2014-08-20
+ *******************************************************************************/
+
+using System;
+using System.Globalization;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Provides access to the properties bag of the package
+/// </summary>
+public sealed class OfficeProperties : XmlHelper {
+  private readonly XmlDocument _xmlPropertiesCore;
+  private readonly XmlDocument _xmlPropertiesExtended;
+
+  private readonly Uri _uriPropertiesCore = new("/docProps/core.xml", UriKind.Relative);
+  private readonly Uri _uriPropertiesExtended = new("/docProps/app.xml", UriKind.Relative);
+
+  private readonly XmlHelper _coreHelper;
+  private readonly XmlHelper _extendedHelper;
+
+  /// <summary>
+  /// Provides access to all the office document properties.
+  /// </summary>
+  /// <param name="package"></param>
+  /// <param name="ns"></param>
+  internal OfficeProperties(ExcelPackage package, XmlNamespaceManager ns)
+      : base(ns) {
+    const string coreBaseXml =
+        $"""<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><cp:coreProperties xmlns:cp="{ExcelPackage._schemaCore}" xmlns:dc="{ExcelPackage._schemaDc}" xmlns:dcterms="{ExcelPackage._schemaDcTerms}" xmlns:dcmitype="{ExcelPackage._schemaDcmiType}" xmlns:xsi="{ExcelPackage._schemaXsi}"></cp:coreProperties>""";
+    _xmlPropertiesCore = package.GetOrCreateXmlDocument(
+        _uriPropertiesCore,
+        "application/vnd.openxmlformats-package.core-properties+xml",
+        "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties",
+        coreBaseXml);
+    _coreHelper = XmlHelperFactory.Create(
+        ns,
+        _xmlPropertiesCore.SelectSingleNode("cp:coreProperties", NameSpaceManager));
+
+    const string extendedBaseXml =
+        $"""<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><Properties xmlns:vt="{ExcelPackage._schemaVt}" xmlns="{ExcelPackage._schemaExtended}"></Properties>""";
+    _xmlPropertiesExtended = package.GetOrCreateXmlDocument(
+        _uriPropertiesExtended,
+        "application/vnd.openxmlformats-officedocument.extended-properties+xml",
+        "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties",
+        extendedBaseXml);
+    _extendedHelper = XmlHelperFactory.Create(ns, _xmlPropertiesExtended);
+  }
+
+  private const string _titlePath = "dc:title";
+
+  /// <summary>
+  /// Gets/sets the title property of the document (core property)
+  /// </summary>
+  public string Title {
+    get => _coreHelper.GetXmlNodeString(_titlePath);
+    set => _coreHelper.SetXmlNodeString(_titlePath, value);
+  }
+
+  private const string _subjectPath = "dc:subject";
+
+  /// <summary>
+  /// Gets/sets the subject property of the document (core property)
+  /// </summary>
+  public string Subject {
+    get => _coreHelper.GetXmlNodeString(_subjectPath);
+    set => _coreHelper.SetXmlNodeString(_subjectPath, value);
+  }
+
+  private const string _authorPath = "dc:creator";
+
+  /// <summary>
+  /// Gets/sets the author property of the document (core property)
+  /// </summary>
+  public string Author {
+    get => _coreHelper.GetXmlNodeString(_authorPath);
+    set => _coreHelper.SetXmlNodeString(_authorPath, value);
+  }
+
+  private const string _commentsPath = "dc:description";
+
+  /// <summary>
+  /// Gets/sets the comments property of the document (core property)
+  /// </summary>
+  public string Comments {
+    get => _coreHelper.GetXmlNodeString(_commentsPath);
+    set => _coreHelper.SetXmlNodeString(_commentsPath, value);
+  }
+
+  private const string _keywordsPath = "cp:keywords";
+
+  /// <summary>
+  /// Gets/sets the keywords property of the document (core property)
+  /// </summary>
+  public string Keywords {
+    get => _coreHelper.GetXmlNodeString(_keywordsPath);
+    set => _coreHelper.SetXmlNodeString(_keywordsPath, value);
+  }
+
+  private const string _lastModifiedByPath = "cp:lastModifiedBy";
+
+  /// <summary>
+  /// Gets/sets the lastModifiedBy property of the document (core property)
+  /// </summary>
+  public string LastModifiedBy {
+    get => _coreHelper.GetXmlNodeString(_lastModifiedByPath);
+    set => _coreHelper.SetXmlNodeString(_lastModifiedByPath, value);
+  }
+
+  private const string _lastPrintedPath = "cp:lastPrinted";
+
+  /// <summary>
+  /// Gets/sets the lastPrinted property of the document (core property)
+  /// </summary>
+  public string LastPrinted {
+    get => _coreHelper.GetXmlNodeString(_lastPrintedPath);
+    set => _coreHelper.SetXmlNodeString(_lastPrintedPath, value);
+  }
+
+  private const string _createdPath = "dcterms:created";
+
+  /// <summary>
+  /// Gets/sets the created property of the document (core property)
+  /// </summary>
+  public DateTime Created {
+    get =>
+      DateTime.TryParse(_coreHelper.GetXmlNodeString(_createdPath), out var date)
+          ? date
+          : DateTime.MinValue;
+    set {
+      var dateString = value.ToUniversalTime().ToString("s", CultureInfo.InvariantCulture) + "Z";
+      _coreHelper.SetXmlNodeString(_createdPath, dateString);
+      _coreHelper.SetXmlNodeString(_createdPath + "/@xsi:type", "dcterms:W3CDTF");
+    }
+  }
+
+  private const string _categoryPath = "cp:category";
+
+  /// <summary>
+  /// Gets/sets the category property of the document (core property)
+  /// </summary>
+  public string Category {
+    get => _coreHelper.GetXmlNodeString(_categoryPath);
+    set => _coreHelper.SetXmlNodeString(_categoryPath, value);
+  }
+
+  private const string _contentStatusPath = "cp:contentStatus";
+
+  /// <summary>
+  /// Gets/sets the status property of the document (core property)
+  /// </summary>
+  public string Status {
+    get => _coreHelper.GetXmlNodeString(_contentStatusPath);
+    set => _coreHelper.SetXmlNodeString(_contentStatusPath, value);
+  }
+
+  /// <summary>
+  /// Provides access to the XML document that holds the extended properties of the document (app.xml)
+  /// </summary>
+  public XmlDocument ExtendedPropertiesXml {
+    get {
+      if (_xmlPropertiesExtended == null) {}
+      return (_xmlPropertiesExtended);
+    }
+  }
+
+  private const string _applicationPath = "xp:Properties/xp:Application";
+
+  /// <summary>
+  /// Gets/Set the Application property of the document (extended property)
+  /// </summary>
+  public string Application {
+    get => _extendedHelper.GetXmlNodeString(_applicationPath);
+    set => _extendedHelper.SetXmlNodeString(_applicationPath, value);
+  }
+
+  private const string _hyperlinkBasePath = "xp:Properties/xp:HyperlinkBase";
+
+  /// <summary>
+  /// Gets/sets the HyperlinkBase property of the document (extended property)
+  /// </summary>
+  public Uri HyperlinkBase {
+    get => new(_extendedHelper.GetXmlNodeString(_hyperlinkBasePath), UriKind.Absolute);
+    set => _extendedHelper.SetXmlNodeString(_hyperlinkBasePath, value.AbsoluteUri);
+  }
+
+  private const string _appVersionPath = "xp:Properties/xp:AppVersion";
+
+  /// <summary>
+  /// Gets/Set the AppVersion property of the document (extended property)
+  /// </summary>
+  public string AppVersion {
+    get => _extendedHelper.GetXmlNodeString(_appVersionPath);
+    set => _extendedHelper.SetXmlNodeString(_appVersionPath, value);
+  }
+
+  private const string _companyPath = "xp:Properties/xp:Company";
+
+  /// <summary>
+  /// Gets/sets the Company property of the document (extended property)
+  /// </summary>
+  public string Company {
+    get => _extendedHelper.GetXmlNodeString(_companyPath);
+    set => _extendedHelper.SetXmlNodeString(_companyPath, value);
+  }
+
+  private const string _managerPath = "xp:Properties/xp:Manager";
+
+  /// <summary>
+  /// Gets/sets the Manager property of the document (extended property)
+  /// </summary>
+  public string Manager {
+    get => _extendedHelper.GetXmlNodeString(_managerPath);
+    set => _extendedHelper.SetXmlNodeString(_managerPath, value);
+  }
+
+  private const string _modifiedPath = "dcterms:modified";
+
+  /// <summary>
+  /// Gets/sets the modified property of the document (core property)
+  /// </summary>
+  public DateTime Modified {
+    get =>
+      DateTime.TryParse(_coreHelper.GetXmlNodeString(_modifiedPath), out var date)
+          ? date
+          : DateTime.MinValue;
+    set {
+      var dateString = value.ToUniversalTime().ToString("s", CultureInfo.InvariantCulture) + "Z";
+      _coreHelper.SetXmlNodeString(_modifiedPath, dateString);
+      _coreHelper.SetXmlNodeString(_modifiedPath + "/@xsi:type", "dcterms:W3CDTF");
+    }
+  }
+}
diff --git a/AppsheetEpplus/Packaging/ZipPackage.cs b/AppsheetEpplus/Packaging/ZipPackage.cs
new file mode 100644
index 0000000..444b4d0
--- /dev/null
+++ b/AppsheetEpplus/Packaging/ZipPackage.cs
@@ -0,0 +1,262 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Jan Källman		Added		25-Oct-2012
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.IO.Compression;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Specifies whether the target is inside or outside the System.IO.Packaging.Package.
+/// </summary>
+public enum TargetMode {
+  /// <summary>
+  /// The relationship references a part that is inside the package.
+  /// </summary>
+  Internal = 0,
+
+  /// <summary>
+  /// The relationship references a resource that is external to the package.
+  /// </summary>
+  External = 1,
+}
+
+/// <summary>
+/// Represent an OOXML Zip package.
+/// </summary>
+internal class ZipPackage : ZipPackageRelationshipBase {
+  internal class ContentType {
+    internal string Name;
+    internal bool IsExtension;
+    internal string Match;
+
+    public ContentType(string name, bool isExtension, string match) {
+      Name = name;
+      IsExtension = isExtension;
+      Match = match;
+    }
+  }
+
+  private readonly Dictionary<string, ZipPackagePart> Parts = new(
+      StringComparer.InvariantCultureIgnoreCase);
+  internal Dictionary<string, ContentType> _contentTypes = new(
+      StringComparer.InvariantCultureIgnoreCase);
+
+  internal ZipPackage() {
+    AddNew();
+  }
+
+  private void AddNew() {
+    _contentTypes.Add("xml", new(ExcelPackage._schemaXmlExtension, true, "xml"));
+    _contentTypes.Add("rels", new(ExcelPackage._schemaRelsExtension, true, "rels"));
+  }
+
+  internal ZipPackage(Stream stream) {
+    bool hasContentTypeXml = false;
+    if (stream == null || stream.Length == 0) {
+      AddNew();
+    } else {
+      var rels = new Dictionary<string, ZipArchiveEntry>();
+      stream.Seek(0, SeekOrigin.Begin);
+      using var zip = new ZipArchive(stream, ZipArchiveMode.Read, leaveOpen: true);
+      foreach (var e in zip.Entries) {
+        if (e.Length > 0) {
+          if (e.FullName.Equals(
+              "[content_types].xml",
+              StringComparison.InvariantCultureIgnoreCase)) {
+            using var inputStream = e.Open();
+            AddContentTypes(inputStream);
+            hasContentTypeXml = true;
+          } else if (e.FullName.Equals(
+              "_rels/.rels",
+              StringComparison.InvariantCultureIgnoreCase)) {
+            using var inputStream = e.Open();
+            ReadRelation(inputStream, "");
+          } else {
+            if (e.FullName.EndsWith(".rels", StringComparison.InvariantCultureIgnoreCase)) {
+              rels.Add(GetUriKey(e.FullName), e);
+            } else {
+              var data = new byte[e.Length];
+              using var inputStream = e.Open();
+              inputStream.ReadExactly(data);
+              var part = new ZipPackagePart(
+                  this,
+                  e,
+                  ImmutableCollectionsMarshal.AsImmutableArray(data));
+              Parts.Add(GetUriKey(e.FullName), part);
+            }
+          }
+        }
+      }
+      foreach (var p in Parts) {
+        string name = Path.GetFileName(p.Key);
+        string extension = Path.GetExtension(p.Key);
+        string relFile = string.Format(
+            "{0}_rels/{1}.rels",
+            p.Key.Substring(0, p.Key.Length - name.Length),
+            name);
+        if (rels.TryGetValue(relFile, out var zipArchiveEntry)) {
+          using var inputStream = zipArchiveEntry.Open();
+          p.Value.ReadRelation(inputStream, p.Value.Uri.OriginalString);
+        }
+        if (_contentTypes.TryGetValue(p.Key, out var type)) {
+          p.Value.ContentType = type.Name;
+        } else if (extension.Length > 1 && _contentTypes.ContainsKey(extension.Substring(1))) {
+          p.Value.ContentType = _contentTypes[extension.Substring(1)].Name;
+        }
+      }
+      if (!hasContentTypeXml) {
+        throw new InvalidDataException("The file is not an valid Package file.");
+      }
+    }
+  }
+
+  private void AddContentTypes(Stream inputStream) {
+    var doc = new XmlDocument();
+    XmlHelper.LoadXmlSafe(doc, inputStream);
+
+    foreach (XmlElement c in doc.DocumentElement.ChildNodes) {
+      ContentType ct;
+      if (string.IsNullOrEmpty(c.GetAttribute("Extension"))) {
+        ct = new(c.GetAttribute("ContentType"), false, c.GetAttribute("PartName"));
+      } else {
+        ct = new(c.GetAttribute("ContentType"), true, c.GetAttribute("Extension"));
+      }
+      _contentTypes.Add(GetUriKey(ct.Match), ct);
+    }
+  }
+
+  internal void CreatePart(Uri partUri, string contentType, Action<StreamWriter> saveHandler) {
+    if (PartExists(partUri)) {
+      throw (new InvalidOperationException("Part already exist"));
+    }
+
+    var part = new ZipPackagePart(this, partUri, contentType, saveHandler);
+    _contentTypes.Add(
+        GetUriKey(part.Uri.OriginalString),
+        new(contentType, false, part.Uri.OriginalString));
+    Parts.Add(GetUriKey(part.Uri.OriginalString), part);
+  }
+
+  internal ZipPackagePart GetPart(Uri partUri) {
+    if (PartExists(partUri)) {
+      return Parts
+          .Single(x =>
+              x.Key.Equals(
+                  GetUriKey(partUri.OriginalString),
+                  StringComparison.InvariantCultureIgnoreCase))
+          .Value;
+    }
+    throw (new InvalidOperationException("Part does not exist."));
+  }
+
+  internal string GetUriKey(string uri) {
+    string ret = uri;
+    if (ret[0] != '/') {
+      ret = "/" + ret;
+    }
+    return ret;
+  }
+
+  internal bool PartExists(Uri partUri) {
+    var uriKey = GetUriKey(partUri.OriginalString.ToLower(CultureInfo.InvariantCulture));
+    return Parts.Keys.Any(x => x.Equals(uriKey, StringComparison.InvariantCultureIgnoreCase));
+  }
+
+  internal void DeletePart(Uri uri) {
+    var delList = new List<object[]>();
+    foreach (var p in Parts.Values) {
+      foreach (var r in p.GetRelationships()) {
+        if (UriHelper
+            .ResolvePartUri(p.Uri, r.TargetUri)
+            .OriginalString.Equals(
+                uri.OriginalString,
+                StringComparison.InvariantCultureIgnoreCase)) {
+          delList.Add([r.Id, p]);
+        }
+      }
+    }
+    foreach (var o in delList) {
+      ((ZipPackagePart)o[1]).DeleteRelationship(o[0].ToString());
+    }
+    var rels = GetPart(uri).GetRelationships();
+    while (rels.Count > 0) {
+      rels.Remove(rels.First().Id);
+    }
+    _contentTypes.Remove(GetUriKey(uri.OriginalString));
+    //remove all relations
+    Parts.Remove(GetUriKey(uri.OriginalString));
+  }
+
+  internal void Save(Stream stream) {
+    using var zipArchive = new ZipArchive(stream, ZipArchiveMode.Create, leaveOpen: true);
+    // Content types
+    var contentTypesEntry = zipArchive.CreateEntry("[Content_Types].xml");
+    using (var contentTypesWriter = new StreamWriter(contentTypesEntry.Open())) {
+      contentTypesWriter.Write(GetContentTypeXml());
+    }
+    // Top Rels
+    _rels.WriteZip(zipArchive, "_rels/.rels");
+    ZipPackagePart ssPart = null;
+    foreach (var part in Parts.Values) {
+      if (part.ContentType != ExcelPackage._contentTypeSharedString) {
+        part.WriteZip(zipArchive);
+      } else {
+        ssPart = part;
+      }
+    }
+    //Shared strings must be saved after all worksheets. The ss dictionary is populated when that workheets are saved (to get the best performance).
+    if (ssPart != null) {
+      ssPart.WriteZip(zipArchive);
+    }
+  }
+
+  private string GetContentTypeXml() {
+    StringBuilder xml = new StringBuilder(
+        "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">");
+    foreach (ContentType ct in _contentTypes.Values) {
+      if (ct.IsExtension) {
+        xml.Append($"<Default ContentType=\"{ct.Name}\" Extension=\"{ct.Match}\"/>");
+      } else {
+        xml.Append($"<Override ContentType=\"{ct.Name}\" PartName=\"{GetUriKey(ct.Match)}\" />");
+      }
+    }
+    xml.Append("</Types>");
+    return xml.ToString();
+  }
+}
diff --git a/AppsheetEpplus/Packaging/ZipPackagePart.cs b/AppsheetEpplus/Packaging/ZipPackagePart.cs
new file mode 100644
index 0000000..e1ca691
--- /dev/null
+++ b/AppsheetEpplus/Packaging/ZipPackagePart.cs
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Jan Källman		Added		25-Oct-2012
+ *******************************************************************************/
+
+using System;
+using System.Collections.Immutable;
+using System.IO;
+using System.IO.Compression;
+using System.Runtime.InteropServices;
+
+namespace AppsheetEpplus;
+
+internal class ZipPackagePart : ZipPackageRelationshipBase, IDisposable {
+  internal ZipPackagePart(ZipPackage package, ZipArchiveEntry entry, ImmutableArray<byte> data) {
+    Package = package;
+    SaveHandler = null;
+    Uri = new(package.GetUriKey(entry.FullName), UriKind.Relative);
+    _data = data;
+  }
+
+  private readonly ImmutableArray<byte> _data;
+
+  internal ZipPackagePart(
+      ZipPackage package,
+      Uri partUri,
+      string contentType,
+      Action<StreamWriter> saveHandler) {
+    Package = package;
+    Uri = partUri;
+    ContentType = contentType;
+    SaveHandler = saveHandler;
+  }
+
+  private ZipPackage Package { get; }
+
+  internal override ZipPackageRelationship CreateRelationship(
+      Uri targetUri,
+      TargetMode targetMode,
+      string relationshipType) {
+    var rel = base.CreateRelationship(targetUri, targetMode, relationshipType);
+    rel.SourceUri = Uri;
+    return rel;
+  }
+
+  internal MemoryStream GetStream() {
+    return new(ImmutableCollectionsMarshal.AsArray(_data) ?? [], false);
+  }
+
+  private string _contentType = "";
+
+  public string ContentType {
+    get => _contentType;
+    internal set {
+      if (!string.IsNullOrEmpty(_contentType)) {
+        if (Package._contentTypes.ContainsKey(Package.GetUriKey(Uri.OriginalString))) {
+          Package._contentTypes.Remove(Package.GetUriKey(Uri.OriginalString));
+          Package._contentTypes.Add(
+              Package.GetUriKey(Uri.OriginalString),
+              new(value, false, Uri.OriginalString));
+        }
+      }
+      _contentType = value;
+    }
+  }
+
+  public Uri Uri { get; }
+
+  internal Action<StreamWriter> SaveHandler { get; set; }
+
+  internal void WriteZip(ZipArchive zipArchive) {
+    if (SaveHandler == null) {
+      if (_data.Length == 0) {
+        return;
+      }
+      var zipEntry = zipArchive.CreateEntry(Uri.OriginalString);
+      using var os = zipEntry.Open();
+      os.Write(_data.AsSpan());
+    } else {
+      var zipEntry = zipArchive.CreateEntry(Uri.OriginalString);
+      using var streamWriter = new StreamWriter(zipEntry.Open());
+      SaveHandler(streamWriter);
+    }
+
+    if (_rels.Count > 0) {
+      string f = Uri.OriginalString;
+      var name = Path.GetFileName(f);
+      _rels.WriteZip(zipArchive, $"{f.Substring(0, f.Length - name.Length)}_rels/{name}.rels");
+    }
+  }
+
+  public void Dispose() {}
+}
diff --git a/AppsheetEpplus/Packaging/ZipPackageRelationship.cs b/AppsheetEpplus/Packaging/ZipPackageRelationship.cs
new file mode 100644
index 0000000..915cddf
--- /dev/null
+++ b/AppsheetEpplus/Packaging/ZipPackageRelationship.cs
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Jan Källman		Added		25-Oct-2012
+ *******************************************************************************/
+
+using System;
+
+namespace AppsheetEpplus;
+
+internal class ZipPackageRelationship {
+  public Uri TargetUri { get; internal set; }
+
+  public Uri SourceUri { get; internal set; }
+
+  public string RelationshipType { get; internal set; }
+
+  public TargetMode TargetMode { get; internal set; }
+
+  public string Id { get; internal set; }
+}
diff --git a/AppsheetEpplus/Packaging/ZipPackageRelationshipBase.cs b/AppsheetEpplus/Packaging/ZipPackageRelationshipBase.cs
new file mode 100644
index 0000000..240ed85
--- /dev/null
+++ b/AppsheetEpplus/Packaging/ZipPackageRelationshipBase.cs
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Jan Källman		Added		25-Oct-2012
+ *******************************************************************************/
+
+using System;
+using System.IO;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+internal abstract class ZipPackageRelationshipBase {
+  protected ZipPackageRelationshipCollection _rels = new();
+  protected internal int maxRId = 1;
+
+  internal void DeleteRelationship(string id) {
+    _rels.Remove(id);
+    UpdateMaxRId(id, ref maxRId);
+  }
+
+  protected void UpdateMaxRId(string id, ref int maxRId) {
+    if (id.StartsWith("rId")) {
+      if (int.TryParse(id.Substring(3), out var num)) {
+        if (num == maxRId - 1) {
+          maxRId--;
+        }
+      }
+    }
+  }
+
+  internal virtual ZipPackageRelationship CreateRelationship(
+      Uri targetUri,
+      TargetMode targetMode,
+      string relationshipType) {
+    var rel = new ZipPackageRelationship();
+    rel.TargetUri = targetUri;
+    rel.TargetMode = targetMode;
+    rel.RelationshipType = relationshipType;
+    rel.Id = "rId" + (maxRId++);
+    _rels.Add(rel);
+    return rel;
+  }
+
+  internal bool RelationshipExists(string id) {
+    return _rels.ContainsKey(id);
+  }
+
+  internal ZipPackageRelationshipCollection GetRelationshipsByType(string schema) {
+    return _rels.GetRelationshipsByType(schema);
+  }
+
+  internal ZipPackageRelationshipCollection GetRelationships() {
+    return _rels;
+  }
+
+  internal ZipPackageRelationship GetRelationship(string id) {
+    return _rels[id];
+  }
+
+  internal void ReadRelation(Stream inputStream, string source) {
+    var doc = new XmlDocument();
+    XmlHelper.LoadXmlSafe(doc, inputStream);
+
+    foreach (XmlElement c in doc.DocumentElement.ChildNodes) {
+      var rel = new ZipPackageRelationship();
+      rel.Id = c.GetAttribute("Id");
+      rel.RelationshipType = c.GetAttribute("Type");
+      rel.TargetMode = c.GetAttribute("TargetMode")
+          .Equals("external", StringComparison.InvariantCultureIgnoreCase)
+          ? TargetMode.External
+          : TargetMode.Internal;
+      try {
+        rel.TargetUri = new(c.GetAttribute("Target"), UriKind.RelativeOrAbsolute);
+      } catch {
+        //The URI is not a valid URI. Encode it to make i valid.
+        rel.TargetUri = new(
+            Uri.EscapeUriString("Invalid:URI " + c.GetAttribute("Target")),
+            UriKind.RelativeOrAbsolute);
+      }
+      if (!string.IsNullOrEmpty(source)) {
+        rel.SourceUri = new(source, UriKind.Relative);
+      }
+      if (rel.Id.StartsWith("rid", StringComparison.InvariantCultureIgnoreCase)) {
+        if (int.TryParse(rel.Id.Substring(3), out var id)) {
+          if (id >= maxRId
+              && id
+                  < int.MaxValue
+                      - 10000) //Not likly to have this high id's but make sure we have space to avoid overflow.
+          {
+            maxRId = id + 1;
+          }
+        }
+      }
+      _rels.Add(rel);
+    }
+  }
+}
diff --git a/AppsheetEpplus/Packaging/ZipPackageRelationshipCollection.cs b/AppsheetEpplus/Packaging/ZipPackageRelationshipCollection.cs
new file mode 100644
index 0000000..ef9c5c1
--- /dev/null
+++ b/AppsheetEpplus/Packaging/ZipPackageRelationshipCollection.cs
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ *******************************************************************************
+ * Jan Källman		Added		25-Oct-2012
+ *******************************************************************************/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.IO.Compression;
+using System.Security;
+
+namespace AppsheetEpplus;
+
+internal class ZipPackageRelationshipCollection : IEnumerable<ZipPackageRelationship> {
+  protected internal Dictionary<string, ZipPackageRelationship> _rels = new(
+      StringComparer.InvariantCultureIgnoreCase);
+
+  internal void Add(ZipPackageRelationship item) {
+    _rels.Add(item.Id, item);
+  }
+
+  public IEnumerator<ZipPackageRelationship> GetEnumerator() {
+    return _rels.Values.GetEnumerator();
+  }
+
+  IEnumerator IEnumerable.GetEnumerator() {
+    return _rels.Values.GetEnumerator();
+  }
+
+  internal void Remove(string id) {
+    _rels.Remove(id);
+  }
+
+  internal bool ContainsKey(string id) {
+    return _rels.ContainsKey(id);
+  }
+
+  internal ZipPackageRelationship this[string id] => _rels[id];
+
+  internal ZipPackageRelationshipCollection GetRelationshipsByType(string relationshipType) {
+    var ret = new ZipPackageRelationshipCollection();
+    foreach (var rel in _rels.Values) {
+      if (rel.RelationshipType == relationshipType) {
+        ret.Add(rel);
+      }
+    }
+    return ret;
+  }
+
+  internal void WriteZip(ZipArchive zipArchive, string filename) {
+    var entry = zipArchive.CreateEntry(filename);
+    using var writer = new StreamWriter(entry.Open());
+
+    writer.Write(
+        "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">");
+    foreach (var rel in _rels.Values) {
+      writer.Write(
+          "<Relationship Id=\"{0}\" Type=\"{1}\" Target=\"{2}\"{3}/>",
+          SecurityElement.Escape(rel.Id),
+          rel.RelationshipType,
+          SecurityElement.Escape(rel.TargetUri.OriginalString),
+          rel.TargetMode == TargetMode.External ? " TargetMode=\"External\"" : "");
+    }
+    writer.Write("</Relationships>");
+  }
+
+  public int Count => _rels.Count;
+}
diff --git a/AppsheetEpplus/RangeCollection.cs b/AppsheetEpplus/RangeCollection.cs
new file mode 100644
index 0000000..87fa5be
--- /dev/null
+++ b/AppsheetEpplus/RangeCollection.cs
@@ -0,0 +1,277 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		    Added       		        2010-02-04
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// This is the store for all Rows, Columns and Cells.
+/// It is a Dictionary implementation that allows you to change the Key (the RowID, ColumnID or CellID )
+/// </summary>
+internal class RangeCollection : IEnumerator<IRangeId>, IEnumerable {
+  private class IndexItem {
+    internal IndexItem(ulong cellId) {
+      RangeID = cellId;
+    }
+
+    internal IndexItem(ulong cellId, int listPointer) {
+      RangeID = cellId;
+      ListPointer = listPointer;
+    }
+
+    internal ulong RangeID;
+    internal int ListPointer;
+  }
+
+  /// <summary>
+  /// Compares an IndexItem
+  /// </summary>
+  internal class Compare : IComparer<IndexItem> {
+    int IComparer<IndexItem>.Compare(IndexItem x, IndexItem y) {
+      return x.RangeID < y.RangeID
+          ? -1
+          : x.RangeID > y.RangeID
+              ? 1
+              : 0;
+    }
+  }
+
+  private IndexItem[] _cellIndex;
+  private List<IRangeId> _cells;
+  private static readonly Compare _comparer = new();
+
+  /// <summary>
+  /// Creates a new collection
+  /// </summary>
+  /// <param name="cells">The Cells. This list must be sorted</param>
+  internal RangeCollection(List<IRangeId> cells) {
+    _cells = cells;
+    InitSize(_cells);
+    for (int i = 0; i < _cells.Count; i++) {
+      _cellIndex[i] = new(cells[i].RangeID, i);
+    }
+  }
+
+  ~RangeCollection() {
+    _cells = null;
+    _cellIndex = null;
+  }
+
+  /// <summary>
+  /// Return the item with the RangeID
+  /// </summary>
+  /// <param name="rangeId"></param>
+  /// <returns></returns>
+  internal IRangeId this[ulong rangeId] => _cells[_cellIndex[IndexOf(rangeId)].ListPointer];
+
+  /// <summary>
+  /// Return specified index from the sorted list
+  /// </summary>
+  /// <param name="index"></param>
+  /// <returns></returns>
+  internal IRangeId this[int index] => _cells[_cellIndex[index].ListPointer];
+
+  internal int Count => _cells.Count;
+
+  internal void Add(IRangeId cell) {
+    var ix = IndexOf(cell.RangeID);
+    if (ix >= 0) {
+      throw (new("Item already exists"));
+    }
+    Insert(~ix, cell);
+  }
+
+  internal void Delete(ulong key) {
+    var ix = IndexOf(key);
+    if (ix < 0) {
+      throw (new("Key does not exists"));
+    }
+    int listPointer = _cellIndex[ix].ListPointer;
+    Array.Copy(_cellIndex, ix + 1, _cellIndex, ix, _cells.Count - ix - 1);
+    _cells.RemoveAt(listPointer);
+
+    //Item is removed subtract one from all items with greater ListPointer
+    for (int i = 0; i < _cells.Count; i++) {
+      if (_cellIndex[i].ListPointer >= listPointer) {
+        _cellIndex[i].ListPointer--;
+      }
+    }
+  }
+
+  internal int IndexOf(ulong key) {
+    return Array.BinarySearch(_cellIndex, 0, _cells.Count, new(key), _comparer);
+  }
+
+  internal bool ContainsKey(ulong key) {
+    return IndexOf(key) < 0 ? false : true;
+  }
+
+  private int _size { get; set; }
+
+  /// <summary>
+  /// Insert a number of rows in the collecion but dont update the cell only the index
+  /// </summary>
+  /// <param name="rowId"></param>
+  /// <param name="rows"></param>
+  /// <returns>Index of first rangeItem</returns>
+  internal int InsertRowsUpdateIndex(ulong rowId, int rows) {
+    int index = IndexOf(rowId);
+    if (index < 0) {
+      index = ~index; //No match found invert to get start cell
+    }
+    ulong rowAdd = (((ulong)rows) << 29);
+    for (int i = index; i < _cells.Count; i++) {
+      _cellIndex[i].RangeID += rowAdd;
+    }
+    return index;
+  }
+
+  /// <summary>
+  /// Insert a number of rows in the collecion
+  /// </summary>
+  /// <param name="rowId"></param>
+  /// <param name="rows"></param>
+  /// <returns>Index of first rangeItem</returns>
+  internal int InsertRows(ulong rowId, int rows) {
+    int index = IndexOf(rowId);
+    if (index < 0) {
+      index = ~index; //No match found invert to get start cell
+    }
+    ulong rowAdd = (((ulong)rows) << 29);
+    for (int i = index; i < _cells.Count; i++) {
+      _cellIndex[i].RangeID += rowAdd;
+      _cells[_cellIndex[i].ListPointer].RangeID += rowAdd;
+    }
+    return index;
+  }
+
+  /// <summary>
+  /// Delete rows from the collecion
+  /// </summary>
+  /// <param name="rowId"></param>
+  /// <param name="rows"></param>
+  /// <param name="updateCells">Update range id's on cells</param>
+  internal int DeleteRows(ulong rowId, int rows, bool updateCells) {
+    ulong rowAdd = (((ulong)rows) << 29);
+    var index = IndexOf(rowId);
+    if (index < 0) {
+      index = ~index; //No match found invert to get start cell
+    }
+
+    if (index >= _cells.Count || _cellIndex[index] == null) {
+      return -1; //No row above this row
+    }
+    while (index < _cells.Count && _cellIndex[index].RangeID < rowId + rowAdd) {
+      Delete(_cellIndex[index].RangeID);
+    }
+
+    int updIndex = IndexOf(rowId + rowAdd);
+    if (updIndex < 0) {
+      updIndex = ~updIndex; //No match found invert to get start cell
+    }
+
+    for (int i = updIndex; i < _cells.Count; i++) {
+      _cellIndex[i].RangeID -= rowAdd; //Change the index
+      if (updateCells) {
+        _cells[_cellIndex[i].ListPointer].RangeID -= rowAdd; //Change the cell/row or column object
+      }
+    }
+    return index;
+  }
+
+  internal void InsertColumn(ulong columnId, int columns) {
+    throw (new("Working on it..."));
+  }
+
+  internal void DeleteColumn(ulong columnId, int columns) {
+    throw (new("Working on it..."));
+  }
+
+  /// <summary>
+  /// Init the size starting from 128 items. Double the size until the list fits.
+  /// </summary>
+  /// <param name="_cells"></param>
+  private void InitSize(List<IRangeId> cells) {
+    _size = 128;
+    while (cells.Count > _size) {
+      _size <<= 1;
+    }
+    _cellIndex = new IndexItem[_size];
+  }
+
+  /// <summary>
+  /// Check the size and double the size if out of bound
+  /// </summary>
+  private void CheckSize() {
+    if (_cells.Count >= _size) {
+      _size <<= 1;
+      Array.Resize(ref _cellIndex, _size);
+    }
+  }
+
+  private void Insert(int ix, IRangeId cell) {
+    CheckSize();
+    Array.Copy(_cellIndex, ix, _cellIndex, ix + 1, _cells.Count - ix);
+    _cellIndex[ix] = new(cell.RangeID, _cells.Count);
+    _cells.Add(cell);
+  }
+
+  IRangeId IEnumerator<IRangeId>.Current {
+    get { throw new NotImplementedException(); }
+  }
+
+  void IDisposable.Dispose() {
+    _ix = -1;
+  }
+
+  private int _ix = -1;
+
+  object IEnumerator.Current {
+    get { return _cells[_cellIndex[_ix].ListPointer]; }
+  }
+
+  bool IEnumerator.MoveNext() {
+    _ix++;
+    return _ix < _cells.Count;
+  }
+
+  void IEnumerator.Reset() {
+    _ix = -1;
+  }
+
+  IEnumerator IEnumerable.GetEnumerator() {
+    return MemberwiseClone() as IEnumerator;
+  }
+}
diff --git a/AppsheetEpplus/Style/Dxf/DxfStyleBase.cs b/AppsheetEpplus/Style/Dxf/DxfStyleBase.cs
new file mode 100644
index 0000000..569badf
--- /dev/null
+++ b/AppsheetEpplus/Style/Dxf/DxfStyleBase.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Globalization;
+
+namespace AppsheetEpplus;
+
+public abstract class DxfStyleBase<T> {
+  protected ExcelStyles _styles;
+
+  internal DxfStyleBase(ExcelStyles styles) {
+    _styles = styles;
+  }
+
+  protected internal abstract string Id { get; }
+
+  protected internal abstract bool HasValue { get; }
+
+  protected internal abstract void CreateNodes(XmlHelper helper, string path);
+
+  protected internal abstract T Clone();
+
+  protected void SetValueColor(XmlHelper helper, string path, ExcelDxfColor color) {
+    if (color != null && color.HasValue) {
+      if (color.Rgb != null) {
+        SetValue(helper, path + "/@rgb", color.Rgb);
+      } else if (color.Auto != null) {
+        SetValueBool(helper, path + "/@auto", color.Auto);
+      } else if (color.Theme != null) {
+        SetValue(helper, path + "/@theme", color.Theme);
+      } else if (color.Index != null) {
+        SetValue(helper, path + "/@indexed", color.Index);
+      }
+      if (color.Tint != null) {
+        SetValue(helper, path + "/@tint", color.Tint);
+      }
+    }
+  }
+
+  /// <summary>
+  /// Same as SetValue but will set first char to lower case.
+  /// </summary>
+  /// <param name="helper"></param>
+  /// <param name="path"></param>
+  /// <param name="v"></param>
+  protected void SetValueEnum(XmlHelper helper, string path, Enum v) {
+    if (v == null) {
+      helper.DeleteNode(path);
+    } else {
+      var s = v.ToString();
+      s = s.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + s.Substring(1);
+      helper.SetXmlNodeString(path, s);
+    }
+  }
+
+  protected void SetValue(XmlHelper helper, string path, object v) {
+    if (v == null) {
+      helper.DeleteNode(path);
+    } else {
+      helper.SetXmlNodeString(path, v.ToString());
+    }
+  }
+
+  protected void SetValueBool(XmlHelper helper, string path, bool? v) {
+    if (v == null) {
+      helper.DeleteNode(path);
+    } else {
+      helper.SetXmlNodeBool(path, (bool)v);
+    }
+  }
+
+  protected string GetAsString(object v) {
+    return (v ?? "").ToString();
+  }
+
+  /// <summary>
+  /// Is this value allowed to be changed?
+  /// </summary>
+  protected internal bool AllowChange { get; set; } = false;
+}
diff --git a/AppsheetEpplus/Style/Dxf/ExcelDxfBorder.cs b/AppsheetEpplus/Style/Dxf/ExcelDxfBorder.cs
new file mode 100644
index 0000000..10a219d
--- /dev/null
+++ b/AppsheetEpplus/Style/Dxf/ExcelDxfBorder.cs
@@ -0,0 +1,81 @@
+namespace AppsheetEpplus;
+
+public class ExcelDxfBorderBase : DxfStyleBase<ExcelDxfBorderBase> {
+  internal ExcelDxfBorderBase(ExcelStyles styles)
+      : base(styles) {
+    Left = new(_styles);
+    Right = new(_styles);
+    Top = new(_styles);
+    Bottom = new(_styles);
+  }
+
+  /// <summary>
+  /// Left border style
+  /// </summary>
+  public ExcelDxfBorderItem Left { get; internal set; }
+
+  /// <summary>
+  /// Right border style
+  /// </summary>
+  public ExcelDxfBorderItem Right { get; internal set; }
+
+  /// <summary>
+  /// Top border style
+  /// </summary>
+  public ExcelDxfBorderItem Top { get; internal set; }
+
+  /// <summary>
+  /// Bottom border style
+  /// </summary>
+  public ExcelDxfBorderItem Bottom { get; internal set; }
+
+  ///// <summary>
+  ///// Diagonal border style
+  ///// </summary>
+  //public ExcelDxfBorderItem Diagonal
+  //{
+  //    get;
+  //    private set;
+  //}
+  ///// <summary>
+  ///// A diagonal from the bottom left to top right of the cell
+  ///// </summary>
+  //public bool DiagonalUp
+  //{
+  //    get;
+  //    set;
+  //}
+  ///// <summary>
+  ///// A diagonal from the top left to bottom right of the cell
+  ///// </summary>
+  //public bool DiagonalDown
+  //{
+  //    get;
+  //    set;
+  //}
+
+  protected internal override string Id =>
+    Top.Id
+        + Bottom.Id
+        + Left.Id
+        + Right.Id /* + Diagonal.Id + GetAsString(DiagonalUp) + GetAsString(DiagonalDown)*/;
+
+  protected internal override void CreateNodes(XmlHelper helper, string path) {
+    Left.CreateNodes(helper, path + "/d:left");
+    Right.CreateNodes(helper, path + "/d:right");
+    Top.CreateNodes(helper, path + "/d:top");
+    Bottom.CreateNodes(helper, path + "/d:bottom");
+  }
+
+  protected internal override bool HasValue =>
+    Left.HasValue || Right.HasValue || Top.HasValue || Bottom.HasValue;
+
+  protected internal override ExcelDxfBorderBase Clone() {
+    return new(_styles) {
+      Bottom = Bottom.Clone(),
+      Top = Top.Clone(),
+      Left = Left.Clone(),
+      Right = Right.Clone(),
+    };
+  }
+}
diff --git a/AppsheetEpplus/Style/Dxf/ExcelDxfBorderItem.cs b/AppsheetEpplus/Style/Dxf/ExcelDxfBorderItem.cs
new file mode 100644
index 0000000..029eac0
--- /dev/null
+++ b/AppsheetEpplus/Style/Dxf/ExcelDxfBorderItem.cs
@@ -0,0 +1,29 @@
+namespace AppsheetEpplus;
+
+public class ExcelDxfBorderItem : DxfStyleBase<ExcelDxfBorderItem> {
+  internal ExcelDxfBorderItem(ExcelStyles styles)
+      : base(styles) {
+    Color = new(styles);
+  }
+
+  public ExcelBorderStyle? Style { get; set; }
+
+  public ExcelDxfColor Color { get; internal set; }
+
+  protected internal override string Id =>
+    GetAsString(Style) + "|" + (Color == null ? "" : Color.Id);
+
+  protected internal override void CreateNodes(XmlHelper helper, string path) {
+    SetValueEnum(helper, path + "/@style", Style);
+    SetValueColor(helper, path + "/d:color", Color);
+  }
+
+  protected internal override bool HasValue => Style != null || Color.HasValue;
+
+  protected internal override ExcelDxfBorderItem Clone() {
+    return new(_styles) {
+      Style = Style,
+      Color = Color,
+    };
+  }
+}
diff --git a/AppsheetEpplus/Style/Dxf/ExcelDxfColor.cs b/AppsheetEpplus/Style/Dxf/ExcelDxfColor.cs
new file mode 100644
index 0000000..0cb4b36
--- /dev/null
+++ b/AppsheetEpplus/Style/Dxf/ExcelDxfColor.cs
@@ -0,0 +1,46 @@
+using System;
+
+namespace AppsheetEpplus;
+
+public class ExcelDxfColor : DxfStyleBase<ExcelDxfColor> {
+  public ExcelDxfColor(ExcelStyles styles)
+      : base(styles) {}
+
+  public int? Theme { get; set; }
+
+  public int? Index { get; set; }
+
+  public bool? Auto { get; set; }
+
+  public double? Tint { get; set; }
+
+  public string Rgb { get; set; }
+
+  protected internal override string Id =>
+    GetAsString(Theme)
+        + "|"
+        + GetAsString(Index)
+        + "|"
+        + GetAsString(Auto)
+        + "|"
+        + GetAsString(Tint)
+        + "|"
+        + GetAsString(Rgb);
+
+  protected internal override ExcelDxfColor Clone() {
+    return new(_styles) {
+      Theme = Theme,
+      Index = Index,
+      Rgb = Rgb,
+      Auto = Auto,
+      Tint = Tint,
+    };
+  }
+
+  protected internal override bool HasValue =>
+    Theme != null || Index != null || Auto != null || Tint != null || Rgb != null;
+
+  protected internal override void CreateNodes(XmlHelper helper, string path) {
+    throw new NotImplementedException();
+  }
+}
diff --git a/AppsheetEpplus/Style/Dxf/ExcelDxfFill.cs b/AppsheetEpplus/Style/Dxf/ExcelDxfFill.cs
new file mode 100644
index 0000000..887807d
--- /dev/null
+++ b/AppsheetEpplus/Style/Dxf/ExcelDxfFill.cs
@@ -0,0 +1,46 @@
+namespace AppsheetEpplus;
+
+public class ExcelDxfFill : DxfStyleBase<ExcelDxfFill> {
+  public ExcelDxfFill(ExcelStyles styles)
+      : base(styles) {
+    PatternColor = new(styles);
+    BackgroundColor = new(styles);
+  }
+
+  public ExcelFillStyle? PatternType { get; set; }
+
+  /// <summary>
+  /// The color of the pattern
+  /// </summary>
+  public ExcelDxfColor PatternColor { get; internal set; }
+
+  /// <summary>
+  /// The background color
+  /// </summary>
+  public ExcelDxfColor BackgroundColor { get; internal set; }
+
+  protected internal override string Id =>
+    GetAsString(PatternType)
+        + "|"
+        + (PatternColor == null ? "" : PatternColor.Id)
+        + "|"
+        + (BackgroundColor == null ? "" : BackgroundColor.Id);
+
+  protected internal override void CreateNodes(XmlHelper helper, string path) {
+    helper.CreateNode(path);
+    SetValueEnum(helper, path + "/d:patternFill/@patternType", PatternType);
+    SetValueColor(helper, path + "/d:patternFill/d:fgColor", PatternColor);
+    SetValueColor(helper, path + "/d:patternFill/d:bgColor", BackgroundColor);
+  }
+
+  protected internal override bool HasValue =>
+    PatternType != null || PatternColor.HasValue || BackgroundColor.HasValue;
+
+  protected internal override ExcelDxfFill Clone() {
+    return new(_styles) {
+      PatternType = PatternType,
+      PatternColor = PatternColor.Clone(),
+      BackgroundColor = BackgroundColor.Clone(),
+    };
+  }
+}
diff --git a/AppsheetEpplus/Style/Dxf/ExcelDxfFontBase.cs b/AppsheetEpplus/Style/Dxf/ExcelDxfFontBase.cs
new file mode 100644
index 0000000..cb81921
--- /dev/null
+++ b/AppsheetEpplus/Style/Dxf/ExcelDxfFontBase.cs
@@ -0,0 +1,72 @@
+namespace AppsheetEpplus;
+
+public class ExcelDxfFontBase : DxfStyleBase<ExcelDxfFontBase> {
+  public ExcelDxfFontBase(ExcelStyles styles)
+      : base(styles) {
+    Color = new(styles);
+  }
+
+  /// <summary>
+  /// Font bold
+  /// </summary>
+  public bool? Bold { get; set; }
+
+  /// <summary>
+  /// Font Italic
+  /// </summary>
+  public bool? Italic { get; set; }
+
+  /// <summary>
+  /// Font-Strikeout
+  /// </summary>
+  public bool? Strike { get; set; }
+
+  //public float? Size { get; set; }
+  public ExcelDxfColor Color { get; set; }
+
+  //public string Name { get; set; }
+  //public int? Family { get; set; }
+  ///// <summary>
+  ///// Font-Vertical Align
+  ///// </summary>
+  //public ExcelVerticalAlignmentFont? VerticalAlign
+  //{
+  //    get;
+  //    set;
+  //}
+
+  public ExcelUnderLineType? Underline { get; set; }
+
+  protected internal override string Id =>
+    GetAsString(Bold)
+        + "|"
+        + GetAsString(Italic)
+        + "|"
+        + GetAsString(Strike)
+        + "|"
+        + (Color == null ? "" : Color.Id)
+        + "|" /*+ GetAsString(VerticalAlign) + "|"*/
+        + GetAsString(Underline);
+
+  protected internal override void CreateNodes(XmlHelper helper, string path) {
+    helper.CreateNode(path);
+    SetValueBool(helper, path + "/d:b/@val", Bold);
+    SetValueBool(helper, path + "/d:i/@val", Italic);
+    SetValueBool(helper, path + "/d:strike", Strike);
+    SetValue(helper, path + "/d:u/@val", Underline);
+    SetValueColor(helper, path + "/d:color", Color);
+  }
+
+  protected internal override bool HasValue =>
+    Bold != null || Italic != null || Strike != null || Underline != null || Color.HasValue;
+
+  protected internal override ExcelDxfFontBase Clone() {
+    return new(_styles) {
+      Bold = Bold,
+      Color = Color.Clone(),
+      Italic = Italic,
+      Strike = Strike,
+      Underline = Underline,
+    };
+  }
+}
diff --git a/AppsheetEpplus/Style/Dxf/ExcelDxfNumberFormat.cs b/AppsheetEpplus/Style/Dxf/ExcelDxfNumberFormat.cs
new file mode 100644
index 0000000..7c00ffd
--- /dev/null
+++ b/AppsheetEpplus/Style/Dxf/ExcelDxfNumberFormat.cs
@@ -0,0 +1,77 @@
+namespace AppsheetEpplus;
+
+public class ExcelDxfNumberFormat : DxfStyleBase<ExcelDxfNumberFormat> {
+  public ExcelDxfNumberFormat(ExcelStyles styles)
+      : base(styles) {}
+
+  private int _numFmtID = int.MinValue;
+
+  /// <summary>
+  /// Id for number format
+  ///
+  /// Build in ID's
+  ///
+  /// 0   General
+  /// 1   0
+  /// 2   0.00
+  /// 3   #,##0
+  /// 4   #,##0.00
+  /// 9   0%
+  /// 10  0.00%
+  /// 11  0.00E+00
+  /// 12  # ?/?
+  /// 13  # ??/??
+  /// 14  mm-dd-yy
+  /// 15  d-mmm-yy
+  /// 16  d-mmm
+  /// 17  mmm-yy
+  /// 18  h:mm AM/PM
+  /// 19  h:mm:ss AM/PM
+  /// 20  h:mm
+  /// 21  h:mm:ss
+  /// 22  m/d/yy h:mm
+  /// 37  #,##0 ;(#,##0)
+  /// 38  #,##0 ;[Red](#,##0)
+  /// 39  #,##0.00;(#,##0.00)
+  /// 40  #,##0.00;[Red](#,##0.00)
+  /// 45  mm:ss
+  /// 46  [h]:mm:ss
+  /// 47  mmss.0
+  /// 48  ##0.0E+0
+  /// 49  @
+  /// </summary>
+  public int NumFmtID {
+    get => _numFmtID;
+    internal set => _numFmtID = value;
+  }
+
+  private string _format = "";
+
+  public string Format {
+    get => _format;
+    set {
+      _format = value;
+      NumFmtID = ExcelNumberFormat.GetFromBuildIdFromFormat(value);
+    }
+  }
+
+  protected internal override string Id => Format;
+
+  protected internal override void CreateNodes(XmlHelper helper, string path) {
+    if (NumFmtID < 0 && !string.IsNullOrEmpty(Format)) {
+      NumFmtID = _styles._nextDfxNumFmtID++;
+    }
+    helper.CreateNode(path);
+    SetValue(helper, path + "/@numFmtId", NumFmtID);
+    SetValue(helper, path + "/@formatCode", Format);
+  }
+
+  protected internal override bool HasValue => !string.IsNullOrEmpty(Format);
+
+  protected internal override ExcelDxfNumberFormat Clone() {
+    return new(_styles) {
+      NumFmtID = NumFmtID,
+      Format = Format,
+    };
+  }
+}
diff --git a/AppsheetEpplus/Style/Dxf/ExcelDxfStyle.cs b/AppsheetEpplus/Style/Dxf/ExcelDxfStyle.cs
new file mode 100644
index 0000000..7d3bde6
--- /dev/null
+++ b/AppsheetEpplus/Style/Dxf/ExcelDxfStyle.cs
@@ -0,0 +1,135 @@
+using System;
+using System.Collections.Immutable;
+using System.Globalization;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+public class ExcelDxfStyleConditionalFormatting : DxfStyleBase<ExcelDxfStyleConditionalFormatting> {
+  private readonly DxfStyleXmlHelper _helper;
+
+  private class DxfStyleXmlHelper(XmlNamespaceManager nameSpaceManager, XmlNode topNode)
+      : XmlHelper(nameSpaceManager, topNode) {
+    protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
+      "font",
+      "numFmt",
+      "fill",
+      "border",
+    ];
+  }
+
+  internal ExcelDxfStyleConditionalFormatting(
+      XmlNamespaceManager nameSpaceManager,
+      XmlNode topNode,
+      ExcelStyles styles)
+      : base(styles) {
+    NumberFormat = new(_styles);
+    Font = new(_styles);
+    Border = new(_styles);
+    Fill = new(_styles);
+    if (topNode != null) {
+      _helper = new(nameSpaceManager, topNode);
+      NumberFormat.NumFmtID = _helper.GetXmlNodeInt("d:numFmt/@numFmtId");
+      NumberFormat.Format = _helper.GetXmlNodeString("d:numFmt/@formatCode");
+      if (NumberFormat.NumFmtID < 164 && string.IsNullOrEmpty(NumberFormat.Format)) {
+        NumberFormat.Format = ExcelNumberFormat.GetFromBuildInFromId(NumberFormat.NumFmtID);
+      }
+
+      Font.Bold = _helper.GetXmlNodeBoolNullable("d:font/d:b/@val");
+      Font.Italic = _helper.GetXmlNodeBoolNullable("d:font/d:i/@val");
+      Font.Strike = _helper.GetXmlNodeBoolNullable("d:font/d:strike");
+      Font.Underline = GetUnderLineEnum(_helper.GetXmlNodeString("d:font/d:u/@val"));
+      Font.Color = GetColor(_helper, "d:font/d:color");
+
+      Border.Left = GetBorderItem(_helper, "d:border/d:left");
+      Border.Right = GetBorderItem(_helper, "d:border/d:right");
+      Border.Bottom = GetBorderItem(_helper, "d:border/d:bottom");
+      Border.Top = GetBorderItem(_helper, "d:border/d:top");
+
+      Fill.PatternType = GetPatternTypeEnum(
+          _helper.GetXmlNodeString("d:fill/d:patternFill/@patternType"));
+      Fill.BackgroundColor = GetColor(_helper, "d:fill/d:patternFill/d:bgColor/");
+      Fill.PatternColor = GetColor(_helper, "d:fill/d:patternFill/d:fgColor/");
+    } else {
+      _helper = new(nameSpaceManager, null);
+    }
+  }
+
+  private ExcelDxfBorderItem GetBorderItem(XmlHelper helper, string path) {
+    ExcelDxfBorderItem bi = new ExcelDxfBorderItem(_styles);
+    bi.Style = GetBorderStyleEnum(helper.GetXmlNodeString(path + "/@style"));
+    bi.Color = GetColor(helper, path + "/d:color");
+    return bi;
+  }
+
+  private ExcelBorderStyle GetBorderStyleEnum(string style) =>
+    Enum.TryParse<ExcelBorderStyle>(style, true, out var result) ? result : ExcelBorderStyle.None;
+
+  private ExcelFillStyle GetPatternTypeEnum(string patternType) =>
+    Enum.TryParse<ExcelFillStyle>(patternType, true, out var result) ? result : ExcelFillStyle.None;
+
+  private ExcelDxfColor GetColor(XmlHelper helper, string path) {
+    ExcelDxfColor ret = new ExcelDxfColor(_styles);
+    ret.Theme = helper.GetXmlNodeIntNull(path + "/@theme");
+    ret.Index = helper.GetXmlNodeIntNull(path + "/@indexed");
+    ret.Rgb = helper.GetXmlNodeString(path + "/@rgb");
+    ret.Auto = helper.GetXmlNodeBoolNullable(path + "/@auto");
+    ret.Tint = helper.GetXmlNodeDoubleNull(path + "/@tint");
+    return ret;
+  }
+
+  private ExcelUnderLineType? GetUnderLineEnum(string value) {
+    switch (value.ToLower(CultureInfo.InvariantCulture)) {
+      case "single":
+        return ExcelUnderLineType.Single;
+      case "double":
+        return ExcelUnderLineType.Double;
+      case "singleaccounting":
+        return ExcelUnderLineType.SingleAccounting;
+      case "doubleaccounting":
+        return ExcelUnderLineType.DoubleAccounting;
+      default:
+        return null;
+    }
+  }
+
+  internal int DxfId { get; set; }
+
+  public ExcelDxfFontBase Font { get; set; }
+
+  public ExcelDxfNumberFormat NumberFormat { get; set; }
+
+  public ExcelDxfFill Fill { get; set; }
+
+  public ExcelDxfBorderBase Border { get; set; }
+
+  protected internal override string Id =>
+    NumberFormat.Id + Font.Id + Border.Id + Fill.Id + (AllowChange ? "" : DxfId.ToString()); //If allowchange is false we add the dxfID to ensure it's not used when conditional formatting is updated);
+
+  protected internal override ExcelDxfStyleConditionalFormatting Clone() {
+    var s = new ExcelDxfStyleConditionalFormatting(_helper.NameSpaceManager, null, _styles);
+    s.Font = Font.Clone();
+    s.NumberFormat = NumberFormat.Clone();
+    s.Fill = Fill.Clone();
+    s.Border = Border.Clone();
+    return s;
+  }
+
+  protected internal override void CreateNodes(XmlHelper helper, string path) {
+    if (Font.HasValue) {
+      Font.CreateNodes(helper, "d:font");
+    }
+    if (NumberFormat.HasValue) {
+      NumberFormat.CreateNodes(helper, "d:numFmt");
+    }
+    if (Fill.HasValue) {
+      Fill.CreateNodes(helper, "d:fill");
+    }
+    if (Border.HasValue) {
+      Border.CreateNodes(helper, "d:border");
+    }
+  }
+
+  protected internal override bool HasValue =>
+    Font.HasValue || NumberFormat.HasValue || Fill.HasValue || Border.HasValue;
+}
diff --git a/AppsheetEpplus/Style/ExcelBorder.cs b/AppsheetEpplus/Style/ExcelBorder.cs
new file mode 100644
index 0000000..f5ba1ca
--- /dev/null
+++ b/AppsheetEpplus/Style/ExcelBorder.cs
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		                Initial Release		        2009-10-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Cell Border style
+/// </summary>
+public sealed class Border : StyleBase {
+  internal Border(
+      ExcelStyles styles,
+      XmlHelper.ChangedEventHandler changedEvent,
+      int positionId,
+      string address,
+      int index)
+      : base(styles, changedEvent, positionId, address) {
+    Index = index;
+  }
+
+  /// <summary>
+  /// Left border style
+  /// </summary>
+  public ExcelBorderItem Left =>
+    new(_styles, _ChangedEvent, _positionID, _address, eStyleClass.BorderLeft, this);
+
+  /// <summary>
+  /// Right border style
+  /// </summary>
+  public ExcelBorderItem Right =>
+    new(_styles, _ChangedEvent, _positionID, _address, eStyleClass.BorderRight, this);
+
+  /// <summary>
+  /// Top border style
+  /// </summary>
+  public ExcelBorderItem Top =>
+    new(_styles, _ChangedEvent, _positionID, _address, eStyleClass.BorderTop, this);
+
+  /// <summary>
+  /// Bottom border style
+  /// </summary>
+  public ExcelBorderItem Bottom =>
+    new(_styles, _ChangedEvent, _positionID, _address, eStyleClass.BorderBottom, this);
+
+  /// <summary>
+  /// 0Diagonal border style
+  /// </summary>
+  public ExcelBorderItem Diagonal =>
+    new(_styles, _ChangedEvent, _positionID, _address, eStyleClass.BorderDiagonal, this);
+
+  /// <summary>
+  /// A diagonal from the bottom left to top right of the cell
+  /// </summary>
+  public bool DiagonalUp {
+    get {
+      if (Index >= 0) {
+        return _styles.Borders[Index].DiagonalUp;
+      }
+      return false;
+    }
+  }
+
+  /// <summary>
+  /// A diagonal from the top left to bottom right of the cell
+  /// </summary>
+  public bool DiagonalDown {
+    get {
+      if (Index >= 0) {
+        return _styles.Borders[Index].DiagonalDown;
+      }
+      return false;
+    }
+  }
+
+  internal override string Id =>
+    Top.Id + Bottom.Id + Left.Id + Right.Id + Diagonal.Id + DiagonalUp + DiagonalDown;
+}
diff --git a/AppsheetEpplus/Style/ExcelBorderItem.cs b/AppsheetEpplus/Style/ExcelBorderItem.cs
new file mode 100644
index 0000000..e1fc6d9
--- /dev/null
+++ b/AppsheetEpplus/Style/ExcelBorderItem.cs
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		                Initial Release		        2009-10-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Cell border style
+/// </summary>
+public sealed class ExcelBorderItem : StyleBase {
+  private readonly eStyleClass _cls;
+  private readonly StyleBase _parent;
+
+  internal ExcelBorderItem(
+      ExcelStyles styles,
+      XmlHelper.ChangedEventHandler changedEvent,
+      int worksheetId,
+      string address,
+      eStyleClass cls,
+      StyleBase parent)
+      : base(styles, changedEvent, worksheetId, address) {
+    _cls = cls;
+    _parent = parent;
+  }
+
+  /// <summary>
+  /// The line style of the border
+  /// </summary>
+  public ExcelBorderStyle Style => GetSource().Style;
+
+  private ExcelColor _color;
+
+  /// <summary>
+  /// The color of the border
+  /// </summary>
+  public ExcelColor Color {
+    get {
+      if (_color == null) {
+        _color = new(_styles, _ChangedEvent, _positionID, _address, _cls, _parent);
+      }
+      return _color;
+    }
+  }
+
+  internal override string Id => Style + Color.Id;
+
+  internal override void SetIndex(int index) {
+    _parent.Index = index;
+  }
+
+  private ExcelBorderItemXml GetSource() {
+    int ix = _parent.Index < 0 ? 0 : _parent.Index;
+
+    switch (_cls) {
+      case eStyleClass.BorderTop:
+        return _styles.Borders[ix].Top;
+      case eStyleClass.BorderBottom:
+        return _styles.Borders[ix].Bottom;
+      case eStyleClass.BorderLeft:
+        return _styles.Borders[ix].Left;
+      case eStyleClass.BorderRight:
+        return _styles.Borders[ix].Right;
+      case eStyleClass.BorderDiagonal:
+        return _styles.Borders[ix].Diagonal;
+      default:
+        throw new("Invalid class for Borderitem");
+    }
+  }
+}
diff --git a/AppsheetEpplus/Style/ExcelColor.cs b/AppsheetEpplus/Style/ExcelColor.cs
new file mode 100644
index 0000000..61ccc6d
--- /dev/null
+++ b/AppsheetEpplus/Style/ExcelColor.cs
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		                Initial Release		        2009-10-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Color for cellstyling
+/// </summary>
+public sealed class ExcelColor : StyleBase {
+  private readonly eStyleClass _cls;
+  private readonly StyleBase _parent;
+
+  internal ExcelColor(
+      ExcelStyles styles,
+      XmlHelper.ChangedEventHandler changedEvent,
+      int worksheetId,
+      string address,
+      eStyleClass cls,
+      StyleBase parent)
+      : base(styles, changedEvent, worksheetId, address) {
+    _parent = parent;
+    _cls = cls;
+  }
+
+  /// <summary>
+  /// The theme color
+  /// </summary>
+  public string Theme => GetSource().Theme;
+
+  /// <summary>
+  /// The tint value
+  /// </summary>
+  public decimal Tint => GetSource().Tint;
+
+  /// <summary>
+  /// The RGB value
+  /// </summary>
+  public string Rgb => GetSource().Rgb;
+
+  /// <summary>
+  /// The indexed color number.
+  /// </summary>
+  public int Indexed => GetSource().Indexed;
+
+  internal override string Id => Theme + Tint + Rgb + Indexed;
+
+  private ExcelColorXml GetSource() {
+    Index = _parent.Index < 0 ? 0 : _parent.Index;
+    switch (_cls) {
+      case eStyleClass.FillBackgroundColor:
+        return _styles.Fills[Index].BackgroundColor;
+      case eStyleClass.FillPatternColor:
+        return _styles.Fills[Index].PatternColor;
+      case eStyleClass.Font:
+        return _styles.Fonts[Index].Color;
+      case eStyleClass.BorderLeft:
+        return _styles.Borders[Index].Left.Color;
+      case eStyleClass.BorderTop:
+        return _styles.Borders[Index].Top.Color;
+      case eStyleClass.BorderRight:
+        return _styles.Borders[Index].Right.Color;
+      case eStyleClass.BorderBottom:
+        return _styles.Borders[Index].Bottom.Color;
+      case eStyleClass.BorderDiagonal:
+        return _styles.Borders[Index].Diagonal.Color;
+      default:
+        throw (new("Invalid style-class for Color"));
+    }
+  }
+
+  internal override void SetIndex(int index) {
+    _parent.Index = index;
+  }
+}
diff --git a/AppsheetEpplus/Style/ExcelFill.cs b/AppsheetEpplus/Style/ExcelFill.cs
new file mode 100644
index 0000000..620e9af
--- /dev/null
+++ b/AppsheetEpplus/Style/ExcelFill.cs
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		                Initial Release		        2009-10-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// The background fill of a cell
+/// </summary>
+public class ExcelFill : StyleBase {
+  internal ExcelFill(
+      ExcelStyles styles,
+      XmlHelper.ChangedEventHandler changedEvent,
+      int positionId,
+      string address,
+      int index)
+      : base(styles, changedEvent, positionId, address) {
+    Index = index;
+  }
+
+  /// <summary>
+  /// The pattern for solid fills.
+  /// </summary>
+  public ExcelFillStyle PatternType {
+    get {
+      if (Index == int.MinValue) {
+        return ExcelFillStyle.None;
+      }
+      return _styles.Fills[Index].PatternType;
+    }
+  }
+
+  private ExcelColor _patternColor;
+
+  /// <summary>
+  /// The color of the pattern
+  /// </summary>
+  public ExcelColor PatternColor {
+    get {
+      if (_patternColor == null) {
+        _patternColor = new(
+            _styles,
+            _ChangedEvent,
+            _positionID,
+            _address,
+            eStyleClass.FillPatternColor,
+            this);
+        if (_gradient != null) {
+          _gradient = null;
+        }
+      }
+      return _patternColor;
+    }
+  }
+
+  private ExcelColor _backgroundColor;
+
+  /// <summary>
+  /// The background color
+  /// </summary>
+  public ExcelColor BackgroundColor {
+    get {
+      if (_backgroundColor == null) {
+        _backgroundColor = new(
+            _styles,
+            _ChangedEvent,
+            _positionID,
+            _address,
+            eStyleClass.FillBackgroundColor,
+            this);
+        if (_gradient != null) {
+          _gradient = null;
+        }
+      }
+      return _backgroundColor;
+    }
+  }
+
+  private ExcelGradientFill _gradient;
+
+  /// <summary>
+  /// Access to properties for gradient fill.
+  /// </summary>
+  public ExcelGradientFill Gradient {
+    get {
+      if (_gradient == null) {
+        _gradient = new(_styles, _ChangedEvent, _positionID, _address, Index);
+        _backgroundColor = null;
+        _patternColor = null;
+      }
+      return _gradient;
+    }
+  }
+
+  internal override string Id {
+    get {
+      if (_gradient == null) {
+        return PatternType + PatternColor.Id + BackgroundColor.Id;
+      }
+      return _gradient.Id;
+    }
+  }
+}
diff --git a/AppsheetEpplus/Style/ExcelFont.cs b/AppsheetEpplus/Style/ExcelFont.cs
new file mode 100644
index 0000000..bbb1ca4
--- /dev/null
+++ b/AppsheetEpplus/Style/ExcelFont.cs
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		                Initial Release		        2009-10-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Cell style Font
+/// </summary>
+public sealed class ExcelFont : StyleBase {
+  internal ExcelFont(
+      ExcelStyles styles,
+      XmlHelper.ChangedEventHandler changedEvent,
+      int positionId,
+      string address,
+      int index)
+      : base(styles, changedEvent, positionId, address) {
+    Index = index;
+  }
+
+  /// <summary>
+  /// The name of the font
+  /// </summary>
+  public string Name => _styles.Fonts[Index].Name;
+
+  /// <summary>
+  /// The Size of the font
+  /// </summary>
+  public float Size => _styles.Fonts[Index].Size;
+
+  /// <summary>
+  /// Font family
+  /// </summary>
+  public int Family => _styles.Fonts[Index].Family;
+
+  /// <summary>
+  /// Cell color
+  /// </summary>
+  public ExcelColor Color =>
+    new(_styles, _ChangedEvent, _positionID, _address, eStyleClass.Font, this);
+
+  /// <summary>
+  /// Scheme
+  /// </summary>
+  public string Scheme => _styles.Fonts[Index].Scheme;
+
+  /// <summary>
+  /// Font-bold
+  /// </summary>
+  public bool Bold {
+    get => _styles.Fonts[Index].Bold;
+    set =>
+      _ChangedEvent(this, new(eStyleClass.Font, eStyleProperty.Bold, value, _positionID, _address));
+  }
+
+  /// <summary>
+  /// Font-italic
+  /// </summary>
+  public bool Italic => _styles.Fonts[Index].Italic;
+
+  /// <summary>
+  /// Font-Strikeout
+  /// </summary>
+  public bool Strike => _styles.Fonts[Index].Strike;
+
+  /// <summary>
+  /// Font-Underline
+  /// </summary>
+  public bool UnderLine => _styles.Fonts[Index].UnderLine;
+
+  public ExcelUnderLineType UnderLineType => _styles.Fonts[Index].UnderLineType;
+
+  /// <summary>
+  /// Font-Vertical Align
+  /// </summary>
+  public ExcelVerticalAlignmentFont VerticalAlign =>
+    Enum.TryParse<ExcelVerticalAlignmentFont>(
+        _styles.Fonts[Index].VerticalAlign,
+        true,
+        out var result)
+        ? result
+        : ExcelVerticalAlignmentFont.None;
+
+  internal override string Id =>
+    Name
+        + Size
+        + Family
+        + Scheme
+        + Bold.ToString()[0]
+        + Italic.ToString()[0]
+        + Strike.ToString()[0]
+        + UnderLine.ToString()[0]
+        + VerticalAlign;
+}
diff --git a/AppsheetEpplus/Style/ExcelGradientFill.cs b/AppsheetEpplus/Style/ExcelGradientFill.cs
new file mode 100644
index 0000000..ab645e3
--- /dev/null
+++ b/AppsheetEpplus/Style/ExcelGradientFill.cs
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		                Initial Release		        2009-10-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// The background fill of a cell
+/// </summary>
+public class ExcelGradientFill : StyleBase {
+  internal ExcelGradientFill(
+      ExcelStyles styles,
+      XmlHelper.ChangedEventHandler changedEvent,
+      int positionId,
+      string address,
+      int index)
+      : base(styles, changedEvent, positionId, address) {
+    Index = index;
+  }
+
+  /// <summary>
+  /// Angle of the linear gradient
+  /// </summary>
+  public double Degree => ((ExcelGradientFillXml)_styles.Fills[Index]).Degree;
+
+  /// <summary>
+  /// Linear or Path gradient
+  /// </summary>
+  public ExcelFillGradientType Type => ((ExcelGradientFillXml)_styles.Fills[Index]).Type;
+
+  /// <summary>
+  /// Specifies in percentage format(from the top to the bottom) the position of the top edge of the inner rectangle (color 1). For top, 0 means the top edge of the inner rectangle is on the top edge of the cell, and 1 means it is on the bottom edge of the cell. (applies to From Corner and From Center gradients).
+  /// </summary>
+  public double Top => ((ExcelGradientFillXml)_styles.Fills[Index]).Top;
+
+  /// <summary>
+  /// Specifies in percentage format (from the top to the bottom) the position of the bottom edge of the inner rectangle (color 1). For bottom, 0 means the bottom edge of the inner rectangle is on the top edge of the cell, and 1 means it is on the bottom edge of the cell.
+  /// </summary>
+  public double Bottom => ((ExcelGradientFillXml)_styles.Fills[Index]).Bottom;
+
+  /// <summary>
+  /// Specifies in percentage format (from the left to the right) the position of the left edge of the inner rectangle (color 1). For left, 0 means the left edge of the inner rectangle is on the left edge of the cell, and 1 means it is on the right edge of the cell. (applies to From Corner and From Center gradients).
+  /// </summary>
+  public double Left => ((ExcelGradientFillXml)_styles.Fills[Index]).Left;
+
+  /// <summary>
+  /// Specifies in percentage format (from the left to the right) the position of the right edge of the inner rectangle (color 1). For right, 0 means the right edge of the inner rectangle is on the left edge of the cell, and 1 means it is on the right edge of the cell. (applies to From Corner and From Center gradients).
+  /// </summary>
+  public double Right => ((ExcelGradientFillXml)_styles.Fills[Index]).Right;
+
+  private ExcelColor _gradientColor1;
+
+  /// <summary>
+  /// Gradient Color 1
+  /// </summary>
+  public ExcelColor Color1 {
+    get {
+      if (_gradientColor1 == null) {
+        _gradientColor1 = new(
+            _styles,
+            _ChangedEvent,
+            _positionID,
+            _address,
+            eStyleClass.FillGradientColor1,
+            this);
+      }
+      return _gradientColor1;
+    }
+  }
+
+  private ExcelColor _gradientColor2;
+
+  /// <summary>
+  /// Gradient Color 2
+  /// </summary>
+  public ExcelColor Color2 {
+    get {
+      if (_gradientColor2 == null) {
+        _gradientColor2 = new(
+            _styles,
+            _ChangedEvent,
+            _positionID,
+            _address,
+            eStyleClass.FillGradientColor2,
+            this);
+      }
+      return _gradientColor2;
+    }
+  }
+
+  internal override string Id =>
+    Degree.ToString() + Type + Color1.Id + Color2.Id + Top + Bottom + Left + Right;
+}
diff --git a/AppsheetEpplus/Style/ExcelNumberFormat.cs b/AppsheetEpplus/Style/ExcelNumberFormat.cs
new file mode 100644
index 0000000..e728eca
--- /dev/null
+++ b/AppsheetEpplus/Style/ExcelNumberFormat.cs
@@ -0,0 +1,210 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		                Initial Release		        2009-10-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// The numberformat of the cell
+/// </summary>
+public sealed class ExcelNumberFormat : StyleBase {
+  internal ExcelNumberFormat(
+      ExcelStyles styles,
+      XmlHelper.ChangedEventHandler changedEvent,
+      int positionId,
+      string address,
+      int index)
+      : base(styles, changedEvent, positionId, address) {
+    Index = index;
+  }
+
+  /// <summary>
+  /// The numeric index fror the format
+  /// </summary>
+  public int NumFmtID => Index;
+
+  /// <summary>
+  /// The numberformat
+  /// </summary>
+  public string Format {
+    get {
+      for (int i = 0; i < _styles.NumberFormats.Count; i++) {
+        if (Index == _styles.NumberFormats[i].NumFmtId) {
+          return _styles.NumberFormats[i].Format;
+        }
+      }
+      return "general";
+    }
+    set =>
+      _ChangedEvent(
+          this,
+          new(
+              eStyleClass.Numberformat,
+              eStyleProperty.Format,
+              (string.IsNullOrEmpty(value) ? "General" : value),
+              _positionID,
+              _address));
+  }
+
+  internal override string Id => Format;
+
+  /// <summary>
+  /// If the numeric format is a build-in from.
+  /// </summary>
+  public bool BuildIn { get; private set; }
+
+  internal static string GetFromBuildInFromId(int numFmtId) {
+    switch (numFmtId) {
+      case 0:
+        return "General";
+      case 1:
+        return "0";
+      case 2:
+        return "0.00";
+      case 3:
+        return "#,##0";
+      case 4:
+        return "#,##0.00";
+      case 9:
+        return "0%";
+      case 10:
+        return "0.00%";
+      case 11:
+        return "0.00E+00";
+      case 12:
+        return "# ?/?";
+      case 13:
+        return "# ??/??";
+      case 14:
+        return "mm-dd-yy";
+      case 15:
+        return "d-mmm-yy";
+      case 16:
+        return "d-mmm";
+      case 17:
+        return "mmm-yy";
+      case 18:
+        return "h:mm AM/PM";
+      case 19:
+        return "h:mm:ss AM/PM";
+      case 20:
+        return "h:mm";
+      case 21:
+        return "h:mm:ss";
+      case 22:
+        return "m/d/yy h:mm";
+      case 37:
+        return "#,##0 ;(#,##0)";
+      case 38:
+        return "#,##0 ;[Red](#,##0)";
+      case 39:
+        return "#,##0.00;(#,##0.00)";
+      case 40:
+        return "#,##0.00;[Red](#,##0.00)";
+      case 45:
+        return "mm:ss";
+      case 46:
+        return "[h]:mm:ss";
+      case 47:
+        return "mmss.0";
+      case 48:
+        return "##0.0";
+      case 49:
+        return "@";
+      default:
+        return string.Empty;
+    }
+  }
+
+  internal static int GetFromBuildIdFromFormat(string format) {
+    switch (format) {
+      case "General":
+      case "":
+        return 0;
+      case "0":
+        return 1;
+      case "0.00":
+        return 2;
+      case "#,##0":
+        return 3;
+      case "#,##0.00":
+        return 4;
+      case "0%":
+        return 9;
+      case "0.00%":
+        return 10;
+      case "0.00E+00":
+        return 11;
+      case "# ?/?":
+        return 12;
+      case "# ??/??":
+        return 13;
+      case "mm-dd-yy":
+        return 14;
+      case "d-mmm-yy":
+        return 15;
+      case "d-mmm":
+        return 16;
+      case "mmm-yy":
+        return 17;
+      case "h:mm AM/PM":
+        return 18;
+      case "h:mm:ss AM/PM":
+        return 19;
+      case "h:mm":
+        return 20;
+      case "h:mm:ss":
+        return 21;
+      case "m/d/yy h:mm":
+        return 22;
+      case "#,##0 ;(#,##0)":
+        return 37;
+      case "#,##0 ;[Red](#,##0)":
+        return 38;
+      case "#,##0.00;(#,##0.00)":
+        return 39;
+      case "#,##0.00;[Red](#,##0.00)":
+        return 40;
+      case "mm:ss":
+        return 45;
+      case "[h]:mm:ss":
+        return 46;
+      case "mmss.0":
+        return 47;
+      case "##0.0":
+        return 48;
+      case "@":
+        return 49;
+      default:
+        return int.MinValue;
+    }
+  }
+}
diff --git a/AppsheetEpplus/Style/ExcelRichText.cs b/AppsheetEpplus/Style/ExcelRichText.cs
new file mode 100644
index 0000000..e585a77
--- /dev/null
+++ b/AppsheetEpplus/Style/ExcelRichText.cs
@@ -0,0 +1,277 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		                Initial Release		        2009-10-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ * Richard Tallent					Fix inadvertent removal of XML node					2012-10-31
+ * Richard Tallent					Remove VertAlign node if no alignment specified		2012-10-31
+ *******************************************************************************/
+
+using System;
+using System.Collections.Immutable;
+using System.Globalization;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// A richtext part
+/// </summary>
+public class ExcelRichText : XmlHelper {
+  protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
+    "rPr",
+    "t",
+    "b",
+    "i",
+    "strike",
+    "u",
+    "vertAlign",
+    "sz",
+    "color",
+    "rFont",
+    "family",
+    "scheme",
+    "charset",
+  ];
+
+  internal ExcelRichText(
+      XmlNamespaceManager ns,
+      XmlNode topNode,
+      ExcelRichTextCollection collection)
+      : base(ns, topNode) {
+    _collection = collection;
+  }
+
+  internal delegate void CallbackDelegate();
+
+  private CallbackDelegate _callback;
+
+  internal void SetCallback(CallbackDelegate callback) {
+    _callback = callback;
+  }
+
+  private const string _textPath = "d:t";
+
+  /// <summary>
+  /// The text
+  /// </summary>
+  public string Text {
+    get {
+      // Bug 15151
+      if (TopNode.Name == "t") {
+        return TopNode.InnerText;
+      }
+      return GetXmlNodeString(_textPath);
+    }
+    set {
+      _collection.ConvertRichtext();
+      // Don't remove if blank -- setting a blank rich text value on a node is common,
+      // for example when applying both bold and italic to text.
+      SetXmlNodeString(_textPath, value, false);
+      if (PreserveSpace) {
+        XmlElement elem = TopNode.SelectSingleNode(_textPath, NameSpaceManager) as XmlElement;
+        elem.SetAttribute("xml:space", "preserve");
+      }
+      if (_callback != null) {
+        _callback();
+      }
+    }
+  }
+
+  /// <summary>
+  /// Preserves whitespace. Default true
+  /// </summary>
+  public bool PreserveSpace {
+    get {
+      XmlElement elem = TopNode.SelectSingleNode(_textPath, NameSpaceManager) as XmlElement;
+      if (elem != null) {
+        return elem.GetAttribute("xml:space") == "preserve";
+      }
+      return false;
+    }
+    set {
+      _collection.ConvertRichtext();
+      XmlElement elem = TopNode.SelectSingleNode(_textPath, NameSpaceManager) as XmlElement;
+      if (elem != null) {
+        if (value) {
+          elem.SetAttribute("xml:space", "preserve");
+        } else {
+          elem.RemoveAttribute("xml:space");
+        }
+      }
+      if (_callback != null) {
+        _callback();
+      }
+    }
+  }
+
+  private const string _boldPath = "d:rPr/d:b";
+
+  /// <summary>
+  /// Bold text
+  /// </summary>
+  public bool Bold {
+    get => ExistNode(_boldPath);
+    set {
+      _collection.ConvertRichtext();
+      if (value) {
+        CreateNode(_boldPath);
+      } else {
+        DeleteNode(_boldPath);
+      }
+      if (_callback != null) {
+        _callback();
+      }
+    }
+  }
+
+  private const string _italicPath = "d:rPr/d:i";
+
+  /// <summary>
+  /// Italic text
+  /// </summary>
+  public bool Italic {
+    get =>
+      //return GetXmlNodeBool(ITALIC_PATH, false);
+      ExistNode(_italicPath);
+    set {
+      _collection.ConvertRichtext();
+      if (value) {
+        CreateNode(_italicPath);
+      } else {
+        DeleteNode(_italicPath);
+      }
+      if (_callback != null) {
+        _callback();
+      }
+    }
+  }
+
+  private const string _strikePath = "d:rPr/d:strike";
+
+  /// <summary>
+  /// Strike-out text
+  /// </summary>
+  public bool Strike {
+    get => ExistNode(_strikePath);
+    set {
+      _collection.ConvertRichtext();
+      if (value) {
+        CreateNode(_strikePath);
+      } else {
+        DeleteNode(_strikePath);
+      }
+      if (_callback != null) {
+        _callback();
+      }
+    }
+  }
+
+  private const string _underlinePath = "d:rPr/d:u";
+
+  /// <summary>
+  /// Underlined text
+  /// </summary>
+  public bool UnderLine {
+    get => ExistNode(_underlinePath);
+    set {
+      _collection.ConvertRichtext();
+      if (value) {
+        CreateNode(_underlinePath);
+      } else {
+        DeleteNode(_underlinePath);
+      }
+      if (_callback != null) {
+        _callback();
+      }
+    }
+  }
+
+  private const string _vertAlignPath = "d:rPr/d:vertAlign/@val";
+
+  /// <summary>
+  /// Vertical Alignment
+  /// </summary>
+  public ExcelVerticalAlignmentFont VerticalAlign =>
+    Enum.TryParse<ExcelVerticalAlignmentFont>(
+        GetXmlNodeString(TopNode, _vertAlignPath),
+        true,
+        out var result)
+        ? result
+        : ExcelVerticalAlignmentFont.None;
+
+  private const string _sizePath = "d:rPr/d:sz/@val";
+
+  /// <summary>
+  /// Font size
+  /// </summary>
+  public float Size {
+    get => Convert.ToSingle(GetXmlNodeDecimal(_sizePath));
+    set {
+      _collection.ConvertRichtext();
+      SetXmlNodeString(_sizePath, value.ToString(CultureInfo.InvariantCulture));
+      if (_callback != null) {
+        _callback();
+      }
+    }
+  }
+
+  private const string _fontPath = "d:rPr/d:rFont/@val";
+
+  /// <summary>
+  /// Name of the font
+  /// </summary>
+  public string FontName {
+    get => GetXmlNodeString(_fontPath);
+    set {
+      _collection.ConvertRichtext();
+      SetXmlNodeString(_fontPath, value);
+      if (_callback != null) {
+        _callback();
+      }
+    }
+  }
+
+  private const string _colorPath = "d:rPr/d:color/@rgb";
+
+  /// <summary>
+  /// Text color
+  /// </summary>
+  public string Color {
+    get => GetXmlNodeString(_colorPath);
+    set {
+      _collection.ConvertRichtext();
+      SetXmlNodeString(_colorPath, value);
+      if (_callback != null) {
+        _callback();
+      }
+    }
+  }
+
+  public ExcelRichTextCollection _collection { get; set; }
+}
diff --git a/AppsheetEpplus/Style/ExcelRichTextCollection.cs b/AppsheetEpplus/Style/ExcelRichTextCollection.cs
new file mode 100644
index 0000000..2641b2e
--- /dev/null
+++ b/AppsheetEpplus/Style/ExcelRichTextCollection.cs
@@ -0,0 +1,233 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		                Initial Release		        2009-10-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Collection of Richtext objects
+/// </summary>
+public class ExcelRichTextCollection : XmlHelper, IEnumerable<ExcelRichText> {
+  private readonly List<ExcelRichText> _list = new();
+  private readonly ExcelRangeBase _cells;
+
+  internal ExcelRichTextCollection(XmlNamespaceManager ns, XmlNode topNode)
+      : base(ns, topNode) {
+    var nl = topNode.SelectNodes("d:r|d:t", NameSpaceManager); // Bug 15151
+    if (nl != null) {
+      foreach (XmlNode n in nl) {
+        _list.Add(new(ns, n, this));
+      }
+    }
+  }
+
+  internal ExcelRichTextCollection(XmlNamespaceManager ns, XmlNode topNode, ExcelRangeBase cells)
+      : this(ns, topNode) {
+    _cells = cells;
+  }
+
+  /// <summary>
+  /// Collection containing the richtext objects
+  /// </summary>
+  /// <param name="index"></param>
+  /// <returns></returns>
+  public ExcelRichText this[int index] {
+    get {
+      var item = _list[index];
+      if (_cells != null) {
+        item.SetCallback(UpdateCells);
+      }
+      return item;
+    }
+  }
+
+  /// <summary>
+  /// Items in the list
+  /// </summary>
+  public int Count => _list.Count;
+
+  /// <summary>
+  /// Add a rich text string
+  /// </summary>
+  /// <param name="text">The text to add</param>
+  /// <returns></returns>
+  public ExcelRichText Add(string text) {
+    ConvertRichtext();
+    XmlDocument doc;
+    if (TopNode is XmlDocument document) {
+      doc = document;
+    } else {
+      doc = TopNode.OwnerDocument;
+    }
+    var node = doc.CreateElement("d", "r", ExcelPackage._schemaMain);
+    TopNode.AppendChild(node);
+    var rt = new ExcelRichText(NameSpaceManager, node, this);
+    if (_list.Count > 0) {
+      ExcelRichText prevItem = _list[_list.Count - 1];
+      rt.FontName = prevItem.FontName;
+      rt.Size = prevItem.Size;
+      rt.Color = prevItem.Color == "" ? "FF00000" : prevItem.Color;
+      rt.PreserveSpace = rt.PreserveSpace;
+      rt.Bold = prevItem.Bold;
+      rt.Italic = prevItem.Italic;
+      rt.UnderLine = prevItem.UnderLine;
+    } else if (_cells == null) {
+      rt.FontName = "Calibri";
+      rt.Size = 11;
+    } else {
+      var style = _cells.Offset(0, 0).Style;
+      rt.FontName = style.Font.Name;
+      rt.Size = style.Font.Size;
+      rt.Bold = style.Font.Bold;
+      rt.Italic = style.Font.Italic;
+      _cells.IsRichText = true;
+    }
+    rt.Text = text;
+    rt.PreserveSpace = true;
+    if (_cells != null) {
+      rt.SetCallback(UpdateCells);
+      UpdateCells();
+    }
+    _list.Add(rt);
+    return rt;
+  }
+
+  internal void ConvertRichtext() {
+    if (_cells == null) {
+      return;
+    }
+    var isRt = _cells.Worksheet._flags.GetFlagValue(
+        _cells._fromRow,
+        _cells._fromCol,
+        CellFlags.RichText);
+    if (Count == 1 && isRt == false) {
+      _cells.Worksheet._flags.SetFlagValue(
+          _cells._fromRow,
+          _cells._fromCol,
+          true,
+          CellFlags.RichText);
+      var s = _cells.Worksheet._styles.GetValue(_cells._fromRow, _cells._fromCol);
+      //var fnt = cell.Style.Font;
+      var fnt = _cells.Worksheet.Workbook.Styles
+          .GetStyleObject(
+              s,
+              _cells.Worksheet.PositionID,
+              ExcelCellBase.GetAddress(_cells._fromRow, _cells._fromCol))
+          .Font;
+      this[0].PreserveSpace = true;
+      this[0].Bold = fnt.Bold;
+      this[0].FontName = fnt.Name;
+      this[0].Italic = fnt.Italic;
+      this[0].Size = fnt.Size;
+      this[0].UnderLine = fnt.UnderLine;
+    }
+  }
+
+  internal void UpdateCells() {
+    _cells.SetValueRichText(TopNode.InnerXml);
+  }
+
+  /// <summary>
+  /// Removes an item at the specific index
+  /// </summary>
+  /// <param name="index"></param>
+  public void RemoveAt(int index) {
+    TopNode.RemoveChild(_list[index].TopNode);
+    _list.RemoveAt(index);
+    if (_cells != null && _list.Count == 0) {
+      _cells.IsRichText = false;
+    }
+  }
+
+  /// <summary>
+  /// Removes an item
+  /// </summary>
+  /// <param name="item"></param>
+  public void Remove(ExcelRichText item) {
+    TopNode.RemoveChild(item.TopNode);
+    _list.Remove(item);
+    if (_cells != null && _list.Count == 0) {
+      _cells.IsRichText = false;
+    }
+  }
+
+  //public void Insert(int index, string Text)
+  //{
+  //    _list.Insert(index, item);
+  //}
+
+  /// <summary>
+  /// The text
+  /// </summary>
+  public string Text {
+    get {
+      StringBuilder sb = new StringBuilder();
+      foreach (var item in _list) {
+        sb.Append(item.Text);
+      }
+      return sb.ToString();
+    }
+    set {
+      if (Count == 0) {
+        Add(value);
+      } else {
+        this[0].Text = value;
+        for (int ix = 1; ix < Count; ix++) {
+          RemoveAt(ix);
+        }
+      }
+    }
+  }
+
+  IEnumerator<ExcelRichText> IEnumerable<ExcelRichText>.GetEnumerator() {
+    return _list
+        .Select(x => {
+          x.SetCallback(UpdateCells);
+          return x;
+        })
+        .GetEnumerator();
+  }
+
+  IEnumerator IEnumerable.GetEnumerator() {
+    return _list
+        .Select(x => {
+          x.SetCallback(UpdateCells);
+          return x;
+        })
+        .GetEnumerator();
+  }
+}
diff --git a/AppsheetEpplus/Style/ExcelStyle.cs b/AppsheetEpplus/Style/ExcelStyle.cs
new file mode 100644
index 0000000..65d5a28
--- /dev/null
+++ b/AppsheetEpplus/Style/ExcelStyle.cs
@@ -0,0 +1,162 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		                Initial Release		        2009-10-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Toplevel class for cell styling
+/// </summary>
+public sealed class ExcelStyle : StyleBase {
+  internal ExcelStyle(
+      ExcelStyles styles,
+      XmlHelper.ChangedEventHandler changedEvent,
+      int positionId,
+      string address,
+      int xfsId)
+      : base(styles, changedEvent, positionId, address) {
+    Index = xfsId;
+    ExcelXfs xfs;
+    if (positionId > -1) {
+      xfs = _styles.CellXfs[xfsId];
+    } else {
+      xfs = _styles.CellStyleXfs[xfsId];
+    }
+    Styles = styles;
+    PositionID = positionId;
+    Numberformat = new(styles, changedEvent, PositionID, address, xfs.NumberFormatId);
+    Font = new(styles, changedEvent, PositionID, address, xfs.FontId);
+    Fill = new(styles, changedEvent, PositionID, address, xfs.FillId);
+    Border = new(styles, changedEvent, PositionID, address, xfs.BorderId);
+  }
+
+  /// <summary>
+  /// Numberformat
+  /// </summary>
+  public ExcelNumberFormat Numberformat { get; set; }
+
+  /// <summary>
+  /// Font styling
+  /// </summary>
+  public ExcelFont Font { get; set; }
+
+  /// <summary>
+  /// Fill Styling
+  /// </summary>
+  public ExcelFill Fill { get; set; }
+
+  /// <summary>
+  /// Border
+  /// </summary>
+  public Border Border { get; set; }
+
+  /// <summary>
+  /// The horizontal alignment in the cell
+  /// </summary>
+  public ExcelHorizontalAlignment HorizontalAlignment => _styles.CellXfs[Index].HorizontalAlignment;
+
+  /// <summary>
+  /// The vertical alignment in the cell
+  /// </summary>
+  public ExcelVerticalAlignment VerticalAlignment => _styles.CellXfs[Index].VerticalAlignment;
+
+  /// <summary>
+  /// Wrap the text
+  /// </summary>
+  public bool WrapText {
+    get => _styles.CellXfs[Index].WrapText;
+    set =>
+      _ChangedEvent(
+          this,
+          new(eStyleClass.Style, eStyleProperty.WrapText, value, _positionID, _address));
+  }
+
+  /// <summary>
+  /// Readingorder
+  /// </summary>
+  public ExcelReadingOrder ReadingOrder => _styles.CellXfs[Index].ReadingOrder;
+
+  /// <summary>
+  /// Shrink the text to fit
+  /// </summary>
+  public bool ShrinkToFit => _styles.CellXfs[Index].ShrinkToFit;
+
+  /// <summary>
+  /// The margin between the border and the text
+  /// </summary>
+  public int Indent => _styles.CellXfs[Index].Indent;
+
+  /// <summary>
+  /// Text orientation in degrees. Values range from 0 to 180.
+  /// </summary>
+  public int TextRotation => _styles.CellXfs[Index].TextRotation;
+
+  /// <summary>
+  /// If true the cell is locked for editing when the sheet is protected
+  /// <seealso cref="ExcelWorksheet.Protection"/>
+  /// </summary>
+  public bool Locked => _styles.CellXfs[Index].Locked;
+
+  /// <summary>
+  /// If true the formula is hidden when the sheet is protected.
+  /// <seealso cref="ExcelWorksheet.Protection"/>
+  /// </summary>
+  public bool Hidden => _styles.CellXfs[Index].Hidden;
+
+  /// <summary>
+  /// The index in the style collection
+  /// </summary>
+  public int XfId => _styles.CellXfs[Index].XfId;
+
+  internal int PositionID { get; set; }
+
+  internal ExcelStyles Styles { get; set; }
+
+  internal override string Id =>
+    Numberformat.Id
+        + "|"
+        + Font.Id
+        + "|"
+        + Fill.Id
+        + "|"
+        + Border.Id
+        + "|"
+        + VerticalAlignment
+        + "|"
+        + HorizontalAlignment
+        + "|"
+        + WrapText
+        + "|"
+        + ReadingOrder
+        + "|"
+        + XfId;
+}
diff --git a/AppsheetEpplus/Style/IStyle.cs b/AppsheetEpplus/Style/IStyle.cs
new file mode 100644
index 0000000..7aafb76
--- /dev/null
+++ b/AppsheetEpplus/Style/IStyle.cs
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		                Initial Release		        2009-10-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+internal interface IStyle {
+  void SetNewStyleId(string value);
+
+  ulong Id { get; }
+
+  ExcelStyle ExcelStyle { get; }
+}
diff --git a/AppsheetEpplus/Style/StyleBase.cs b/AppsheetEpplus/Style/StyleBase.cs
new file mode 100644
index 0000000..a9904ae
--- /dev/null
+++ b/AppsheetEpplus/Style/StyleBase.cs
@@ -0,0 +1,188 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		                Initial Release		        2009-10-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Border line style
+/// </summary>
+public enum ExcelBorderStyle {
+  None,
+  Hair,
+  Dotted,
+  DashDot,
+  Thin,
+  DashDotDot,
+  Dashed,
+  MediumDashDotDot,
+  MediumDashed,
+  MediumDashDot,
+  Thick,
+  Medium,
+  Double,
+}
+
+/// <summary>
+/// Horizontal text alignment
+/// </summary>
+public enum ExcelHorizontalAlignment {
+  General,
+  Left,
+  Center,
+  CenterContinuous,
+  Right,
+  Fill,
+  Distributed,
+  Justify,
+}
+
+/// <summary>
+/// Vertical text alignment
+/// </summary>
+public enum ExcelVerticalAlignment {
+  Top,
+  Center,
+  Bottom,
+  Distributed,
+  Justify,
+}
+
+/// <summary>
+/// Font-Vertical Align
+/// </summary>
+public enum ExcelVerticalAlignmentFont {
+  None,
+  Subscript,
+  Superscript,
+}
+
+/// <summary>
+/// Font-Underlinestyle for
+/// </summary>
+public enum ExcelUnderLineType {
+  None,
+  Single,
+  Double,
+  SingleAccounting,
+  DoubleAccounting,
+}
+
+/// <summary>
+/// Fill pattern
+/// </summary>
+public enum ExcelFillStyle {
+  None,
+  Solid,
+  DarkGray,
+  MediumGray,
+  LightGray,
+  Gray125,
+  Gray0625,
+  DarkVertical,
+  DarkHorizontal,
+  DarkDown,
+  DarkUp,
+  DarkGrid,
+  DarkTrellis,
+  LightVertical,
+  LightHorizontal,
+  LightDown,
+  LightUp,
+  LightGrid,
+  LightTrellis,
+}
+
+/// <summary>
+/// Type of gradient fill
+/// </summary>
+public enum ExcelFillGradientType {
+  /// <summary>
+  /// No gradient fill.
+  /// </summary>
+  None,
+
+  /// <summary>
+  /// This gradient fill is of linear gradient type. Linear gradient type means that the transition from one color to the next is along a line (e.g., horizontal, vertical,diagonal, etc.)
+  /// </summary>
+  Linear,
+
+  /// <summary>
+  /// This gradient fill is of path gradient type. Path gradient type means the that the boundary of transition from one color to the next is a rectangle, defined by top,bottom, left, and right attributes on the gradientFill element.
+  /// </summary>
+  Path,
+}
+
+/// <summary>
+/// The reading order
+/// </summary>
+public enum ExcelReadingOrder {
+  /// <summary>
+  /// Reading order is determined by scanning the text for the first non-whitespace character: if it is a strong right-to-left character, the reading order is right-to-left; otherwise, the reading order left-to-right.
+  /// </summary>
+  ContextDependent = 0,
+
+  /// <summary>
+  /// Left to Right
+  /// </summary>
+  LeftToRight = 1,
+
+  /// <summary>
+  /// Right to Left
+  /// </summary>
+  RightToLeft = 2,
+}
+
+public abstract class StyleBase {
+  protected ExcelStyles _styles;
+  internal XmlHelper.ChangedEventHandler _ChangedEvent;
+  protected int _positionID;
+  protected string _address;
+
+  internal StyleBase(
+      ExcelStyles styles,
+      XmlHelper.ChangedEventHandler changedEvent,
+      int positionId,
+      string address) {
+    _styles = styles;
+    _ChangedEvent = changedEvent;
+    _address = address;
+    _positionID = positionId;
+  }
+
+  internal int Index { get; set; }
+
+  internal abstract string Id { get; }
+
+  internal virtual void SetIndex(int index) {
+    Index = index;
+  }
+}
diff --git a/AppsheetEpplus/Style/StyleChangeEventArgs.cs b/AppsheetEpplus/Style/StyleChangeEventArgs.cs
new file mode 100644
index 0000000..340ef1f
--- /dev/null
+++ b/AppsheetEpplus/Style/StyleChangeEventArgs.cs
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		                Initial Release		        2009-10-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System;
+
+namespace AppsheetEpplus;
+
+internal enum eStyleClass {
+  Numberformat,
+  Font,
+  Border,
+  BorderTop,
+  BorderLeft,
+  BorderBottom,
+  BorderRight,
+  BorderDiagonal,
+  Fill,
+  GradientFill,
+  FillBackgroundColor,
+  FillPatternColor,
+  FillGradientColor1,
+  FillGradientColor2,
+  NamedStyle,
+  Style,
+}
+
+internal enum eStyleProperty {
+  Format,
+  Name,
+  Size,
+  Bold,
+  Italic,
+  Strike,
+  Color,
+  Tint,
+  IndexedColor,
+  AutoColor,
+  GradientColor,
+  Family,
+  Scheme,
+  UnderlineType,
+  HorizontalAlign,
+  VerticalAlign,
+  Border,
+  NamedStyle,
+  Style,
+  PatternType,
+  ReadingOrder,
+  WrapText,
+  TextRotation,
+  Locked,
+  Hidden,
+  ShrinkToFit,
+  BorderDiagonalUp,
+  BorderDiagonalDown,
+  GradientDegree,
+  GradientType,
+  GradientTop,
+  GradientBottom,
+  GradientLeft,
+  GradientRight,
+  XfId,
+  Indent,
+}
+
+internal class StyleChangeEventArgs : EventArgs {
+  internal StyleChangeEventArgs(
+      eStyleClass styleclass,
+      eStyleProperty styleProperty,
+      object value,
+      int positionId,
+      string address) {
+    StyleClass = styleclass;
+    StyleProperty = styleProperty;
+    Value = value;
+    Address = address;
+    PositionID = positionId;
+  }
+
+  internal eStyleClass StyleClass;
+  internal eStyleProperty StyleProperty;
+
+  //internal string PropertyName;
+  internal object Value;
+
+  internal int PositionID { get; set; }
+
+  //internal string Address;
+  internal string Address;
+}
diff --git a/AppsheetEpplus/Style/XmlAccess/ExcelBorderItemXml.cs b/AppsheetEpplus/Style/XmlAccess/ExcelBorderItemXml.cs
new file mode 100644
index 0000000..a68da66
--- /dev/null
+++ b/AppsheetEpplus/Style/XmlAccess/ExcelBorderItemXml.cs
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		                Initial Release		        2009-10-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System;
+using System.Globalization;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Xml access class for border items
+/// </summary>
+public sealed class ExcelBorderItemXml : StyleXmlHelper {
+  internal ExcelBorderItemXml(XmlNamespaceManager nameSpaceManager)
+      : base(nameSpaceManager) {
+    _borderStyle = ExcelBorderStyle.None;
+    _color = new(NameSpaceManager);
+  }
+
+  internal ExcelBorderItemXml(XmlNamespaceManager nsm, XmlNode topNode)
+      : base(nsm, topNode) {
+    if (topNode != null) {
+      _borderStyle = GetBorderStyle(GetXmlNodeString("@style"));
+      _color = new(nsm, topNode.SelectSingleNode(_colorPath, nsm));
+      Exists = true;
+    } else {
+      Exists = false;
+    }
+  }
+
+  private ExcelBorderStyle GetBorderStyle(string style) {
+    if (style == "") {
+      return ExcelBorderStyle.None;
+    }
+    return Enum.TryParse<ExcelBorderStyle>(style, true, out var result)
+        ? result
+        : ExcelBorderStyle.None;
+  }
+
+  private ExcelBorderStyle _borderStyle = ExcelBorderStyle.None;
+
+  /// <summary>
+  /// Cell Border style
+  /// </summary>
+  public ExcelBorderStyle Style {
+    get => _borderStyle;
+    set {
+      _borderStyle = value;
+      Exists = true;
+    }
+  }
+
+  private ExcelColorXml _color;
+  private const string _colorPath = "d:color";
+
+  /// <summary>
+  /// Border style
+  /// </summary>
+  public ExcelColorXml Color {
+    get => _color;
+    internal set => _color = value;
+  }
+
+  internal override string Id {
+    get {
+      if (Exists) {
+        return Style + Color.Id;
+      }
+      return "None";
+    }
+  }
+
+  internal ExcelBorderItemXml Copy() {
+    ExcelBorderItemXml borderItem = new ExcelBorderItemXml(NameSpaceManager);
+    borderItem.Style = _borderStyle;
+    borderItem.Color = _color.Copy();
+    return borderItem;
+  }
+
+  internal override XmlNode CreateXmlNode(XmlNode topNode) {
+    TopNode = topNode;
+
+    if (Style != ExcelBorderStyle.None) {
+      SetXmlNodeString("@style", SetBorderString(Style));
+      if (Color.Exists) {
+        CreateNode(_colorPath);
+        topNode.AppendChild(
+            Color.CreateXmlNode(TopNode.SelectSingleNode(_colorPath, NameSpaceManager)));
+      }
+    }
+    return TopNode;
+  }
+
+  private string SetBorderString(ExcelBorderStyle style) {
+    string newName = Enum.GetName(typeof(ExcelBorderStyle), style);
+    return newName.Substring(0, 1).ToLower(CultureInfo.InvariantCulture)
+        + newName.Substring(1, newName.Length - 1);
+  }
+
+  public bool Exists { get; private set; }
+}
diff --git a/AppsheetEpplus/Style/XmlAccess/ExcelBorderXml.cs b/AppsheetEpplus/Style/XmlAccess/ExcelBorderXml.cs
new file mode 100644
index 0000000..f905799
--- /dev/null
+++ b/AppsheetEpplus/Style/XmlAccess/ExcelBorderXml.cs
@@ -0,0 +1,171 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		                Initial Release		        2009-10-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Xml access class for border top level
+/// </summary>
+public sealed class ExcelBorderXml : StyleXmlHelper {
+  internal ExcelBorderXml(XmlNamespaceManager nameSpaceManager)
+      : base(nameSpaceManager) {}
+
+  internal ExcelBorderXml(XmlNamespaceManager nsm, XmlNode topNode)
+      : base(nsm, topNode) {
+    _left = new(nsm, topNode.SelectSingleNode(_leftPath, nsm));
+    _right = new(nsm, topNode.SelectSingleNode(_rightPath, nsm));
+    _top = new(nsm, topNode.SelectSingleNode(_topPath, nsm));
+    _bottom = new(nsm, topNode.SelectSingleNode(_bottomPath, nsm));
+    _diagonal = new(nsm, topNode.SelectSingleNode(_diagonalPath, nsm));
+    _diagonalUp = GetBoolValue(topNode, _diagonalUpPath);
+    _diagonalDown = GetBoolValue(topNode, _diagonalDownPath);
+  }
+
+  internal override string Id =>
+    Left.Id + Right.Id + Top.Id + Bottom.Id + Diagonal.Id + DiagonalUp + DiagonalDown;
+
+  private const string _leftPath = "d:left";
+  private ExcelBorderItemXml _left;
+
+  /// <summary>
+  /// Left border style properties
+  /// </summary>
+  public ExcelBorderItemXml Left {
+    get => _left;
+    internal set => _left = value;
+  }
+
+  private const string _rightPath = "d:right";
+  private ExcelBorderItemXml _right;
+
+  /// <summary>
+  /// Right border style properties
+  /// </summary>
+  public ExcelBorderItemXml Right {
+    get => _right;
+    internal set => _right = value;
+  }
+
+  private const string _topPath = "d:top";
+  private ExcelBorderItemXml _top;
+
+  /// <summary>
+  /// Top border style properties
+  /// </summary>
+  public ExcelBorderItemXml Top {
+    get => _top;
+    internal set => _top = value;
+  }
+
+  private const string _bottomPath = "d:bottom";
+  private ExcelBorderItemXml _bottom;
+
+  /// <summary>
+  /// Bottom border style properties
+  /// </summary>
+  public ExcelBorderItemXml Bottom {
+    get => _bottom;
+    internal set => _bottom = value;
+  }
+
+  private const string _diagonalPath = "d:diagonal";
+  private ExcelBorderItemXml _diagonal;
+
+  /// <summary>
+  /// Diagonal border style properties
+  /// </summary>
+  public ExcelBorderItemXml Diagonal {
+    get => _diagonal;
+    internal set => _diagonal = value;
+  }
+
+  private const string _diagonalUpPath = "@diagonalUp";
+  private bool _diagonalUp;
+
+  /// <summary>
+  /// Diagonal up border
+  /// </summary>
+  public bool DiagonalUp {
+    get => _diagonalUp;
+    internal set => _diagonalUp = value;
+  }
+
+  private const string _diagonalDownPath = "@diagonalDown";
+  private bool _diagonalDown;
+
+  /// <summary>
+  /// Diagonal down border
+  /// </summary>
+  public bool DiagonalDown {
+    get => _diagonalDown;
+    internal set => _diagonalDown = value;
+  }
+
+  internal ExcelBorderXml Copy() {
+    ExcelBorderXml newBorder = new ExcelBorderXml(NameSpaceManager);
+    newBorder.Bottom = _bottom.Copy();
+    newBorder.Diagonal = _diagonal.Copy();
+    newBorder.Left = _left.Copy();
+    newBorder.Right = _right.Copy();
+    newBorder.Top = _top.Copy();
+    newBorder.DiagonalUp = _diagonalUp;
+    newBorder.DiagonalDown = _diagonalDown;
+
+    return newBorder;
+  }
+
+  internal override XmlNode CreateXmlNode(XmlNode topNode) {
+    TopNode = topNode;
+    CreateNode(_leftPath);
+    topNode.AppendChild(_left.CreateXmlNode(TopNode.SelectSingleNode(_leftPath, NameSpaceManager)));
+    CreateNode(_rightPath);
+    topNode.AppendChild(
+        _right.CreateXmlNode(TopNode.SelectSingleNode(_rightPath, NameSpaceManager)));
+    CreateNode(_topPath);
+    topNode.AppendChild(_top.CreateXmlNode(TopNode.SelectSingleNode(_topPath, NameSpaceManager)));
+    CreateNode(_bottomPath);
+    topNode.AppendChild(
+        _bottom.CreateXmlNode(TopNode.SelectSingleNode(_bottomPath, NameSpaceManager)));
+    CreateNode(_diagonalPath);
+    topNode.AppendChild(
+        _diagonal.CreateXmlNode(TopNode.SelectSingleNode(_diagonalPath, NameSpaceManager)));
+    if (_diagonalUp) {
+      SetXmlNodeString(_diagonalUpPath, "1");
+    }
+    if (_diagonalDown) {
+      SetXmlNodeString(_diagonalDownPath, "1");
+    }
+    return topNode;
+  }
+}
diff --git a/AppsheetEpplus/Style/XmlAccess/ExcelColorXml.cs b/AppsheetEpplus/Style/XmlAccess/ExcelColorXml.cs
new file mode 100644
index 0000000..d1a3792
--- /dev/null
+++ b/AppsheetEpplus/Style/XmlAccess/ExcelColorXml.cs
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		                Initial Release		        2009-10-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System;
+using System.Globalization;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Xml access class for color
+/// </summary>
+public sealed class ExcelColorXml : StyleXmlHelper {
+  internal ExcelColorXml(XmlNamespaceManager nameSpaceManager)
+      : base(nameSpaceManager) {
+    _auto = false;
+    _theme = "";
+    _tint = 0;
+    _rgb = "";
+    _indexed = int.MinValue;
+  }
+
+  internal ExcelColorXml(XmlNamespaceManager nsm, XmlNode topNode)
+      : base(nsm, topNode) {
+    if (topNode == null) {
+      _exists = false;
+    } else {
+      _exists = true;
+      _auto = GetXmlNodeBool("@auto");
+      _theme = GetXmlNodeString("@theme");
+      _tint = GetXmlNodeDecimalNull("@tint") ?? decimal.MinValue;
+      _rgb = GetXmlNodeString("@rgb");
+      _indexed = GetXmlNodeIntNull("@indexed") ?? int.MinValue;
+    }
+  }
+
+  internal override string Id => _auto + "|" + _theme + "|" + _tint + "|" + _rgb + "|" + _indexed;
+
+  private bool _auto;
+
+  public bool Auto {
+    get => _auto;
+    set {
+      _auto = value;
+      _exists = true;
+      Clear();
+    }
+  }
+
+  private string _theme;
+
+  /// <summary>
+  /// Theme color value
+  /// </summary>
+  public string Theme => _theme;
+
+  private decimal _tint;
+
+  /// <summary>
+  /// Tint
+  /// </summary>
+  public decimal Tint {
+    get {
+      if (_tint == decimal.MinValue) {
+        return 0;
+      }
+      return _tint;
+    }
+    set {
+      _tint = value;
+      _exists = true;
+    }
+  }
+
+  private string _rgb;
+
+  /// <summary>
+  /// RGB value
+  /// </summary>
+  public string Rgb {
+    get => _rgb;
+    set {
+      _rgb = value;
+      _exists = true;
+      _indexed = int.MinValue;
+      _auto = false;
+    }
+  }
+
+  private int _indexed;
+
+  /// <summary>
+  /// Indexed color value
+  /// </summary>
+  public int Indexed {
+    get => (_indexed == int.MinValue ? 0 : _indexed);
+    set {
+      if (value < 0 || value > 65) {
+        throw (new ArgumentOutOfRangeException("Index out of range"));
+      }
+      Clear();
+      _indexed = value;
+      _exists = true;
+    }
+  }
+
+  internal void Clear() {
+    _theme = "";
+    _tint = decimal.MinValue;
+    _indexed = int.MinValue;
+    _rgb = "";
+    _auto = false;
+  }
+
+  internal ExcelColorXml Copy() {
+    return new(NameSpaceManager) {
+      _indexed = _indexed,
+      _tint = _tint,
+      _rgb = _rgb,
+      _theme = _theme,
+      _auto = _auto,
+      _exists = _exists,
+    };
+  }
+
+  internal override XmlNode CreateXmlNode(XmlNode topNode) {
+    TopNode = topNode;
+    if (_rgb != "") {
+      SetXmlNodeString("@rgb", _rgb);
+    } else if (_indexed >= 0) {
+      SetXmlNodeString("@indexed", _indexed.ToString());
+    } else if (_auto) {
+      SetXmlNodeBool("@auto", _auto);
+    } else {
+      SetXmlNodeString("@theme", _theme);
+    }
+    if (_tint != decimal.MinValue) {
+      SetXmlNodeString("@tint", _tint.ToString(CultureInfo.InvariantCulture));
+    }
+    return TopNode;
+  }
+
+  private bool _exists;
+
+  internal bool Exists => _exists;
+}
diff --git a/AppsheetEpplus/Style/XmlAccess/ExcelFillXml.cs b/AppsheetEpplus/Style/XmlAccess/ExcelFillXml.cs
new file mode 100644
index 0000000..5a00bcd
--- /dev/null
+++ b/AppsheetEpplus/Style/XmlAccess/ExcelFillXml.cs
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		                Initial Release		        2009-10-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System;
+using System.Globalization;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Xml access class for fills
+/// </summary>
+public class ExcelFillXml : StyleXmlHelper {
+  internal ExcelFillXml(XmlNamespaceManager nameSpaceManager)
+      : base(nameSpaceManager) {
+    _fillPatternType = ExcelFillStyle.None;
+    _backgroundColor = new(NameSpaceManager);
+    _patternColor = new(NameSpaceManager);
+  }
+
+  internal ExcelFillXml(XmlNamespaceManager nsm, XmlNode topNode)
+      : base(nsm, topNode) {
+    PatternType = GetPatternType(GetXmlNodeString(_fillPatternTypePath));
+    _backgroundColor = new(nsm, topNode.SelectSingleNode(_backgroundColorPath, nsm));
+    _patternColor = new(nsm, topNode.SelectSingleNode(_patternColorPath, nsm));
+  }
+
+  private ExcelFillStyle GetPatternType(string patternType) {
+    return Enum.TryParse<ExcelFillStyle>(patternType, true, out var result)
+        ? result
+        : ExcelFillStyle.None;
+  }
+
+  internal override string Id => PatternType + PatternColor.Id + BackgroundColor.Id;
+
+  private const string _fillPatternTypePath = "d:patternFill/@patternType";
+  protected ExcelFillStyle _fillPatternType;
+
+  /// <summary>
+  /// Cell fill pattern style
+  /// </summary>
+  public ExcelFillStyle PatternType {
+    get => _fillPatternType;
+    set => _fillPatternType = value;
+  }
+
+  protected ExcelColorXml _patternColor;
+  private const string _patternColorPath = "d:patternFill/d:bgColor";
+
+  /// <summary>
+  /// Pattern color
+  /// </summary>
+  public ExcelColorXml PatternColor {
+    get => _patternColor;
+    internal set => _patternColor = value;
+  }
+
+  protected ExcelColorXml _backgroundColor;
+  private const string _backgroundColorPath = "d:patternFill/d:fgColor";
+
+  /// <summary>
+  /// Cell background color
+  /// </summary>
+  public ExcelColorXml BackgroundColor {
+    get => _backgroundColor;
+    internal set => _backgroundColor = value;
+  }
+
+  internal virtual ExcelFillXml Copy() {
+    ExcelFillXml newFill = new ExcelFillXml(NameSpaceManager);
+    newFill.PatternType = _fillPatternType;
+    newFill.BackgroundColor = _backgroundColor.Copy();
+    newFill.PatternColor = _patternColor.Copy();
+    return newFill;
+  }
+
+  internal override XmlNode CreateXmlNode(XmlNode topNode) {
+    TopNode = topNode;
+    SetXmlNodeString(_fillPatternTypePath, SetPatternString(_fillPatternType));
+    if (PatternType != ExcelFillStyle.None) {
+      XmlNode pattern = topNode.SelectSingleNode(_fillPatternTypePath, NameSpaceManager);
+      if (BackgroundColor.Exists) {
+        CreateNode(_backgroundColorPath);
+        BackgroundColor.CreateXmlNode(
+            topNode.SelectSingleNode(_backgroundColorPath, NameSpaceManager));
+        if (PatternColor.Exists) {
+          CreateNode(_patternColorPath);
+          //topNode.AppendChild(PatternColor.CreateXmlNode(topNode.SelectSingleNode(_patternColorPath, NameSpaceManager)));
+          PatternColor.CreateXmlNode(topNode.SelectSingleNode(_patternColorPath, NameSpaceManager));
+        }
+      }
+    }
+    return topNode;
+  }
+
+  private string SetPatternString(ExcelFillStyle pattern) {
+    string newName = Enum.GetName(typeof(ExcelFillStyle), pattern);
+    return newName.Substring(0, 1).ToLower(CultureInfo.InvariantCulture)
+        + newName.Substring(1, newName.Length - 1);
+  }
+}
diff --git a/AppsheetEpplus/Style/XmlAccess/ExcelFontXml.cs b/AppsheetEpplus/Style/XmlAccess/ExcelFontXml.cs
new file mode 100644
index 0000000..ef66ee9
--- /dev/null
+++ b/AppsheetEpplus/Style/XmlAccess/ExcelFontXml.cs
@@ -0,0 +1,294 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		                Initial Release		        2009-10-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System;
+using System.Globalization;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Xml access class for fonts
+/// </summary>
+public sealed class ExcelFontXml : StyleXmlHelper {
+  internal ExcelFontXml(XmlNamespaceManager nameSpaceManager)
+      : base(nameSpaceManager) {
+    _name = "";
+    _size = 0;
+    _family = int.MinValue;
+    _scheme = "";
+    _color = _color = new(NameSpaceManager);
+    _bold = false;
+    _italic = false;
+    _strike = false;
+    _underlineType = ExcelUnderLineType.None;
+    _verticalAlign = "";
+  }
+
+  internal ExcelFontXml(XmlNamespaceManager nsm, XmlNode topNode)
+      : base(nsm, topNode) {
+    _name = GetXmlNodeString(_namePath);
+    _size = (float)GetXmlNodeDecimal(_sizePath);
+    _family = GetXmlNodeIntNull(_familyPath) ?? int.MinValue;
+    _scheme = GetXmlNodeString(_schemePath);
+    _color = new(nsm, topNode.SelectSingleNode(_colorPath, nsm));
+    _bold = GetBoolValue(topNode, _boldPath);
+    _italic = GetBoolValue(topNode, _italicPath);
+    _strike = GetBoolValue(topNode, _strikePath);
+    _verticalAlign = GetXmlNodeString(_verticalAlignPath);
+    if (topNode.SelectSingleNode(_underLinedPath, NameSpaceManager) != null) {
+      string ut = GetXmlNodeString(_underLinedPath + "/@val");
+      if (ut == "") {
+        _underlineType = ExcelUnderLineType.Single;
+      } else {
+        if (!Enum.TryParse(ut, true, out _underlineType)) {
+          _underlineType = ExcelUnderLineType.Single;
+        }
+      }
+    } else {
+      _underlineType = ExcelUnderLineType.None;
+    }
+  }
+
+  internal override string Id =>
+    Name
+        + "|"
+        + Size
+        + "|"
+        + Family
+        + "|"
+        + Color.Id
+        + "|"
+        + Scheme
+        + "|"
+        + Bold
+        + "|"
+        + Italic
+        + "|"
+        + Strike
+        + "|"
+        + VerticalAlign
+        + "|"
+        + UnderLineType;
+
+  private const string _namePath = "d:name/@val";
+  private string _name;
+
+  /// <summary>
+  /// The name of the font
+  /// </summary>
+  public string Name {
+    get => _name;
+    set {
+      Scheme = ""; //Reset schema to avoid corrupt file if unsupported font is selected.
+      _name = value;
+    }
+  }
+
+  private const string _sizePath = "d:sz/@val";
+  private float _size;
+
+  /// <summary>
+  /// Font size
+  /// </summary>
+  public float Size {
+    get => _size;
+    set => _size = value;
+  }
+
+  private const string _familyPath = "d:family/@val";
+  private int _family;
+
+  /// <summary>
+  /// Font family
+  /// </summary>
+  public int Family {
+    get => (_family == int.MinValue ? 0 : _family);
+    set => _family = value;
+  }
+
+  private ExcelColorXml _color;
+  private const string _colorPath = "d:color";
+
+  /// <summary>
+  /// Text color
+  /// </summary>
+  public ExcelColorXml Color {
+    get => _color;
+    internal set => _color = value;
+  }
+
+  private const string _schemePath = "d:scheme/@val";
+  private string _scheme = "";
+
+  /// <summary>
+  /// Font Scheme
+  /// </summary>
+  public string Scheme {
+    get => _scheme;
+    private set => _scheme = value;
+  }
+
+  private const string _boldPath = "d:b";
+  private bool _bold;
+
+  /// <summary>
+  /// If the font is bold
+  /// </summary>
+  public bool Bold {
+    get => _bold;
+    set => _bold = value;
+  }
+
+  private const string _italicPath = "d:i";
+  private bool _italic;
+
+  /// <summary>
+  /// If the font is italic
+  /// </summary>
+  public bool Italic {
+    get => _italic;
+    set => _italic = value;
+  }
+
+  private const string _strikePath = "d:strike";
+  private bool _strike;
+
+  /// <summary>
+  /// If the font is striked out
+  /// </summary>
+  public bool Strike {
+    get => _strike;
+    set => _strike = value;
+  }
+
+  private const string _underLinedPath = "d:u";
+
+  /// <summary>
+  /// If the font is underlined.
+  /// When set to true a the text is underlined with a single line
+  /// </summary>
+  public bool UnderLine {
+    get => UnderLineType != ExcelUnderLineType.None;
+    set => _underlineType = value ? ExcelUnderLineType.Single : ExcelUnderLineType.None;
+  }
+
+  private ExcelUnderLineType _underlineType;
+
+  /// <summary>
+  /// If the font is underlined
+  /// </summary>
+  public ExcelUnderLineType UnderLineType {
+    get => _underlineType;
+    set => _underlineType = value;
+  }
+
+  private const string _verticalAlignPath = "d:vertAlign/@val";
+  private string _verticalAlign;
+
+  /// <summary>
+  /// Vertical aligned
+  /// </summary>
+  public string VerticalAlign {
+    get => _verticalAlign;
+    set => _verticalAlign = value;
+  }
+
+  internal ExcelFontXml Copy() {
+    ExcelFontXml newFont = new ExcelFontXml(NameSpaceManager);
+    newFont.Name = _name;
+    newFont.Size = _size;
+    newFont.Family = _family;
+    newFont.Scheme = _scheme;
+    newFont.Bold = _bold;
+    newFont.Italic = _italic;
+    newFont.UnderLineType = _underlineType;
+    newFont.Strike = _strike;
+    newFont.VerticalAlign = _verticalAlign;
+    newFont.Color = Color.Copy();
+    return newFont;
+  }
+
+  internal override XmlNode CreateXmlNode(XmlNode topElement) {
+    TopNode = topElement;
+
+    if (_bold) {
+      CreateNode(_boldPath);
+    } else {
+      DeleteAllNode(_boldPath);
+    }
+    if (_italic) {
+      CreateNode(_italicPath);
+    } else {
+      DeleteAllNode(_italicPath);
+    }
+    if (_strike) {
+      CreateNode(_strikePath);
+    } else {
+      DeleteAllNode(_strikePath);
+    }
+
+    if (_underlineType == ExcelUnderLineType.None) {
+      DeleteAllNode(_underLinedPath);
+    } else if (_underlineType == ExcelUnderLineType.Single) {
+      CreateNode(_underLinedPath);
+    } else {
+      var v = _underlineType.ToString();
+      SetXmlNodeString(
+          _underLinedPath + "/@val",
+          v.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + v.Substring(1));
+    }
+
+    if (_verticalAlign != "") {
+      SetXmlNodeString(_verticalAlignPath, _verticalAlign);
+    }
+    if (_size > 0) {
+      SetXmlNodeString(_sizePath, _size.ToString(CultureInfo.InvariantCulture));
+    }
+    if (_color.Exists) {
+      CreateNode(_colorPath);
+      TopNode.AppendChild(
+          _color.CreateXmlNode(TopNode.SelectSingleNode(_colorPath, NameSpaceManager)));
+    }
+    if (!string.IsNullOrEmpty(_name)) {
+      SetXmlNodeString(_namePath, _name);
+    }
+    if (_family > int.MinValue) {
+      SetXmlNodeString(_familyPath, _family.ToString());
+    }
+    if (_scheme != "") {
+      SetXmlNodeString(_schemePath, _scheme);
+    }
+
+    return TopNode;
+  }
+}
diff --git a/AppsheetEpplus/Style/XmlAccess/ExcelGradientFillXml.cs b/AppsheetEpplus/Style/XmlAccess/ExcelGradientFillXml.cs
new file mode 100644
index 0000000..fb4a173
--- /dev/null
+++ b/AppsheetEpplus/Style/XmlAccess/ExcelGradientFillXml.cs
@@ -0,0 +1,184 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		                Initial Release		        2009-10-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System.Globalization;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Xml access class for gradient fillsde
+/// </summary>
+public sealed class ExcelGradientFillXml : ExcelFillXml {
+  internal ExcelGradientFillXml(XmlNamespaceManager nameSpaceManager)
+      : base(nameSpaceManager) {
+    GradientColor1 = new(nameSpaceManager);
+    GradientColor2 = new(nameSpaceManager);
+  }
+
+  internal ExcelGradientFillXml(XmlNamespaceManager nsm, XmlNode topNode)
+      : base(nsm, topNode) {
+    Degree = GetXmlNodeDouble(_degreePath);
+    Type =
+        GetXmlNodeString(_typePath) == "path"
+            ? ExcelFillGradientType.Path
+            : ExcelFillGradientType.Linear;
+    GradientColor1 = new(nsm, topNode.SelectSingleNode(_gradientColor1Path, nsm));
+    GradientColor2 = new(nsm, topNode.SelectSingleNode(_gradientColor2Path, nsm));
+
+    Top = GetXmlNodeDouble(_topPath);
+    Bottom = GetXmlNodeDouble(_bottomPath);
+    Left = GetXmlNodeDouble(_leftPath);
+    Right = GetXmlNodeDouble(_rightPath);
+  }
+
+  private const string _typePath = "d:gradientFill/@type";
+
+  /// <summary>
+  /// Type of gradient fill.
+  /// </summary>
+  public ExcelFillGradientType Type { get; internal set; }
+
+  private const string _degreePath = "d:gradientFill/@degree";
+
+  /// <summary>
+  /// Angle of the linear gradient
+  /// </summary>
+  public double Degree { get; internal set; }
+
+  private const string _gradientColor1Path = "d:gradientFill/d:stop[@position=\"0\"]/d:color";
+
+  /// <summary>
+  /// Gradient color 1
+  /// </summary>
+  public ExcelColorXml GradientColor1 { get; private set; }
+
+  private const string _gradientColor2Path = "d:gradientFill/d:stop[@position=\"1\"]/d:color";
+
+  /// <summary>
+  /// Gradient color 2
+  /// </summary>
+  public ExcelColorXml GradientColor2 { get; private set; }
+
+  private const string _bottomPath = "d:gradientFill/@bottom";
+
+  /// <summary>
+  /// Percentage format bottom
+  /// </summary>
+  public double Bottom { get; internal set; }
+
+  private const string _topPath = "d:gradientFill/@top";
+
+  /// <summary>
+  /// Percentage format top
+  /// </summary>
+  public double Top { get; internal set; }
+
+  private const string _leftPath = "d:gradientFill/@left";
+
+  /// <summary>
+  /// Percentage format left
+  /// </summary>
+  public double Left { get; internal set; }
+
+  private const string _rightPath = "d:gradientFill/@right";
+
+  /// <summary>
+  /// Percentage format right
+  /// </summary>
+  public double Right { get; internal set; }
+
+  internal override string Id =>
+    base.Id + Degree + GradientColor1.Id + GradientColor2.Id + Type + Left + Right + Bottom + Top;
+
+  internal override ExcelFillXml Copy() {
+    ExcelGradientFillXml newFill = new ExcelGradientFillXml(NameSpaceManager);
+    newFill.PatternType = _fillPatternType;
+    newFill.BackgroundColor = _backgroundColor.Copy();
+    newFill.PatternColor = _patternColor.Copy();
+
+    newFill.GradientColor1 = GradientColor1.Copy();
+    newFill.GradientColor2 = GradientColor2.Copy();
+    newFill.Type = Type;
+    newFill.Degree = Degree;
+    newFill.Top = Top;
+    newFill.Bottom = Bottom;
+    newFill.Left = Left;
+    newFill.Right = Right;
+
+    return newFill;
+  }
+
+  internal override XmlNode CreateXmlNode(XmlNode topNode) {
+    TopNode = topNode;
+    CreateNode("d:gradientFill");
+    if (Type == ExcelFillGradientType.Path) {
+      SetXmlNodeString(_typePath, "path");
+    }
+    if (!double.IsNaN(Degree)) {
+      SetXmlNodeString(_degreePath, Degree.ToString(CultureInfo.InvariantCulture));
+    }
+    if (GradientColor1 != null) {
+      /*** Gradient color node 1***/
+      var node = TopNode.SelectSingleNode("d:gradientFill", NameSpaceManager);
+      var stopNode = node.OwnerDocument.CreateElement("stop", ExcelPackage._schemaMain);
+      stopNode.SetAttribute("position", "0");
+      node.AppendChild(stopNode);
+      var colorNode = node.OwnerDocument.CreateElement("color", ExcelPackage._schemaMain);
+      stopNode.AppendChild(colorNode);
+      GradientColor1.CreateXmlNode(colorNode);
+
+      /*** Gradient color node 2***/
+      stopNode = node.OwnerDocument.CreateElement("stop", ExcelPackage._schemaMain);
+      stopNode.SetAttribute("position", "1");
+      node.AppendChild(stopNode);
+      colorNode = node.OwnerDocument.CreateElement("color", ExcelPackage._schemaMain);
+      stopNode.AppendChild(colorNode);
+
+      GradientColor2.CreateXmlNode(colorNode);
+    }
+    if (!double.IsNaN(Top)) {
+      SetXmlNodeString(_topPath, Top.ToString("F5", CultureInfo.InvariantCulture));
+    }
+    if (!double.IsNaN(Bottom)) {
+      SetXmlNodeString(_bottomPath, Bottom.ToString("F5", CultureInfo.InvariantCulture));
+    }
+    if (!double.IsNaN(Left)) {
+      SetXmlNodeString(_leftPath, Left.ToString("F5", CultureInfo.InvariantCulture));
+    }
+    if (!double.IsNaN(Right)) {
+      SetXmlNodeString(_rightPath, Right.ToString("F5", CultureInfo.InvariantCulture));
+    }
+
+    return topNode;
+  }
+}
diff --git a/AppsheetEpplus/Style/XmlAccess/ExcelNamedStyleXml.cs b/AppsheetEpplus/Style/XmlAccess/ExcelNamedStyleXml.cs
new file mode 100644
index 0000000..8039ebd
--- /dev/null
+++ b/AppsheetEpplus/Style/XmlAccess/ExcelNamedStyleXml.cs
@@ -0,0 +1,127 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		                Initial Release		        2009-10-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Xml access class for named styles
+/// </summary>
+public sealed class ExcelNamedStyleXml : StyleXmlHelper {
+  private readonly ExcelStyles _styles;
+
+  internal ExcelNamedStyleXml(XmlNamespaceManager nameSpaceManager, ExcelStyles styles)
+      : base(nameSpaceManager) {
+    _styles = styles;
+    BuildInId = int.MinValue;
+  }
+
+  internal ExcelNamedStyleXml(
+      XmlNamespaceManager nameSpaceManager,
+      XmlNode topNode,
+      ExcelStyles styles)
+      : base(nameSpaceManager, topNode) {
+    StyleXfId = GetXmlNodeInt(_idPath);
+    Name = GetXmlNodeString(_namePath);
+    BuildInId = GetXmlNodeInt(_buildInIdPath);
+    CustomBuildin = GetXmlNodeBool(_customBuiltinPath);
+
+    _styles = styles;
+    _style = new(styles, styles.NamedStylePropertyChange, -1, Name, _styleXfId);
+  }
+
+  internal override string Id => Name;
+
+  private int _styleXfId;
+  private const string _idPath = "@xfId";
+
+  /// <summary>
+  /// Named style index
+  /// </summary>
+  public int StyleXfId {
+    get => _styleXfId;
+    set => _styleXfId = value;
+  }
+
+  private int _xfId = int.MinValue;
+
+  /// <summary>
+  /// Style index
+  /// </summary>
+  internal int XfId {
+    get => _xfId;
+    set => _xfId = value;
+  }
+
+  private const string _buildInIdPath = "@builtinId";
+
+  public int BuildInId { get; set; }
+
+  private const string _customBuiltinPath = "@customBuiltin";
+
+  public bool CustomBuildin { get; set; }
+
+  private const string _namePath = "@name";
+  private string _name;
+
+  /// <summary>
+  /// Name of the style
+  /// </summary>
+  public string Name {
+    get => _name;
+    internal set => _name = value;
+  }
+
+  private ExcelStyle _style;
+
+  /// <summary>
+  /// The style object
+  /// </summary>
+  public ExcelStyle Style {
+    get => _style;
+    internal set => _style = value;
+  }
+
+  internal override XmlNode CreateXmlNode(XmlNode topNode) {
+    TopNode = topNode;
+    SetXmlNodeString(_namePath, _name);
+    SetXmlNodeString("@xfId", _styles.CellStyleXfs[StyleXfId].newID.ToString());
+    if (BuildInId >= 0) {
+      SetXmlNodeString("@builtinId", BuildInId.ToString());
+    }
+    if (CustomBuildin) {
+      SetXmlNodeBool(_customBuiltinPath, true);
+    }
+    return TopNode;
+  }
+}
diff --git a/AppsheetEpplus/Style/XmlAccess/ExcelNumberFormatXml.cs b/AppsheetEpplus/Style/XmlAccess/ExcelNumberFormatXml.cs
new file mode 100644
index 0000000..7bcbf32
--- /dev/null
+++ b/AppsheetEpplus/Style/XmlAccess/ExcelNumberFormatXml.cs
@@ -0,0 +1,696 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		                Initial Release		        2009-10-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Xml access class for number formats
+/// </summary>
+public sealed class ExcelNumberFormatXml : StyleXmlHelper {
+  internal ExcelNumberFormatXml(XmlNamespaceManager nameSpaceManager)
+      : base(nameSpaceManager) {}
+
+  internal ExcelNumberFormatXml(XmlNamespaceManager nameSpaceManager, bool buildIn)
+      : base(nameSpaceManager) {
+    BuildIn = buildIn;
+  }
+
+  internal ExcelNumberFormatXml(XmlNamespaceManager nsm, XmlNode topNode)
+      : base(nsm, topNode) {
+    _numFmtId = GetXmlNodeInt("@numFmtId");
+    _format = GetXmlNodeString("@formatCode");
+  }
+
+  public bool BuildIn { get; private set; }
+
+  private int _numFmtId;
+
+  //        const string idPath = "@numFmtId";
+  /// <summary>
+  /// Id for number format
+  ///
+  /// Build in ID's
+  ///
+  /// 0   General
+  /// 1   0
+  /// 2   0.00
+  /// 3   #,##0
+  /// 4   #,##0.00
+  /// 9   0%
+  /// 10  0.00%
+  /// 11  0.00E+00
+  /// 12  # ?/?
+  /// 13  # ??/??
+  /// 14  mm-dd-yy
+  /// 15  d-mmm-yy
+  /// 16  d-mmm
+  /// 17  mmm-yy
+  /// 18  h:mm AM/PM
+  /// 19  h:mm:ss AM/PM
+  /// 20  h:mm
+  /// 21  h:mm:ss
+  /// 22  m/d/yy h:mm
+  /// 37  #,##0 ;(#,##0)
+  /// 38  #,##0 ;[Red](#,##0)
+  /// 39  #,##0.00;(#,##0.00)
+  /// 40  #,##0.00;[Red](#,##0.00)
+  /// 45  mm:ss
+  /// 46  [h]:mm:ss
+  /// 47  mmss.0
+  /// 48  ##0.0E+0
+  /// 49  @
+  /// </summary>
+  public int NumFmtId {
+    get => _numFmtId;
+    set => _numFmtId = value;
+  }
+
+  internal override string Id => _format;
+
+  private string _format = string.Empty;
+
+  public string Format {
+    get => _format;
+    set {
+      _numFmtId = ExcelNumberFormat.GetFromBuildIdFromFormat(value);
+      _format = value;
+    }
+  }
+
+  internal string GetNewId(int numFmtId, string format) {
+    if (numFmtId < 0) {
+      numFmtId = ExcelNumberFormat.GetFromBuildIdFromFormat(format);
+    }
+    return numFmtId.ToString();
+  }
+
+  internal static void AddBuildIn(
+      XmlNamespaceManager nameSpaceManager,
+      ExcelStyleCollection<ExcelNumberFormatXml> numberFormats) {
+    numberFormats.Add(
+        "General",
+        new(nameSpaceManager, true) {
+          NumFmtId = 0,
+          Format = "General",
+        });
+    numberFormats.Add(
+        "0",
+        new(nameSpaceManager, true) {
+          NumFmtId = 1,
+          Format = "0",
+        });
+    numberFormats.Add(
+        "0.00",
+        new(nameSpaceManager, true) {
+          NumFmtId = 2,
+          Format = "0.00",
+        });
+    numberFormats.Add(
+        "#,##0",
+        new(nameSpaceManager, true) {
+          NumFmtId = 3,
+          Format = "#,##0",
+        });
+    numberFormats.Add(
+        "#,##0.00",
+        new(nameSpaceManager, true) {
+          NumFmtId = 4,
+          Format = "#,##0.00",
+        });
+    numberFormats.Add(
+        "0%",
+        new(nameSpaceManager, true) {
+          NumFmtId = 9,
+          Format = "0%",
+        });
+    numberFormats.Add(
+        "0.00%",
+        new(nameSpaceManager, true) {
+          NumFmtId = 10,
+          Format = "0.00%",
+        });
+    numberFormats.Add(
+        "0.00E+00",
+        new(nameSpaceManager, true) {
+          NumFmtId = 11,
+          Format = "0.00E+00",
+        });
+    numberFormats.Add(
+        "# ?/?",
+        new(nameSpaceManager, true) {
+          NumFmtId = 12,
+          Format = "# ?/?",
+        });
+    numberFormats.Add(
+        "# ??/??",
+        new(nameSpaceManager, true) {
+          NumFmtId = 13,
+          Format = "# ??/??",
+        });
+    numberFormats.Add(
+        "mm-dd-yy",
+        new(nameSpaceManager, true) {
+          NumFmtId = 14,
+          Format = "mm-dd-yy",
+        });
+    numberFormats.Add(
+        "d-mmm-yy",
+        new(nameSpaceManager, true) {
+          NumFmtId = 15,
+          Format = "d-mmm-yy",
+        });
+    numberFormats.Add(
+        "d-mmm",
+        new(nameSpaceManager, true) {
+          NumFmtId = 16,
+          Format = "d-mmm",
+        });
+    numberFormats.Add(
+        "mmm-yy",
+        new(nameSpaceManager, true) {
+          NumFmtId = 17,
+          Format = "mmm-yy",
+        });
+    numberFormats.Add(
+        "h:mm AM/PM",
+        new(nameSpaceManager, true) {
+          NumFmtId = 18,
+          Format = "h:mm AM/PM",
+        });
+    numberFormats.Add(
+        "h:mm:ss AM/PM",
+        new(nameSpaceManager, true) {
+          NumFmtId = 19,
+          Format = "h:mm:ss AM/PM",
+        });
+    numberFormats.Add(
+        "h:mm",
+        new(nameSpaceManager, true) {
+          NumFmtId = 20,
+          Format = "h:mm",
+        });
+    numberFormats.Add(
+        "h:mm:ss",
+        new(nameSpaceManager, true) {
+          NumFmtId = 21,
+          Format = "h:mm:ss",
+        });
+    numberFormats.Add(
+        "m/d/yy h:mm",
+        new(nameSpaceManager, true) {
+          NumFmtId = 22,
+          Format = "m/d/yy h:mm",
+        });
+    numberFormats.Add(
+        "#,##0 ;(#,##0)",
+        new(nameSpaceManager, true) {
+          NumFmtId = 37,
+          Format = "#,##0 ;(#,##0)",
+        });
+    numberFormats.Add(
+        "#,##0 ;[Red](#,##0)",
+        new(nameSpaceManager, true) {
+          NumFmtId = 38,
+          Format = "#,##0 ;[Red](#,##0)",
+        });
+    numberFormats.Add(
+        "#,##0.00;(#,##0.00)",
+        new(nameSpaceManager, true) {
+          NumFmtId = 39,
+          Format = "#,##0.00;(#,##0.00)",
+        });
+    numberFormats.Add(
+        "#,##0.00;[Red](#,##0.00)",
+        new(nameSpaceManager, true) {
+          NumFmtId = 40,
+          Format = "#,##0.00;[Red](#,#)",
+        });
+    numberFormats.Add(
+        "mm:ss",
+        new(nameSpaceManager, true) {
+          NumFmtId = 45,
+          Format = "mm:ss",
+        });
+    numberFormats.Add(
+        "[h]:mm:ss",
+        new(nameSpaceManager, true) {
+          NumFmtId = 46,
+          Format = "[h]:mm:ss",
+        });
+    numberFormats.Add(
+        "mmss.0",
+        new(nameSpaceManager, true) {
+          NumFmtId = 47,
+          Format = "mmss.0",
+        });
+    numberFormats.Add(
+        "##0.0",
+        new(nameSpaceManager, true) {
+          NumFmtId = 48,
+          Format = "##0.0",
+        });
+    numberFormats.Add(
+        "@",
+        new(nameSpaceManager, true) {
+          NumFmtId = 49,
+          Format = "@",
+        });
+
+    numberFormats.NextId = 164; //Start for custom formats.
+  }
+
+  internal override XmlNode CreateXmlNode(XmlNode topNode) {
+    TopNode = topNode;
+    SetXmlNodeString("@numFmtId", NumFmtId.ToString());
+    SetXmlNodeString("@formatCode", Format);
+    return TopNode;
+  }
+
+  internal enum eFormatType {
+    Unknown = 0,
+    Number = 1,
+    DateTime = 2,
+  }
+
+  private ExcelFormatTranslator _translator;
+
+  internal ExcelFormatTranslator FormatTranslator {
+    get {
+      if (_translator == null) {
+        _translator = new(Format, NumFmtId);
+      }
+      return _translator;
+    }
+  }
+
+  internal class ExcelFormatTranslator {
+    internal ExcelFormatTranslator(string format, int numFmtId) {
+      if (numFmtId == 14) {
+        NetFormat = NetFormatForWidth = "d";
+        NetTextFormat = NetTextFormatForWidth = "";
+        DataType = eFormatType.DateTime;
+      } else if (format.Equals("general", StringComparison.InvariantCultureIgnoreCase)) {
+        NetFormat = NetFormatForWidth = "0.#####";
+        NetTextFormat = NetTextFormatForWidth = "";
+        DataType = eFormatType.Number;
+      } else {
+        ToNetFormat(format, false);
+        ToNetFormat(format, true);
+      }
+    }
+
+    internal string NetTextFormat { get; private set; }
+
+    internal string NetFormat { get; private set; }
+
+    private CultureInfo _ci;
+
+    internal CultureInfo Culture {
+      get {
+        if (_ci == null) {
+          return CultureInfo.CurrentCulture;
+        }
+        return _ci;
+      }
+      private set => _ci = value;
+    }
+
+    internal eFormatType DataType { get; private set; }
+
+    internal string NetTextFormatForWidth { get; private set; }
+
+    internal string NetFormatForWidth { get; private set; }
+
+    internal string FractionFormat { get; private set; }
+
+    private void ToNetFormat(string excelFormat, bool forColWidth) {
+      DataType = eFormatType.Unknown;
+      int secCount = 0;
+      bool isText = false;
+      bool isBracket = false;
+      string bracketText = "";
+      bool prevBslsh = false;
+      bool useMinute = false;
+      bool prevUnderScore = false;
+      bool ignoreNext = false;
+      string specialDateFormat = "";
+      bool containsAmPm = excelFormat.Contains("AM/PM");
+      List<int> lstDec = [];
+      StringBuilder sb = new StringBuilder();
+      Culture = null;
+      var format = "";
+      var text = "";
+      char clc;
+
+      if (containsAmPm) {
+        excelFormat = Regex.Replace(excelFormat, "AM/PM", "");
+        DataType = eFormatType.DateTime;
+      }
+
+      for (int pos = 0; pos < excelFormat.Length; pos++) {
+        char c = excelFormat[pos];
+        if (c == '"') {
+          isText = !isText;
+        } else {
+          if (ignoreNext) {
+            ignoreNext = false;
+            continue;
+          }
+          if (isText && !isBracket) {
+            sb.Append(c);
+          } else if (isBracket) {
+            if (c == ']') {
+              isBracket = false;
+              if (bracketText[0]
+                  == '$') //Local Info
+              {
+                string[] li = Regex.Split(bracketText, "-");
+                if (li[0].Length > 1) {
+                  sb.Append("\"" + li[0].Substring(1, li[0].Length - 1) + "\""); //Currency symbol
+                }
+                if (li.Length > 1) {
+                  if (li[1].Equals("f800", StringComparison.InvariantCultureIgnoreCase)) {
+                    specialDateFormat = "D";
+                  } else if (li[1].Equals("f400", StringComparison.InvariantCultureIgnoreCase)) {
+                    specialDateFormat = "T";
+                  } else {
+                    var num = int.Parse(li[1], NumberStyles.HexNumber);
+                    try {
+                      Culture = CultureInfo.GetCultureInfo(num & 0xFFFF);
+                    } catch {
+                      Culture = null;
+                    }
+                  }
+                }
+              } else if (bracketText[0] == 't') {
+                sb.Append("hh"); //TODO:This will not be correct for dates over 24H.
+              } else if (bracketText[0] == 'h') {
+                specialDateFormat = "hh"; //TODO:This will not be correct for dates over 24H.
+              }
+            } else {
+              bracketText += c;
+            }
+          } else if (prevUnderScore) {
+            if (forColWidth) {
+              sb.AppendFormat("\"{0}\"", c);
+            }
+            prevUnderScore = false;
+          } else {
+            if (c
+                == ';') //We use first part (for positive only at this stage)
+            {
+              secCount++;
+              if (DataType == eFormatType.DateTime || secCount == 3) {
+                //Add qoutes
+                if (DataType == eFormatType.DateTime) {
+                  SetDecimal(lstDec, sb); //Remove?
+                }
+                lstDec = [];
+                format = sb.ToString();
+                sb = new();
+              } else {
+                sb.Append(c);
+              }
+            } else {
+              clc = c.ToString().ToLower(CultureInfo.InvariantCulture)[0]; //Lowercase character
+              //Set the datetype
+              if (DataType == eFormatType.Unknown) {
+                if (c == '0' || c == '#' || c == '.') {
+                  DataType = eFormatType.Number;
+                } else if (clc == 'y'
+                    || clc == 'm'
+                    || clc == 'd'
+                    || clc == 'h'
+                    || clc == 'm'
+                    || clc == 's') {
+                  DataType = eFormatType.DateTime;
+                }
+              }
+
+              if (prevBslsh) {
+                if (c == '.' || c == ',') {
+                  sb.Append('\\');
+                }
+                sb.Append(c);
+                prevBslsh = false;
+              } else if (c == '[') {
+                bracketText = "";
+                isBracket = true;
+              } else if (c == '\\') {
+                prevBslsh = true;
+              } else if (c == '0'
+                  || c == '#'
+                  || c == '.'
+                  || c == ','
+                  || c == '%'
+                  || clc == 'd'
+                  || clc == 's') {
+                sb.Append(c);
+                if (c == '.') {
+                  lstDec.Add(sb.Length - 1);
+                }
+              } else if (clc == 'h') {
+                if (containsAmPm) {
+                  sb.Append('h');
+                  ;
+                } else {
+                  sb.Append('H');
+                }
+                useMinute = true;
+              } else if (clc == 'm') {
+                if (useMinute) {
+                  sb.Append('m');
+                } else {
+                  sb.Append('M');
+                }
+              } else if (c
+                  == '_') //Skip next but use for alignment
+              {
+                prevUnderScore = true;
+              } else if (c == '?') {
+                sb.Append(' ');
+              } else if (c == '/') {
+                if (DataType == eFormatType.Number) {
+                  int startPos = pos - 1;
+                  while (startPos >= 0
+                          && (excelFormat[startPos] == '?'
+                                  || excelFormat[startPos] == '#'
+                                  || excelFormat[startPos] == '0')) {
+                    startPos--;
+                  }
+
+                  if (startPos
+                      > 0) //RemovePart
+                  {
+                    sb.Remove(sb.Length - (pos - startPos - 1), (pos - startPos - 1));
+                  }
+
+                  int endPos = pos + 1;
+                  while (endPos < excelFormat.Length
+                          && (excelFormat[endPos] == '?'
+                                  || excelFormat[endPos] == '#'
+                                  || (excelFormat[endPos] >= '0' && excelFormat[endPos] <= '9'))) {
+                    endPos++;
+                  }
+                  pos = endPos;
+                  if (FractionFormat != "") {
+                    FractionFormat = excelFormat.Substring(startPos + 1, endPos - startPos - 1);
+                  }
+                  sb.Append('?'); //Will be replaced later on by the fraction
+                } else {
+                  sb.Append('/');
+                }
+              } else if (c == '*') {
+                //repeat char--> ignore
+                ignoreNext = true;
+              } else if (c == '@') {
+                sb.Append("{0}");
+              } else {
+                sb.Append(c);
+              }
+            }
+          }
+        }
+      }
+
+      //Add qoutes
+      if (DataType == eFormatType.DateTime) {
+        SetDecimal(lstDec, sb); //Remove?
+      }
+
+      // AM/PM format
+      if (containsAmPm) {
+        format += "tt";
+      }
+
+      if (format == "") {
+        format = sb.ToString();
+      } else {
+        text = sb.ToString();
+      }
+      if (specialDateFormat != "") {
+        format = specialDateFormat;
+      }
+
+      if (forColWidth) {
+        NetFormatForWidth = format;
+        NetTextFormatForWidth = text;
+      } else {
+        NetFormat = format;
+        NetTextFormat = text;
+      }
+      if (Culture == null) {
+        Culture = CultureInfo.CurrentCulture;
+      }
+    }
+
+    private static void SetDecimal(List<int> lstDec, StringBuilder sb) {
+      if (lstDec.Count > 1) {
+        for (int i = lstDec.Count - 1; i >= 0; i--) {
+          sb.Insert(lstDec[i] + 1, '\'');
+          sb.Insert(lstDec[i], '\'');
+        }
+      }
+    }
+
+    internal string FormatFraction(double d) {
+      int numerator,
+          denomerator;
+
+      int intPart = (int)d;
+
+      string[] fmt = FractionFormat.Split('/');
+
+      if (!int.TryParse(fmt[1], out var fixedDenominator)) {
+        fixedDenominator = 0;
+      }
+
+      if (d == 0 || double.IsNaN(d)) {
+        if (fmt[0].Trim() == "" && fmt[1].Trim() == "") {
+          return new(' ', FractionFormat.Length);
+        }
+        return 0.ToString(fmt[0]) + "/" + 1.ToString(fmt[0]);
+      }
+
+      int maxDigits = fmt[1].Length;
+      string sign = d < 0 ? "-" : "";
+      if (fixedDenominator == 0) {
+        List<double> numerators = [1, 0];
+        List<double> denominators = [0, 1];
+
+        if (maxDigits < 1 && maxDigits > 12) {
+          throw (new ArgumentException("Number of digits out of range (1-12)"));
+        }
+
+        int maxNum = 0;
+        for (int i = 0; i < maxDigits; i++) {
+          maxNum += 9 * (int)(Math.Pow(10, i));
+        }
+
+        double divRes = 1 / (Math.Abs(d) - intPart);
+        double result,
+            prevResult = double.NaN;
+        int listPos = 2,
+            index = 1;
+        while (true) {
+          index++;
+          double intDivRes = Math.Floor(divRes);
+          numerators.Add((intDivRes * numerators[index - 1] + numerators[index - 2]));
+          if (numerators[index] > maxNum) {
+            break;
+          }
+
+          denominators.Add((intDivRes * denominators[index - 1] + denominators[index - 2]));
+
+          result = numerators[index] / denominators[index];
+          if (denominators[index] > maxNum) {
+            break;
+          }
+          listPos = index;
+
+          if (result == prevResult) {
+            break;
+          }
+
+          if (result == d) {
+            break;
+          }
+
+          prevResult = result;
+
+          divRes = 1 / (divRes - intDivRes); //Rest
+        }
+
+        numerator = (int)numerators[listPos];
+        denomerator = (int)denominators[listPos];
+      } else {
+        numerator = (int)Math.Round((d - intPart) / (1D / fixedDenominator), 0);
+        denomerator = fixedDenominator;
+      }
+      if (numerator == denomerator || numerator == 0) {
+        if (numerator == denomerator) {
+          intPart++;
+        }
+        return sign + intPart.ToString(NetFormat).Replace("?", new(' ', FractionFormat.Length));
+      }
+      if (intPart == 0) {
+        return sign + FmtInt(numerator, fmt[0]) + "/" + FmtInt(denomerator, fmt[1]);
+      }
+      return sign
+          + intPart
+              .ToString(NetFormat)
+              .Replace("?", FmtInt(numerator, fmt[0]) + "/" + FmtInt(denomerator, fmt[1]));
+    }
+
+    private string FmtInt(double value, string format) {
+      string v = value.ToString("#");
+      string pad = "";
+      if (v.Length < format.Length) {
+        for (int i = format.Length - v.Length - 1; i >= 0; i--) {
+          if (format[i] == '?') {
+            pad += " ";
+          } else if (format[i] == ' ') {
+            pad += "0";
+          }
+        }
+      }
+      return pad + v;
+    }
+  }
+}
diff --git a/AppsheetEpplus/Style/XmlAccess/ExcelXfsXml.cs b/AppsheetEpplus/Style/XmlAccess/ExcelXfsXml.cs
new file mode 100644
index 0000000..4032042
--- /dev/null
+++ b/AppsheetEpplus/Style/XmlAccess/ExcelXfsXml.cs
@@ -0,0 +1,717 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		                Initial Release		        2009-10-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System;
+using System.Globalization;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Xml access class xfs records. This is the top level style object.
+/// </summary>
+public sealed class ExcelXfs : StyleXmlHelper {
+  private readonly ExcelStyles _styles;
+
+  internal ExcelXfs(XmlNamespaceManager nameSpaceManager, ExcelStyles styles)
+      : base(nameSpaceManager) {
+    _styles = styles;
+    isBuildIn = false;
+  }
+
+  internal ExcelXfs(XmlNamespaceManager nsm, XmlNode topNode, ExcelStyles styles)
+      : base(nsm, topNode) {
+    _styles = styles;
+    _xfID = GetXmlNodeInt("@xfId");
+    if (_xfID == 0) {
+      isBuildIn = true; //Normal taggen
+    }
+    _numFmtId = GetXmlNodeInt("@numFmtId");
+    _fontId = GetXmlNodeInt("@fontId");
+    _fillId = GetXmlNodeInt("@fillId");
+    _borderId = GetXmlNodeInt("@borderId");
+    _readingOrder = GetReadingOrder(GetXmlNodeString(_readingOrderPath));
+    _indent = GetXmlNodeInt(_indentPath);
+    _shrinkToFit = GetXmlNodeString(_shrinkToFitPath) == "1" ? true : false;
+    _verticalAlignment = GetVerticalAlign(GetXmlNodeString(_verticalAlignPath));
+    _horizontalAlignment = GetHorizontalAlign(GetXmlNodeString(_horizontalAlignPath));
+    _wrapText = GetXmlNodeBool(_wrapTextPath);
+    _textRotation = GetXmlNodeInt(textRotationPath);
+    _hidden = GetXmlNodeBool(_hiddenPath);
+    _locked = GetXmlNodeBool(_lockedPath, true);
+  }
+
+  private ExcelReadingOrder GetReadingOrder(string value) {
+    switch (value) {
+      case "1":
+        return ExcelReadingOrder.LeftToRight;
+      case "2":
+        return ExcelReadingOrder.RightToLeft;
+      default:
+        return ExcelReadingOrder.ContextDependent;
+    }
+  }
+
+  private ExcelHorizontalAlignment GetHorizontalAlign(string align) =>
+    Enum.TryParse<ExcelHorizontalAlignment>(align, true, out var result)
+        ? result
+        : ExcelHorizontalAlignment.General;
+
+  private ExcelVerticalAlignment GetVerticalAlign(string align) =>
+    Enum.TryParse<ExcelVerticalAlignment>(align, true, out var result)
+        ? result
+        : ExcelVerticalAlignment.Bottom;
+
+  private int _xfID;
+
+  /// <summary>
+  /// Style index
+  /// </summary>
+  public int XfId {
+    get => _xfID;
+    set => _xfID = value;
+  }
+
+  private int _numFmtId;
+
+  internal int NumberFormatId {
+    get => _numFmtId;
+    set {
+      _numFmtId = value;
+      ApplyNumberFormat = (value > 0);
+    }
+  }
+
+  private int _fontId;
+
+  internal int FontId {
+    get => _fontId;
+    set => _fontId = value;
+  }
+
+  private int _fillId;
+
+  internal int FillId {
+    get => _fillId;
+    set => _fillId = value;
+  }
+
+  private int _borderId;
+
+  internal int BorderId {
+    get => _borderId;
+    set => _borderId = value;
+  }
+
+  private bool isBuildIn { get; set; }
+
+  internal bool ApplyNumberFormat { get; set; }
+
+  internal bool ApplyFont { get; set; }
+
+  internal bool ApplyFill { get; set; }
+
+  internal bool ApplyBorder { get; set; }
+
+  internal bool ApplyAlignment { get; set; }
+
+  internal bool ApplyProtection { get; set; }
+
+  public ExcelStyles Styles { get; private set; }
+
+  /// <summary>
+  /// Numberformat properties
+  /// </summary>
+  public ExcelNumberFormatXml Numberformat => _styles.NumberFormats[_numFmtId < 0 ? 0 : _numFmtId];
+
+  /// <summary>
+  /// Font properties
+  /// </summary>
+  public ExcelFontXml Font => _styles.Fonts[_fontId < 0 ? 0 : _fontId];
+
+  /// <summary>
+  /// Fill properties
+  /// </summary>
+  public ExcelFillXml Fill => _styles.Fills[_fillId < 0 ? 0 : _fillId];
+
+  /// <summary>
+  /// Border style properties
+  /// </summary>
+  public ExcelBorderXml Border => _styles.Borders[_borderId < 0 ? 0 : _borderId];
+
+  private const string _horizontalAlignPath = "d:alignment/@horizontal";
+  private ExcelHorizontalAlignment _horizontalAlignment = ExcelHorizontalAlignment.General;
+
+  /// <summary>
+  /// Horizontal alignment
+  /// </summary>
+  public ExcelHorizontalAlignment HorizontalAlignment {
+    get => _horizontalAlignment;
+    set => _horizontalAlignment = value;
+  }
+
+  private const string _verticalAlignPath = "d:alignment/@vertical";
+  private ExcelVerticalAlignment _verticalAlignment = ExcelVerticalAlignment.Bottom;
+
+  /// <summary>
+  /// Vertical alignment
+  /// </summary>
+  public ExcelVerticalAlignment VerticalAlignment {
+    get => _verticalAlignment;
+    set => _verticalAlignment = value;
+  }
+
+  private const string _wrapTextPath = "d:alignment/@wrapText";
+  private bool _wrapText;
+
+  /// <summary>
+  /// Wraped text
+  /// </summary>
+  public bool WrapText {
+    get => _wrapText;
+    set => _wrapText = value;
+  }
+
+  private readonly string textRotationPath = "d:alignment/@textRotation";
+  private int _textRotation;
+
+  /// <summary>
+  /// Text rotation angle
+  /// </summary>
+  public int TextRotation {
+    get => (_textRotation == int.MinValue ? 0 : _textRotation);
+    set => _textRotation = value;
+  }
+
+  private const string _lockedPath = "d:protection/@locked";
+  private bool _locked = true;
+
+  /// <summary>
+  /// Locked when sheet is protected
+  /// </summary>
+  public bool Locked {
+    get => _locked;
+    set => _locked = value;
+  }
+
+  private const string _hiddenPath = "d:protection/@hidden";
+  private bool _hidden;
+
+  /// <summary>
+  /// Hide formulas when sheet is protected
+  /// </summary>
+  public bool Hidden {
+    get => _hidden;
+    set => _hidden = value;
+  }
+
+  private const string _readingOrderPath = "d:alignment/@readingOrder";
+  private ExcelReadingOrder _readingOrder = ExcelReadingOrder.ContextDependent;
+
+  /// <summary>
+  /// Readingorder
+  /// </summary>
+  public ExcelReadingOrder ReadingOrder {
+    get => _readingOrder;
+    set => _readingOrder = value;
+  }
+
+  private const string _shrinkToFitPath = "d:alignment/@shrinkToFit";
+  private bool _shrinkToFit;
+
+  /// <summary>
+  /// Shrink to fit
+  /// </summary>
+  public bool ShrinkToFit {
+    get => _shrinkToFit;
+    set => _shrinkToFit = value;
+  }
+
+  private const string _indentPath = "d:alignment/@indent";
+  private int _indent;
+
+  /// <summary>
+  /// Indentation
+  /// </summary>
+  public int Indent {
+    get => (_indent == int.MinValue ? 0 : _indent);
+    set => _indent = value;
+  }
+
+  internal void RegisterEvent(ExcelXfs xf) {
+    //                RegisterEvent(xf, xf.Xf_ChangedEvent);
+  }
+
+  internal override string Id =>
+    XfId
+        + "|"
+        + NumberFormatId
+        + "|"
+        + FontId
+        + "|"
+        + FillId
+        + "|"
+        + BorderId
+        + VerticalAlignment
+        + "|"
+        + HorizontalAlignment
+        + "|"
+        + WrapText
+        + "|"
+        + ReadingOrder
+        + "|"
+        + isBuildIn
+        + TextRotation
+        + Locked
+        + Hidden
+        + ShrinkToFit
+        + Indent;
+
+  //return Numberformat.Id + "|" + Font.Id + "|" + Fill.Id + "|" + Border.Id + VerticalAlignment.ToString() + "|" + HorizontalAlignment.ToString() + "|" + WrapText.ToString() + "|" + ReadingOrder.ToString();
+  internal ExcelXfs Copy() {
+    return Copy(_styles);
+  }
+
+  internal ExcelXfs Copy(ExcelStyles styles) {
+    ExcelXfs newXf = new ExcelXfs(NameSpaceManager, styles);
+    newXf.NumberFormatId = _numFmtId;
+    newXf.FontId = _fontId;
+    newXf.FillId = _fillId;
+    newXf.BorderId = _borderId;
+    newXf.XfId = _xfID;
+    newXf.ReadingOrder = _readingOrder;
+    newXf.HorizontalAlignment = _horizontalAlignment;
+    newXf.VerticalAlignment = _verticalAlignment;
+    newXf.WrapText = _wrapText;
+    newXf.ShrinkToFit = _shrinkToFit;
+    newXf.Indent = _indent;
+    newXf.TextRotation = _textRotation;
+    newXf.Locked = _locked;
+    newXf.Hidden = _hidden;
+    return newXf;
+  }
+
+  internal int GetNewId(
+      ExcelStyleCollection<ExcelXfs> xfsCol,
+      StyleBase styleObject,
+      eStyleClass styleClass,
+      eStyleProperty styleProperty,
+      object value) {
+    ExcelXfs newXfs = Copy();
+    switch (styleClass) {
+      case eStyleClass.Numberformat:
+        newXfs.NumberFormatId = GetIdNumberFormat(styleProperty, value);
+        styleObject.SetIndex(newXfs.NumberFormatId);
+        break;
+      case eStyleClass.Font: {
+        newXfs.FontId = GetIdFont(styleProperty, value);
+        styleObject.SetIndex(newXfs.FontId);
+        break;
+      }
+      case eStyleClass.Fill:
+      case eStyleClass.FillBackgroundColor:
+      case eStyleClass.FillPatternColor:
+        newXfs.FillId = GetIdFill(styleClass, styleProperty, value);
+        styleObject.SetIndex(newXfs.FillId);
+        break;
+      case eStyleClass.GradientFill:
+      case eStyleClass.FillGradientColor1:
+      case eStyleClass.FillGradientColor2:
+        newXfs.FillId = GetIdGradientFill(styleClass, styleProperty, value);
+        styleObject.SetIndex(newXfs.FillId);
+        break;
+      case eStyleClass.Border:
+      case eStyleClass.BorderBottom:
+      case eStyleClass.BorderDiagonal:
+      case eStyleClass.BorderLeft:
+      case eStyleClass.BorderRight:
+      case eStyleClass.BorderTop:
+        newXfs.BorderId = GetIdBorder(styleClass, styleProperty, value);
+        styleObject.SetIndex(newXfs.BorderId);
+        break;
+      case eStyleClass.Style:
+        switch (styleProperty) {
+          case eStyleProperty.XfId:
+            newXfs.XfId = (int)value;
+            break;
+          case eStyleProperty.HorizontalAlign:
+            newXfs.HorizontalAlignment = (ExcelHorizontalAlignment)value;
+            break;
+          case eStyleProperty.VerticalAlign:
+            newXfs.VerticalAlignment = (ExcelVerticalAlignment)value;
+            break;
+          case eStyleProperty.WrapText:
+            newXfs.WrapText = (bool)value;
+            break;
+          case eStyleProperty.ReadingOrder:
+            newXfs.ReadingOrder = (ExcelReadingOrder)value;
+            break;
+          case eStyleProperty.ShrinkToFit:
+            newXfs.ShrinkToFit = (bool)value;
+            break;
+          case eStyleProperty.Indent:
+            newXfs.Indent = (int)value;
+            break;
+          case eStyleProperty.TextRotation:
+            newXfs.TextRotation = (int)value;
+            break;
+          case eStyleProperty.Locked:
+            newXfs.Locked = (bool)value;
+            break;
+          case eStyleProperty.Hidden:
+            newXfs.Hidden = (bool)value;
+            break;
+          default:
+            throw (new("Invalid property for class style."));
+        }
+        break;
+    }
+    int id = xfsCol.FindIndexById(newXfs.Id);
+    if (id < 0) {
+      return xfsCol.Add(newXfs.Id, newXfs);
+    }
+    return id;
+  }
+
+  private int GetIdBorder(eStyleClass styleClass, eStyleProperty styleProperty, object value) {
+    ExcelBorderXml border = Border.Copy();
+
+    switch (styleClass) {
+      case eStyleClass.BorderBottom:
+        SetBorderItem(border.Bottom, styleProperty, value);
+        break;
+      case eStyleClass.BorderDiagonal:
+        SetBorderItem(border.Diagonal, styleProperty, value);
+        break;
+      case eStyleClass.BorderLeft:
+        SetBorderItem(border.Left, styleProperty, value);
+        break;
+      case eStyleClass.BorderRight:
+        SetBorderItem(border.Right, styleProperty, value);
+        break;
+      case eStyleClass.BorderTop:
+        SetBorderItem(border.Top, styleProperty, value);
+        break;
+      case eStyleClass.Border:
+        if (styleProperty == eStyleProperty.BorderDiagonalUp) {
+          border.DiagonalUp = (bool)value;
+        } else if (styleProperty == eStyleProperty.BorderDiagonalDown) {
+          border.DiagonalDown = (bool)value;
+        } else {
+          throw (new("Invalid property for class Border."));
+        }
+        break;
+      default:
+        throw (new("Invalid class/property for class Border."));
+    }
+    int subId;
+    string id = border.Id;
+    subId = _styles.Borders.FindIndexById(id);
+    if (subId == int.MinValue) {
+      return _styles.Borders.Add(id, border);
+    }
+    return subId;
+  }
+
+  private void SetBorderItem(
+      ExcelBorderItemXml excelBorderItem,
+      eStyleProperty styleProperty,
+      object value) {
+    if (styleProperty == eStyleProperty.Style) {
+      excelBorderItem.Style = (ExcelBorderStyle)value;
+    } else if (styleProperty == eStyleProperty.Color
+        || styleProperty == eStyleProperty.Tint
+        || styleProperty == eStyleProperty.IndexedColor) {
+      if (excelBorderItem.Style == ExcelBorderStyle.None) {
+        throw (new("Can't set bordercolor when style is not set."));
+      }
+      excelBorderItem.Color.Rgb = value.ToString();
+    }
+  }
+
+  private int GetIdFill(eStyleClass styleClass, eStyleProperty styleProperty, object value) {
+    ExcelFillXml fill = Fill.Copy();
+
+    switch (styleProperty) {
+      case eStyleProperty.PatternType:
+        if (fill is ExcelGradientFillXml) {
+          fill = new(NameSpaceManager);
+        }
+        fill.PatternType = (ExcelFillStyle)value;
+        break;
+      case eStyleProperty.Color:
+      case eStyleProperty.Tint:
+      case eStyleProperty.IndexedColor:
+      case eStyleProperty.AutoColor:
+        if (fill is ExcelGradientFillXml) {
+          fill = new(NameSpaceManager);
+        }
+        if (fill.PatternType == ExcelFillStyle.None) {
+          throw (new ArgumentException("Can't set color when patterntype is not set."));
+        }
+        ExcelColorXml destColor;
+        if (styleClass == eStyleClass.FillPatternColor) {
+          destColor = fill.PatternColor;
+        } else {
+          destColor = fill.BackgroundColor;
+        }
+
+        if (styleProperty == eStyleProperty.Color) {
+          destColor.Rgb = value.ToString();
+        } else if (styleProperty == eStyleProperty.Tint) {
+          destColor.Tint = (decimal)value;
+        } else if (styleProperty == eStyleProperty.IndexedColor) {
+          destColor.Indexed = (int)value;
+        } else {
+          destColor.Auto = (bool)value;
+        }
+
+        break;
+      default:
+        throw (new ArgumentException("Invalid class/property for class Fill."));
+    }
+    int subId;
+    string id = fill.Id;
+    subId = _styles.Fills.FindIndexById(id);
+    if (subId == int.MinValue) {
+      return _styles.Fills.Add(id, fill);
+    }
+    return subId;
+  }
+
+  private int GetIdGradientFill(
+      eStyleClass styleClass,
+      eStyleProperty styleProperty,
+      object value) {
+    ExcelGradientFillXml fill;
+    if (Fill is ExcelGradientFillXml) {
+      fill = (ExcelGradientFillXml)Fill.Copy();
+    } else {
+      fill = new(Fill.NameSpaceManager);
+      fill.GradientColor1.Rgb = "FFFFFFFF";
+      fill.GradientColor2.Rgb = "FF4F81BD";
+      fill.Type = ExcelFillGradientType.Linear;
+      fill.Degree = 90;
+      fill.Top = double.NaN;
+      fill.Bottom = double.NaN;
+      fill.Left = double.NaN;
+      fill.Right = double.NaN;
+    }
+
+    switch (styleProperty) {
+      case eStyleProperty.GradientType:
+        fill.Type = (ExcelFillGradientType)value;
+        break;
+      case eStyleProperty.GradientDegree:
+        fill.Degree = (double)value;
+        break;
+      case eStyleProperty.GradientTop:
+        fill.Top = (double)value;
+        break;
+      case eStyleProperty.GradientBottom:
+        fill.Bottom = (double)value;
+        break;
+      case eStyleProperty.GradientLeft:
+        fill.Left = (double)value;
+        break;
+      case eStyleProperty.GradientRight:
+        fill.Right = (double)value;
+        break;
+      case eStyleProperty.Color:
+      case eStyleProperty.Tint:
+      case eStyleProperty.IndexedColor:
+      case eStyleProperty.AutoColor:
+        ExcelColorXml destColor;
+
+        if (styleClass == eStyleClass.FillGradientColor1) {
+          destColor = fill.GradientColor1;
+        } else {
+          destColor = fill.GradientColor2;
+        }
+
+        if (styleProperty == eStyleProperty.Color) {
+          destColor.Rgb = value.ToString();
+        } else if (styleProperty == eStyleProperty.Tint) {
+          destColor.Tint = (decimal)value;
+        } else if (styleProperty == eStyleProperty.IndexedColor) {
+          destColor.Indexed = (int)value;
+        } else {
+          destColor.Auto = (bool)value;
+        }
+        break;
+      default:
+        throw (new ArgumentException("Invalid class/property for class Fill."));
+    }
+    int subId;
+    string id = fill.Id;
+    subId = _styles.Fills.FindIndexById(id);
+    if (subId == int.MinValue) {
+      return _styles.Fills.Add(id, fill);
+    }
+    return subId;
+  }
+
+  private int GetIdNumberFormat(eStyleProperty styleProperty, object value) {
+    if (styleProperty == eStyleProperty.Format) {
+      ExcelNumberFormatXml item = null;
+      if (!_styles.NumberFormats.FindById(value.ToString(), ref item)) {
+        item = new(NameSpaceManager) {
+          Format = value.ToString(),
+          NumFmtId = _styles.NumberFormats.NextId++,
+        };
+        _styles.NumberFormats.Add(value.ToString(), item);
+      }
+      return item.NumFmtId;
+    }
+    throw (new("Invalid property for class Numberformat"));
+  }
+
+  private int GetIdFont(eStyleProperty styleProperty, object value) {
+    ExcelFontXml fnt = Font.Copy();
+
+    switch (styleProperty) {
+      case eStyleProperty.Name:
+        fnt.Name = value.ToString();
+        break;
+      case eStyleProperty.Size:
+        fnt.Size = (float)value;
+        break;
+      case eStyleProperty.Family:
+        fnt.Family = (int)value;
+        break;
+      case eStyleProperty.Bold:
+        fnt.Bold = (bool)value;
+        break;
+      case eStyleProperty.Italic:
+        fnt.Italic = (bool)value;
+        break;
+      case eStyleProperty.Strike:
+        fnt.Strike = (bool)value;
+        break;
+      case eStyleProperty.UnderlineType:
+        fnt.UnderLineType = (ExcelUnderLineType)value;
+        break;
+      case eStyleProperty.Color:
+        fnt.Color.Rgb = value.ToString();
+        break;
+      case eStyleProperty.VerticalAlign:
+        fnt.VerticalAlign =
+            ((ExcelVerticalAlignmentFont)value) == ExcelVerticalAlignmentFont.None
+                ? ""
+                : value.ToString().ToLower(CultureInfo.InvariantCulture);
+        break;
+      default:
+        throw (new("Invalid property for class Font"));
+    }
+    int subId;
+    string id = fnt.Id;
+    subId = _styles.Fonts.FindIndexById(id);
+    if (subId == int.MinValue) {
+      return _styles.Fonts.Add(id, fnt);
+    }
+    return subId;
+  }
+
+  internal override XmlNode CreateXmlNode(XmlNode topNode) {
+    return CreateXmlNode(topNode, false);
+  }
+
+  internal XmlNode CreateXmlNode(XmlNode topNode, bool isCellStyleXsf) {
+    TopNode = topNode;
+    var doSetXfId =
+        (!isCellStyleXsf
+            && _xfID > int.MinValue
+            && _styles.CellStyleXfs.Count > 0
+            && _styles.CellStyleXfs[_xfID].newID > int.MinValue);
+    if (_numFmtId > 0) {
+      SetXmlNodeString("@numFmtId", _numFmtId.ToString());
+      if (doSetXfId) {
+        SetXmlNodeString("@applyNumberFormat", "1");
+      }
+    }
+    if (_fontId >= 0) {
+      SetXmlNodeString("@fontId", _styles.Fonts[_fontId].newID.ToString());
+      if (doSetXfId) {
+        SetXmlNodeString("@applyFont", "1");
+      }
+    }
+    if (_fillId >= 0) {
+      SetXmlNodeString("@fillId", _styles.Fills[_fillId].newID.ToString());
+      if (doSetXfId) {
+        SetXmlNodeString("@applyFill", "1");
+      }
+    }
+    if (_borderId >= 0) {
+      SetXmlNodeString("@borderId", _styles.Borders[_borderId].newID.ToString());
+      if (doSetXfId) {
+        SetXmlNodeString("@applyBorder", "1");
+      }
+    }
+    if (_horizontalAlignment != ExcelHorizontalAlignment.General) {
+      SetXmlNodeString(_horizontalAlignPath, SetAlignString(_horizontalAlignment));
+    }
+    if (doSetXfId) {
+      SetXmlNodeString("@xfId", _styles.CellStyleXfs[_xfID].newID.ToString());
+    }
+    if (_verticalAlignment != ExcelVerticalAlignment.Bottom) {
+      SetXmlNodeString(_verticalAlignPath, SetAlignString(_verticalAlignment));
+    }
+    if (_wrapText) {
+      SetXmlNodeString(_wrapTextPath, "1");
+    }
+    if (_readingOrder != ExcelReadingOrder.ContextDependent) {
+      SetXmlNodeString(_readingOrderPath, ((int)_readingOrder).ToString());
+    }
+    if (_shrinkToFit) {
+      SetXmlNodeString(_shrinkToFitPath, "1");
+    }
+    if (_indent > 0) {
+      SetXmlNodeString(_indentPath, _indent.ToString());
+    }
+    if (_textRotation > 0) {
+      SetXmlNodeString(textRotationPath, _textRotation.ToString());
+    }
+    if (!_locked) {
+      SetXmlNodeString(_lockedPath, "0");
+    }
+    if (_hidden) {
+      SetXmlNodeString(_hiddenPath, "1");
+    }
+    return TopNode;
+  }
+
+  private string SetAlignString(Enum align) {
+    string newName = Enum.GetName(align.GetType(), align);
+    return newName.Substring(0, 1).ToLower(CultureInfo.InvariantCulture)
+        + newName.Substring(1, newName.Length - 1);
+  }
+}
diff --git a/AppsheetEpplus/Style/XmlAccess/StyleXmlHelper.cs b/AppsheetEpplus/Style/XmlAccess/StyleXmlHelper.cs
new file mode 100644
index 0000000..f17ffa6
--- /dev/null
+++ b/AppsheetEpplus/Style/XmlAccess/StyleXmlHelper.cs
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		                Initial Release		        2009-10-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Xml helper class for cell style classes
+/// </summary>
+public abstract class StyleXmlHelper : XmlHelper {
+  internal StyleXmlHelper(XmlNamespaceManager nameSpaceManager)
+      : base(nameSpaceManager) {}
+
+  internal StyleXmlHelper(XmlNamespaceManager nameSpaceManager, XmlNode topNode)
+      : base(nameSpaceManager, topNode) {}
+
+  internal abstract XmlNode CreateXmlNode(XmlNode top);
+
+  internal abstract string Id { get; }
+
+  internal long useCnt = 0;
+  internal int newID = int.MinValue;
+
+  protected bool GetBoolValue(XmlNode topNode, string path) {
+    var node = topNode.SelectSingleNode(path, NameSpaceManager);
+    if (node is XmlAttribute) {
+      return node.Value != "0";
+    }
+    if (node != null
+        && ((node.Attributes["val"] != null && node.Attributes["val"].Value != "0")
+                || node.Attributes["val"] == null)) {
+      return true;
+    }
+    return false;
+  }
+}
diff --git a/AppsheetEpplus/Table/ExcelTable.cs b/AppsheetEpplus/Table/ExcelTable.cs
new file mode 100644
index 0000000..d7115fd
--- /dev/null
+++ b/AppsheetEpplus/Table/ExcelTable.cs
@@ -0,0 +1,348 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		Added		30-AUG-2010
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Table style Enum
+/// </summary>
+public enum TableStyles {
+  None,
+  Custom,
+  Light1,
+  Light2,
+  Light3,
+  Light4,
+  Light5,
+  Light6,
+  Light7,
+  Light8,
+  Light9,
+  Light10,
+  Light11,
+  Light12,
+  Light13,
+  Light14,
+  Light15,
+  Light16,
+  Light17,
+  Light18,
+  Light19,
+  Light20,
+  Light21,
+  Medium1,
+  Medium2,
+  Medium3,
+  Medium4,
+  Medium5,
+  Medium6,
+  Medium7,
+  Medium8,
+  Medium9,
+  Medium10,
+  Medium11,
+  Medium12,
+  Medium13,
+  Medium14,
+  Medium15,
+  Medium16,
+  Medium17,
+  Medium18,
+  Medium19,
+  Medium20,
+  Medium21,
+  Medium22,
+  Medium23,
+  Medium24,
+  Medium25,
+  Medium26,
+  Medium27,
+  Medium28,
+  Dark1,
+  Dark2,
+  Dark3,
+  Dark4,
+  Dark5,
+  Dark6,
+  Dark7,
+  Dark8,
+  Dark9,
+  Dark10,
+  Dark11,
+}
+
+/// <summary>
+/// An Excel Table
+/// </summary>
+public class ExcelTable : XmlHelper, IEqualityComparer<ExcelTable> {
+  protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
+    "autoFilter",
+    "tableColumns",
+    "tableStyleInfo",
+  ];
+
+  internal ExcelTable(ZipPackageRelationship rel, ExcelWorksheet sheet)
+      : base(sheet.NameSpaceManager) {
+    WorkSheet = sheet;
+    TableUri = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri);
+    RelationshipID = rel.Id;
+    TableXml = sheet._package.GetXmlDocument(TableUri);
+    TopNode = TableXml.DocumentElement;
+    Address = new(GetXmlNodeString("@ref"));
+  }
+
+  /// <summary>
+  /// Provides access to the XML data representing the table in the package.
+  /// </summary>
+  internal XmlDocument TableXml { get; }
+
+  /// <summary>
+  /// The package internal URI to the Table Xml Document.
+  /// </summary>
+  private Uri TableUri { get; }
+
+  internal string RelationshipID { get; set; }
+
+  private const string _idPath = "@id";
+
+  internal int Id => GetXmlNodeInt(_idPath);
+
+  private const string _namePath = "@name";
+  private const string _displayNamePath = "@displayName";
+
+  /// <summary>
+  /// The name of the table object in Excel
+  /// </summary>
+  public string Name => GetXmlNodeString(_namePath);
+
+  /// <summary>
+  /// The worksheet of the table
+  /// </summary>
+  public ExcelWorksheet WorkSheet { get; }
+
+  private ExcelAddressBase _address;
+
+  /// <summary>
+  /// The address of the table
+  /// </summary>
+  public ExcelAddressBase Address {
+    get => _address;
+    set {
+      _address = value;
+      SetXmlNodeString("@ref", value.Address);
+      WriteAutoFilter(ShowTotal);
+    }
+  }
+
+  internal ExcelTableColumnCollection _cols;
+
+  /// <summary>
+  /// Collection of the columns in the table
+  /// </summary>
+  public ExcelTableColumnCollection Columns {
+    get {
+      if (_cols == null) {
+        _cols = new(this);
+      }
+      return _cols;
+    }
+  }
+
+  private const string _headerrowcountPath = "@headerRowCount";
+  private const string _autofilterPath = "d:autoFilter/@ref";
+
+  /// <summary>
+  /// If the header row is visible or not
+  /// </summary>
+  public bool ShowHeader {
+    get => GetXmlNodeInt(_headerrowcountPath) != 0;
+    set {
+      if (Address._toRow - Address._fromRow < 0 && value
+          || Address._toRow - Address._fromRow == 1 && value && ShowTotal) {
+        throw (new("Cant set ShowHeader-property. Table has too few rows"));
+      }
+
+      if (value) {
+        DeleteNode(_headerrowcountPath);
+        WriteAutoFilter(ShowTotal);
+        //for (int i = 0; i < Columns.Count; i++)
+        //{
+        //    var v = WorkSheet.GetValue<string>(Address._fromRow, Address._fromCol + i);
+        //    if (!string.IsNullOrEmpty(v) || v != _cols[i].Name)
+        //    {
+        //        _cols[i].Name = v;
+        //    }
+        //}
+      } else {
+        SetXmlNodeString(_headerrowcountPath, "0");
+        DeleteAllNode(_autofilterPath);
+      }
+    }
+  }
+
+  internal ExcelAddressBase AutoFilterAddress {
+    get {
+      string a = GetXmlNodeString(_autofilterPath);
+      if (a == "") {
+        return null;
+      }
+      return new(a);
+    }
+  }
+
+  private void WriteAutoFilter(bool showTotal) {
+    string autofilterAddress;
+    if (ShowHeader) {
+      if (showTotal) {
+        autofilterAddress = ExcelCellBase.GetAddress(
+            Address._fromRow,
+            Address._fromCol,
+            Address._toRow - 1,
+            Address._toCol);
+      } else {
+        autofilterAddress = Address.Address;
+      }
+      SetXmlNodeString(_autofilterPath, autofilterAddress);
+    }
+  }
+
+  /// <summary>
+  /// If the header row has an autofilter
+  /// </summary>
+  public bool ShowFilter => ShowHeader && AutoFilterAddress != null;
+
+  private const string _totalsrowcountPath = "@totalsRowCount";
+
+  /// <summary>
+  /// If the total row is visible or not
+  /// </summary>
+  public bool ShowTotal {
+    get => GetXmlNodeInt(_totalsrowcountPath) == 1;
+    set {
+      if (value != ShowTotal) {
+        if (value) {
+          Address = new ExcelAddress(
+              WorkSheet.Name,
+              ExcelCellBase.GetAddress(
+                  Address.Start.Row,
+                  Address.Start.Column,
+                  Address.End.Row + 1,
+                  Address.End.Column));
+        } else {
+          Address = new ExcelAddress(
+              WorkSheet.Name,
+              ExcelCellBase.GetAddress(
+                  Address.Start.Row,
+                  Address.Start.Column,
+                  Address.End.Row - 1,
+                  Address.End.Column));
+        }
+        SetXmlNodeString("@ref", Address.Address);
+        if (value) {
+          SetXmlNodeString(_totalsrowcountPath, "1");
+        } else {
+          DeleteNode(_totalsrowcountPath);
+        }
+        WriteAutoFilter(value);
+      }
+    }
+  }
+
+  private const string _stylenamePath = "d:tableStyleInfo/@name";
+
+  /// <summary>
+  /// The style name for custum styles
+  /// </summary>
+  public string StyleName => GetXmlNodeString(_stylenamePath);
+
+  private const string _showfirstcolumnPath = "d:tableStyleInfo/@showFirstColumn";
+
+  /// <summary>
+  /// Display special formatting for the first row
+  /// </summary>
+  public bool ShowFirstColumn => GetXmlNodeBool(_showfirstcolumnPath);
+
+  private const string _showlastcolumnPath = "d:tableStyleInfo/@showLastColumn";
+
+  /// <summary>
+  /// Display special formatting for the last row
+  /// </summary>
+  public bool ShowLastColumn => GetXmlNodeBool(_showlastcolumnPath);
+
+  private const string _showrowstripesPath = "d:tableStyleInfo/@showRowStripes";
+
+  /// <summary>
+  /// Display banded rows
+  /// </summary>
+  public bool ShowRowStripes => GetXmlNodeBool(_showrowstripesPath);
+
+  private const string _showcolumnstripesPath = "d:tableStyleInfo/@showColumnStripes";
+
+  /// <summary>
+  /// Display banded columns
+  /// </summary>
+  public bool ShowColumnStripes => GetXmlNodeBool(_showcolumnstripesPath);
+
+  private const string _totalsrowcellstylePath = "@totalsRowCellStyle";
+
+  /// <summary>
+  /// Named style used for the total row
+  /// </summary>
+  public string TotalsRowCellStyle => GetXmlNodeString(_totalsrowcellstylePath);
+
+  private const string _datacellstylePath = "@dataCellStyle";
+
+  /// <summary>
+  /// Named style used for the data cells
+  /// </summary>
+  public string DataCellStyleName => GetXmlNodeString(_datacellstylePath);
+
+  private const string _headerrowcellstylePath = "@headerRowCellStyle";
+
+  /// <summary>
+  /// Named style used for the header row
+  /// </summary>
+  public string HeaderRowCellStyle => GetXmlNodeString(_headerrowcellstylePath);
+
+  public bool Equals(ExcelTable x, ExcelTable y) {
+    return x.WorkSheet == y.WorkSheet && x.Id == y.Id && x.TableXml.OuterXml == y.TableXml.OuterXml;
+  }
+
+  public int GetHashCode(ExcelTable obj) {
+    return obj.TableXml.OuterXml.GetHashCode();
+  }
+}
diff --git a/AppsheetEpplus/Table/ExcelTableCollection.cs b/AppsheetEpplus/Table/ExcelTableCollection.cs
new file mode 100644
index 0000000..60a4878
--- /dev/null
+++ b/AppsheetEpplus/Table/ExcelTableCollection.cs
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		Added		30-AUG-2010
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// A collection of table objects
+/// </summary>
+public class ExcelTableCollection : IEnumerable<ExcelTable> {
+  private readonly List<ExcelTable> _tables = new();
+  internal Dictionary<string, int> _tableNames = new(StringComparer.InvariantCultureIgnoreCase);
+  private readonly ExcelWorksheet _ws;
+
+  internal ExcelTableCollection(ExcelWorksheet ws) {
+    var pck = ws._package.Package;
+    _ws = ws;
+    foreach (XmlElement node in ws.WorksheetXml.SelectNodes(
+        "//d:tableParts/d:tablePart",
+        ws.NameSpaceManager)) {
+      var rel = ws.Part.GetRelationship(node.GetAttribute("id", ExcelPackage._schemaRelationships));
+      var tbl = new ExcelTable(rel, ws);
+      _tableNames.Add(tbl.Name, _tables.Count);
+      _tables.Add(tbl);
+    }
+  }
+
+  internal string GetNewTableName() {
+    string name = "Table1";
+    int i = 2;
+    while (_ws.Workbook.ExistsTableName(name)) {
+      name = string.Format("Table{0}", i++);
+    }
+    return name;
+  }
+
+  /// <summary>
+  /// Number of items in the collection
+  /// </summary>
+  public int Count => _tables.Count;
+
+  /// <summary>
+  /// Get the table object from a range.
+  /// </summary>
+  /// <param name="range">The range</param>
+  /// <returns>The table. Null if no range matches</returns>
+  public ExcelTable GetFromRange(ExcelRangeBase range) {
+    foreach (var tbl in range.Worksheet.Tables) {
+      if (tbl.Address._address == range._address) {
+        return tbl;
+      }
+    }
+    return null;
+  }
+
+  /// <summary>
+  /// The table Index. Base 0.
+  /// </summary>
+  /// <param name="index"></param>
+  /// <returns></returns>
+  public ExcelTable this[int index] {
+    get {
+      if (index < 0 || index >= _tables.Count) {
+        throw (new ArgumentOutOfRangeException("Table index out of range"));
+      }
+      return _tables[index];
+    }
+  }
+
+  /// <summary>
+  /// Indexer
+  /// </summary>
+  /// <param name="name">The name of the table</param>
+  /// <returns>The table. Null if the table name is not found in the collection</returns>
+  public ExcelTable this[string name] {
+    get {
+      if (_tableNames.ContainsKey(name)) {
+        return _tables[_tableNames[name]];
+      }
+      return null;
+    }
+  }
+
+  public IEnumerator<ExcelTable> GetEnumerator() {
+    return _tables.GetEnumerator();
+  }
+
+  IEnumerator IEnumerable.GetEnumerator() {
+    return _tables.GetEnumerator();
+  }
+}
diff --git a/AppsheetEpplus/Table/ExcelTableColumn.cs b/AppsheetEpplus/Table/ExcelTableColumn.cs
new file mode 100644
index 0000000..b174914
--- /dev/null
+++ b/AppsheetEpplus/Table/ExcelTableColumn.cs
@@ -0,0 +1,202 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		Added		30-AUG-2010
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System;
+using System.Globalization;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Build-in table row functions
+/// </summary>
+public enum RowFunctions {
+  Average,
+  Count,
+  CountNums,
+  Custom,
+  Max,
+  Min,
+  None,
+  StdDev,
+  Sum,
+  Var,
+}
+
+/// <summary>
+/// A table column
+/// </summary>
+public class ExcelTableColumn : XmlHelper {
+  internal ExcelTable _tbl;
+
+  internal ExcelTableColumn(XmlNamespaceManager ns, XmlNode topNode, ExcelTable tbl, int pos)
+      : base(ns, topNode) {
+    _tbl = tbl;
+    Position = pos;
+  }
+
+  /// <summary>
+  /// The column id
+  /// </summary>
+  public int Id {
+    get => GetXmlNodeInt("@id");
+    set => SetXmlNodeString("@id", value.ToString());
+  }
+
+  /// <summary>
+  /// The position of the column
+  /// </summary>
+  public int Position { get; private set; }
+
+  /// <summary>
+  /// The name of the column
+  /// </summary>
+  public string Name {
+    get {
+      var n = GetXmlNodeString("@name");
+      if (string.IsNullOrEmpty(n)) {
+        if (_tbl.ShowHeader) {
+          n = ConvertUtil.ExcelDecodeString(
+              _tbl.WorkSheet.GetValue<string>(
+                  _tbl.Address._fromRow,
+                  _tbl.Address._fromCol + Position));
+        } else {
+          n = "Column" + (Position + 1);
+        }
+      }
+      return n;
+    }
+    set {
+      var v = ConvertUtil.ExcelEncodeString(value);
+      SetXmlNodeString("@name", v);
+      if (_tbl.ShowHeader) {
+        _tbl.WorkSheet.SetValue(_tbl.Address._fromRow, _tbl.Address._fromCol + Position, value);
+      }
+      _tbl.WorkSheet.SetTableTotalFunction(_tbl, this);
+    }
+  }
+
+  /// <summary>
+  /// A string text in the total row
+  /// </summary>
+  public string TotalsRowLabel {
+    get => GetXmlNodeString("@totalsRowLabel");
+    set => SetXmlNodeString("@totalsRowLabel", value);
+  }
+
+  /// <summary>
+  /// Build-in total row functions.
+  /// To set a custom Total row formula use the TotalsRowFormula property
+  /// <seealso cref="TotalsRowFormula"/>
+  /// </summary>
+  public RowFunctions TotalsRowFunction {
+    get {
+      if (GetXmlNodeString("@totalsRowFunction") == "") {
+        return RowFunctions.None;
+      }
+      return (RowFunctions)
+        Enum.Parse(typeof(RowFunctions), GetXmlNodeString("@totalsRowFunction"), true);
+    }
+    set {
+      if (value == RowFunctions.Custom) {
+        throw (new("Use the TotalsRowFormula-property to set a custom table formula"));
+      }
+      string s = value.ToString();
+      s = s.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + s.Substring(1, s.Length - 1);
+      SetXmlNodeString("@totalsRowFunction", s);
+      _tbl.WorkSheet.SetTableTotalFunction(_tbl, this);
+    }
+  }
+
+  private const string _totalsrowformulaPath = "d:totalsRowFormula";
+
+  /// <summary>
+  /// Sets a custom Totals row Formula.
+  /// Be carefull with this property since it is not validated.
+  /// <example>
+  /// tbl.Columns[9].TotalsRowFormula = string.Format("SUM([{0}])",tbl.Columns[9].Name);
+  /// </example>
+  /// </summary>
+  public string TotalsRowFormula {
+    get => GetXmlNodeString(_totalsrowformulaPath);
+    set {
+      if (value.StartsWith("=")) {
+        value = value.Substring(1, value.Length - 1);
+      }
+      SetXmlNodeString("@totalsRowFunction", "custom");
+      SetXmlNodeString(_totalsrowformulaPath, value);
+      _tbl.WorkSheet.SetTableTotalFunction(_tbl, this);
+    }
+  }
+
+  private const string _datacellstylePath = "@dataCellStyle";
+
+  /// <summary>
+  /// The named style for datacells in the column
+  /// </summary>
+  public string DataCellStyleName {
+    get => GetXmlNodeString(_datacellstylePath);
+    set {
+      if (_tbl.WorkSheet.Workbook.Styles.NamedStyles.FindIndexById(value) < 0) {
+        throw (new(string.Format("Named style {0} does not exist.", value)));
+      }
+      SetXmlNodeString(TopNode, _datacellstylePath, value, true);
+
+      int fromRow = _tbl.Address._fromRow + (_tbl.ShowHeader ? 1 : 0),
+          toRow = _tbl.Address._toRow - (_tbl.ShowTotal ? 1 : 0),
+          col = _tbl.Address._fromCol + Position;
+
+      if (fromRow <= toRow) {
+        _tbl.WorkSheet.Cells[fromRow, col, toRow, col].StyleName = value;
+      }
+    }
+  }
+
+  private const string _calculatedcolumnformulaPath = "d:calculatedColumnFormula";
+
+  /// <summary>
+  /// Sets a calculated column Formula.
+  /// Be carefull with this property since it is not validated.
+  /// <example>
+  /// tbl.Columns[9].CalculatedColumnFormula = string.Format("SUM(MyDataTable[[#This Row],[{0}]])",tbl.Columns[9].Name);
+  /// </example>
+  /// </summary>
+  public string CalculatedColumnFormula {
+    get => GetXmlNodeString(_calculatedcolumnformulaPath);
+    set {
+      if (value.StartsWith("=")) {
+        value = value.Substring(1, value.Length - 1);
+      }
+      SetXmlNodeString(_calculatedcolumnformulaPath, value);
+    }
+  }
+}
diff --git a/AppsheetEpplus/Table/ExcelTableColumnCollection.cs b/AppsheetEpplus/Table/ExcelTableColumnCollection.cs
new file mode 100644
index 0000000..a465765
--- /dev/null
+++ b/AppsheetEpplus/Table/ExcelTableColumnCollection.cs
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		Added		30-AUG-2010
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// A collection of table columns
+/// </summary>
+public class ExcelTableColumnCollection : IEnumerable<ExcelTableColumn> {
+  private readonly List<ExcelTableColumn> _cols = new();
+  private readonly Dictionary<string, int> _colNames = new(
+      StringComparer.InvariantCultureIgnoreCase);
+
+  public ExcelTableColumnCollection(ExcelTable table) {
+    Table = table;
+    foreach (XmlNode node in table.TableXml.SelectNodes(
+        "//d:table/d:tableColumns/d:tableColumn",
+        table.NameSpaceManager)) {
+      _cols.Add(new(table.NameSpaceManager, node, table, _cols.Count));
+      _colNames.Add(_cols[_cols.Count - 1].Name, _cols.Count - 1);
+    }
+  }
+
+  /// <summary>
+  /// A reference to the table object
+  /// </summary>
+  public ExcelTable Table { get; private set; }
+
+  /// <summary>
+  /// Number of items in the collection
+  /// </summary>
+  public int Count => _cols.Count;
+
+  /// <summary>
+  /// The column Index. Base 0.
+  /// </summary>
+  /// <param name="index"></param>
+  /// <returns></returns>
+  public ExcelTableColumn this[int index] {
+    get {
+      if (index < 0 || index >= _cols.Count) {
+        throw (new ArgumentOutOfRangeException("Column index out of range"));
+      }
+      return _cols[index];
+    }
+  }
+
+  /// <summary>
+  /// Indexer
+  /// </summary>
+  /// <param name="name">The name of the table</param>
+  /// <returns>The table column. Null if the table name is not found in the collection</returns>
+  public ExcelTableColumn this[string name] {
+    get {
+      if (_colNames.ContainsKey(name)) {
+        return _cols[_colNames[name]];
+      }
+      return null;
+    }
+  }
+
+  IEnumerator<ExcelTableColumn> IEnumerable<ExcelTableColumn>.GetEnumerator() {
+    return _cols.GetEnumerator();
+  }
+
+  IEnumerator IEnumerable.GetEnumerator() {
+    return _cols.GetEnumerator();
+  }
+
+  internal string GetUniqueName(string name) {
+    if (_colNames.ContainsKey(name)) {
+      string newName;
+      var i = 2;
+      do {
+        newName = name + (i++).ToString(CultureInfo.InvariantCulture);
+      } while (_colNames.ContainsKey(newName));
+      return newName;
+    }
+    return name;
+  }
+}
diff --git a/AppsheetEpplus/Table/PivotTable/ExcelPivotCacheDefinition.cs b/AppsheetEpplus/Table/PivotTable/ExcelPivotCacheDefinition.cs
new file mode 100644
index 0000000..5a41248
--- /dev/null
+++ b/AppsheetEpplus/Table/PivotTable/ExcelPivotCacheDefinition.cs
@@ -0,0 +1,233 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		Added		21-MAR-2011
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System;
+using System.Linq;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+public enum eSourceType {
+  /// <summary>
+  /// Indicates that the cache contains data that consolidates ranges.
+  /// </summary>
+  Consolidation,
+
+  /// <summary>
+  /// Indicates that the cache contains data from an external data source.
+  /// </summary>
+  External,
+
+  /// <summary>
+  /// Indicates that the cache contains a scenario summary report
+  /// </summary>
+  Scenario,
+
+  /// <summary>
+  /// Indicates that the cache contains worksheet data
+  /// </summary>
+  Worksheet,
+}
+
+/// <summary>
+/// Cache definition. This class defines the source data. Note that one cache definition can be shared between many pivot tables.
+/// </summary>
+public class ExcelPivotCacheDefinition : XmlHelper {
+  internal ExcelPivotCacheDefinition(XmlNamespaceManager ns, ExcelPivotTable pivotTable)
+      : base(ns, null) {
+    foreach (var r in pivotTable.Part.GetRelationshipsByType(
+        ExcelPackage._schemaRelationships + "/pivotCacheDefinition")) {
+      Relationship = r;
+    }
+    CacheDefinitionUri = UriHelper.ResolvePartUri(Relationship.SourceUri, Relationship.TargetUri);
+
+    var pck = pivotTable.WorkSheet._package.Package;
+    Part = pck.GetPart(CacheDefinitionUri);
+    LoadXmlSafe(CacheDefinitionXml, Part.GetStream());
+
+    TopNode = CacheDefinitionXml.DocumentElement;
+    PivotTable = pivotTable;
+    if (CacheSource == eSourceType.Worksheet) {
+      var worksheetName = GetXmlNodeString(_sourceWorksheetPath);
+      if (pivotTable.WorkSheet.Workbook.Worksheets.Any(t => t.Name == worksheetName)) {
+        _sourceRange = pivotTable
+            .WorkSheet
+            .Workbook
+            .Worksheets[worksheetName].Cells[GetXmlNodeString(_sourceAddressPath)];
+      }
+    }
+  }
+
+  /// <summary>
+  /// Reference to the internal package part
+  /// </summary>
+  internal ZipPackagePart Part { get; set; }
+
+  /// <summary>
+  /// Provides access to the XML data representing the cache definition in the package.
+  /// </summary>
+  public XmlDocument CacheDefinitionXml { get; private set; } = new();
+
+  /// <summary>
+  /// The package internal URI to the pivottable cache definition Xml Document.
+  /// </summary>
+  public Uri CacheDefinitionUri { get; internal set; }
+
+  internal Uri CacheRecordUri { get; set; }
+
+  internal ZipPackageRelationship Relationship { get; set; }
+
+  internal ZipPackageRelationship RecordRelationship { get; set; }
+
+  internal string RecordRelationshipID {
+    get => GetXmlNodeString("@r:id");
+    set => SetXmlNodeString("@r:id", value);
+  }
+
+  /// <summary>
+  /// Referece to the PivoTable object
+  /// </summary>
+  public ExcelPivotTable PivotTable { get; private set; }
+
+  private const string _sourceWorksheetPath = "d:cacheSource/d:worksheetSource/@sheet";
+  private const string _sourceNamePath = "d:cacheSource/d:worksheetSource/@name";
+  private const string _sourceAddressPath = "d:cacheSource/d:worksheetSource/@ref";
+  internal ExcelRangeBase _sourceRange;
+
+  /// <summary>
+  /// The source data range when the pivottable has a worksheet datasource.
+  /// The number of columns in the range must be intact if this property is changed.
+  /// The range must be in the same workbook as the pivottable.
+  /// </summary>
+  public ExcelRangeBase SourceRange {
+    get {
+      if (_sourceRange == null) {
+        if (CacheSource == eSourceType.Worksheet) {
+          var ws = PivotTable.WorkSheet.Workbook.Worksheets[GetXmlNodeString(_sourceWorksheetPath)];
+          if (ws
+              == null) //Not worksheet, check name or table name
+          {
+            var name = GetXmlNodeString(_sourceNamePath);
+            foreach (var n in PivotTable.WorkSheet.Workbook.Names) {
+              if (name.Equals(n.Name, StringComparison.InvariantCultureIgnoreCase)) {
+                _sourceRange = n;
+                return _sourceRange;
+              }
+            }
+            foreach (var w in PivotTable.WorkSheet.Workbook.Worksheets) {
+              if (w.Tables._tableNames.ContainsKey(name)) {
+                _sourceRange = w.Cells[w.Tables[name].Address.Address];
+                break;
+              }
+              foreach (var n in w.Names) {
+                if (name.Equals(n.Name, StringComparison.InvariantCultureIgnoreCase)) {
+                  _sourceRange = n;
+                  break;
+                }
+              }
+            }
+          } else {
+            _sourceRange = ws.Cells[GetXmlNodeString(_sourceAddressPath)];
+          }
+        } else {
+          throw (new ArgumentException("The cachesource is not a worksheet"));
+        }
+      }
+      return _sourceRange;
+    }
+    set {
+      if (PivotTable.WorkSheet.Workbook != value.Worksheet.Workbook) {
+        throw (new ArgumentException("Range must be in the same package as the pivottable"));
+      }
+
+      var sr = SourceRange;
+      if (value.End.Column - value.Start.Column != sr.End.Column - sr.Start.Column) {
+        throw (new ArgumentException(
+                "Can not change the number of columns(fields) in the SourceRange"));
+      }
+
+      SetXmlNodeString(_sourceWorksheetPath, value.Worksheet.Name);
+      SetXmlNodeString(_sourceAddressPath, value.FirstAddress);
+      _sourceRange = value;
+    }
+  }
+
+  /// <summary>
+  /// Type of source data
+  /// </summary>
+  public eSourceType CacheSource {
+    get {
+      var s = GetXmlNodeString("d:cacheSource/@type");
+      if (s == "") {
+        return eSourceType.Worksheet;
+      }
+      return (eSourceType)Enum.Parse(typeof(eSourceType), s, true);
+    }
+  }
+
+  private string GetStartXml(ExcelRangeBase sourceAddress) {
+    string xml =
+        "<pivotCacheDefinition xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" r:id=\"\" refreshOnLoad=\"1\" refreshedBy=\"SomeUser\" refreshedDate=\"40504.582403125001\" createdVersion=\"1\" refreshedVersion=\"3\" recordCount=\"5\" upgradeOnRefresh=\"1\">";
+
+    xml += "<cacheSource type=\"worksheet\">";
+    xml += string.Format(
+        "<worksheetSource ref=\"{0}\" sheet=\"{1}\" /> ",
+        sourceAddress.Address,
+        sourceAddress.WorkSheet);
+    xml += "</cacheSource>";
+    xml += string.Format(
+        "<cacheFields count=\"{0}\">",
+        sourceAddress._toCol - sourceAddress._fromCol + 1);
+    var sourceWorksheet = PivotTable.WorkSheet.Workbook.Worksheets[sourceAddress.WorkSheet];
+    for (int col = sourceAddress._fromCol; col <= sourceAddress._toCol; col++) {
+      if (sourceWorksheet == null
+          || sourceWorksheet._values.GetValue(sourceAddress._fromRow, col) == null
+          || sourceWorksheet._values.GetValue(sourceAddress._fromRow, col).ToString().Trim()
+              == "") {
+        xml += string.Format(
+            "<cacheField name=\"Column{0}\" numFmtId=\"0\">",
+            col - sourceAddress._fromCol + 1);
+      } else {
+        xml += string.Format(
+            "<cacheField name=\"{0}\" numFmtId=\"0\">",
+            sourceWorksheet._values.GetValue(sourceAddress._fromRow, col));
+      }
+      //xml += "<sharedItems containsNonDate=\"0\" containsString=\"0\" containsBlank=\"1\" /> ";
+      xml += "<sharedItems containsBlank=\"1\" /> ";
+      xml += "</cacheField>";
+    }
+    xml += "</cacheFields>";
+    xml += "</pivotCacheDefinition>";
+
+    return xml;
+  }
+}
diff --git a/AppsheetEpplus/Table/PivotTable/ExcelPivotTable.cs b/AppsheetEpplus/Table/PivotTable/ExcelPivotTable.cs
new file mode 100644
index 0000000..b3590d7
--- /dev/null
+++ b/AppsheetEpplus/Table/PivotTable/ExcelPivotTable.cs
@@ -0,0 +1,643 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		Added		21-MAR-2011
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System;
+using System.Collections.Immutable;
+using System.Text.RegularExpressions;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// An Excel Pivottable
+/// </summary>
+public class ExcelPivotTable : XmlHelper {
+  protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
+    "location",
+    "pivotFields",
+    "rowFields",
+    "rowItems",
+    "colFields",
+    "colItems",
+    "pageFields",
+    "pageItems",
+    "dataFields",
+    "dataItems",
+    "formats",
+    "pivotTableStyleInfo",
+  ];
+
+  internal ExcelPivotTable(ZipPackageRelationship rel, ExcelWorksheet sheet)
+      : base(sheet.NameSpaceManager) {
+    WorkSheet = sheet;
+    PivotTableUri = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri);
+    Relationship = rel;
+    var package = sheet._package;
+    PivotTableXml = package.GetXmlDocument(PivotTableUri);
+    TopNode = PivotTableXml.DocumentElement;
+    Address = new(GetXmlNodeString("d:location/@ref"));
+
+    CacheDefinition = new(sheet.NameSpaceManager, this);
+    LoadFields();
+
+    //Add row fields.
+    foreach (XmlElement rowElem in TopNode.SelectNodes("d:rowFields/d:field", NameSpaceManager)) {
+      if (int.TryParse(rowElem.GetAttribute("x"), out var x) && x >= 0) {
+        RowFields.AddInternal(Fields[x]);
+      } else {
+        rowElem.ParentNode.RemoveChild(rowElem);
+      }
+    }
+
+    ////Add column fields.
+    foreach (XmlElement colElem in TopNode.SelectNodes("d:colFields/d:field", NameSpaceManager)) {
+      if (int.TryParse(colElem.GetAttribute("x"), out var x) && x >= 0) {
+        ColumnFields.AddInternal(Fields[x]);
+      } else {
+        colElem.ParentNode.RemoveChild(colElem);
+      }
+    }
+
+    //Add Page elements
+    //int index = 0;
+    foreach (XmlElement pageElem in TopNode.SelectNodes(
+        "d:pageFields/d:pageField",
+        NameSpaceManager)) {
+      if (int.TryParse(pageElem.GetAttribute("fld"), out var fld) && fld >= 0) {
+        var field = Fields[fld];
+        field._pageFieldSettings = new(NameSpaceManager, pageElem, field, fld);
+        PageFields.AddInternal(field);
+      }
+    }
+
+    //Add data elements
+    //index = 0;
+    foreach (XmlElement dataElem in TopNode.SelectNodes(
+        "d:dataFields/d:dataField",
+        NameSpaceManager)) {
+      if (int.TryParse(dataElem.GetAttribute("fld"), out var fld) && fld >= 0) {
+        var field = Fields[fld];
+        var dataField = new ExcelPivotTableDataField(NameSpaceManager, dataElem, field);
+        DataFields.AddInternal(dataField);
+      }
+    }
+  }
+
+  private void LoadFields() {
+    //Fields.Clear();
+    //int ix=0;
+    //foreach(XmlElement fieldNode in PivotXml.SelectNodes("//d:pivotFields/d:pivotField",NameSpaceManager))
+    //{
+    //    Fields.AddInternal(new ExcelPivotTableField(NameSpaceManager, fieldNode, this, ix++));
+    //}
+
+    int index = 0;
+    //Add fields.
+    foreach (XmlElement fieldElem in TopNode.SelectNodes(
+        "d:pivotFields/d:pivotField",
+        NameSpaceManager)) {
+      var fld = new ExcelPivotTableField(NameSpaceManager, fieldElem, this, index, index++);
+      Fields.AddInternal(fld);
+    }
+
+    //Add fields.
+    index = 0;
+    foreach (XmlElement fieldElem in CacheDefinition.TopNode.SelectNodes(
+        "d:cacheFields/d:cacheField",
+        NameSpaceManager)) {
+      var fld = Fields[index++];
+      fld.SetCacheFieldNode(fieldElem);
+    }
+  }
+
+  private XmlDocument GetStartXml(
+      string name,
+      int id,
+      ExcelAddressBase address,
+      ExcelAddressBase sourceAddress) {
+    string xml = $"""
+         <pivotTableDefinition xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" name="
+         {name}" cacheId="{id
+         }" dataOnRows="1" applyNumberFormats="0" applyBorderFormats="0" applyFontFormats="0" applyPatternFormats="0" applyAlignmentFormats="0" applyWidthHeightFormats="1" dataCaption="Data"  createdVersion="4" showMemberPropertyTips="0" useAutoFormatting="1" itemPrintTitles="1" indent="0" compact="0" compactData="0" gridDropZones="1">
+
+         """;
+    xml +=
+        $"""<location ref="{address.FirstAddress
+    }" firstHeaderRow="1" firstDataRow="1" firstDataCol="1" />""";
+    xml += $"""<pivotFields count="{sourceAddress._toCol - sourceAddress._fromCol + 1}">""";
+    for (int col = sourceAddress._fromCol; col <= sourceAddress._toCol; col++) {
+      xml += """<pivotField showAll="0" />""";
+    }
+    xml += "</pivotFields>";
+    xml +=
+        """<pivotTableStyleInfo name="PivotStyleMedium9" showRowHeaders="1" showColHeaders="1" showRowStripes="0" showColStripes="0" showLastColumn="1" />""";
+    xml += "</pivotTableDefinition>";
+    var result = new XmlDocument();
+    result.LoadXml(xml);
+    return result;
+  }
+
+  internal ZipPackagePart Part { get; }
+
+  /// <summary>
+  /// Provides access to the XML data representing the pivottable in the package.
+  /// </summary>
+  public XmlDocument PivotTableXml { get; private set; }
+
+  /// <summary>
+  /// The package internal URI to the pivottable Xml Document.
+  /// </summary>
+  public Uri PivotTableUri { get; internal set; }
+
+  internal ZipPackageRelationship Relationship { get; set; }
+
+  //const string ID_PATH = "@id";
+  //internal int Id
+  //{
+  //    get
+  //    {
+  //        return GetXmlNodeInt(ID_PATH);
+  //    }
+  //    set
+  //    {
+  //        SetXmlNodeString(ID_PATH, value.ToString());
+  //    }
+  //}
+  private const string _namePath = "@name";
+  private const string _displayNamePath = "@displayName";
+
+  /// <summary>
+  /// Name of the pivottable object in Excel
+  /// </summary>
+  public string Name {
+    get => GetXmlNodeString(_namePath);
+    set {
+      if (WorkSheet.Workbook.ExistsTableName(value)) {
+        throw (new ArgumentException("PivotTable name is not unique"));
+      }
+      string prevName = Name;
+      if (WorkSheet.Tables._tableNames.ContainsKey(prevName)) {
+        int ix = WorkSheet.Tables._tableNames[prevName];
+        WorkSheet.Tables._tableNames.Remove(prevName);
+        WorkSheet.Tables._tableNames.Add(value, ix);
+      }
+      SetXmlNodeString(_namePath, value);
+      SetXmlNodeString(_displayNamePath, CleanDisplayName(value));
+    }
+  }
+
+  /// <summary>
+  /// Reference to the pivot table cache definition object
+  /// </summary>
+  public ExcelPivotCacheDefinition CacheDefinition { get; }
+
+  private string CleanDisplayName(string name) {
+    return Regex.Replace(name, @"[^\w\.-_]", "_");
+  }
+
+  /// <summary>
+  /// The worksheet where the pivottable is located
+  /// </summary>
+  public ExcelWorksheet WorkSheet { get; set; }
+
+  /// <summary>
+  /// The location of the pivot table
+  /// </summary>
+  public ExcelAddressBase Address { get; internal set; }
+
+  /// <summary>
+  /// If multiple datafields are displayed in the row area or the column area
+  /// </summary>
+  public bool DataOnRows {
+    get => GetXmlNodeBool("@dataOnRows");
+    set => SetXmlNodeBool("@dataOnRows", value);
+  }
+
+  /// <summary>
+  /// if true apply legacy table autoformat number format properties.
+  /// </summary>
+  public bool ApplyNumberFormats {
+    get => GetXmlNodeBool("@applyNumberFormats");
+    set => SetXmlNodeBool("@applyNumberFormats", value);
+  }
+
+  /// <summary>
+  /// If true apply legacy table autoformat border properties
+  /// </summary>
+  public bool ApplyBorderFormats {
+    get => GetXmlNodeBool("@applyBorderFormats");
+    set => SetXmlNodeBool("@applyBorderFormats", value);
+  }
+
+  /// <summary>
+  /// If true apply legacy table autoformat font properties
+  /// </summary>
+  public bool ApplyFontFormats {
+    get => GetXmlNodeBool("@applyFontFormats");
+    set => SetXmlNodeBool("@applyFontFormats", value);
+  }
+
+  /// <summary>
+  /// If true apply legacy table autoformat pattern properties
+  /// </summary>
+  public bool ApplyPatternFormats {
+    get => GetXmlNodeBool("@applyPatternFormats");
+    set => SetXmlNodeBool("@applyPatternFormats", value);
+  }
+
+  /// <summary>
+  /// If true apply legacy table autoformat width/height properties.
+  /// </summary>
+  public bool ApplyWidthHeightFormats {
+    get => GetXmlNodeBool("@applyWidthHeightFormats");
+    set => SetXmlNodeBool("@applyWidthHeightFormats", value);
+  }
+
+  /// <summary>
+  /// Show member property information
+  /// </summary>
+  public bool ShowMemberPropertyTips {
+    get => GetXmlNodeBool("@showMemberPropertyTips");
+    set => SetXmlNodeBool("@showMemberPropertyTips", value);
+  }
+
+  /// <summary>
+  /// Show the drill indicators
+  /// </summary>
+  public bool ShowCalcMember {
+    get => GetXmlNodeBool("@showCalcMbrs");
+    set => SetXmlNodeBool("@showCalcMbrs", value);
+  }
+
+  /// <summary>
+  /// If the user is prevented from drilling down on a PivotItem or aggregate value
+  /// </summary>
+  public bool EnableDrill {
+    get => GetXmlNodeBool("@enableDrill", true);
+    set => SetXmlNodeBool("@enableDrill", value);
+  }
+
+  /// <summary>
+  /// Show the drill down buttons
+  /// </summary>
+  public bool ShowDrill {
+    get => GetXmlNodeBool("@showDrill", true);
+    set => SetXmlNodeBool("@showDrill", value);
+  }
+
+  /// <summary>
+  /// If the tooltips should be displayed for PivotTable data cells.
+  /// </summary>
+  public bool ShowDataTips {
+    get => GetXmlNodeBool("@showDataTips", true);
+    set => SetXmlNodeBool("@showDataTips", value, true);
+  }
+
+  /// <summary>
+  /// If the row and column titles from the PivotTable should be printed.
+  /// </summary>
+  public bool FieldPrintTitles {
+    get => GetXmlNodeBool("@fieldPrintTitles");
+    set => SetXmlNodeBool("@fieldPrintTitles", value);
+  }
+
+  /// <summary>
+  /// If the row and column titles from the PivotTable should be printed.
+  /// </summary>
+  public bool ItemPrintTitles {
+    get => GetXmlNodeBool("@itemPrintTitles");
+    set => SetXmlNodeBool("@itemPrintTitles", value);
+  }
+
+  /// <summary>
+  /// If the grand totals should be displayed for the PivotTable columns
+  /// </summary>
+  public bool ColumGrandTotals {
+    get => GetXmlNodeBool("@colGrandTotals");
+    set => SetXmlNodeBool("@colGrandTotals", value);
+  }
+
+  /// <summary>
+  /// If the grand totals should be displayed for the PivotTable rows
+  /// </summary>
+  public bool RowGrandTotals {
+    get => GetXmlNodeBool("@rowGrandTotals");
+    set => SetXmlNodeBool("@rowGrandTotals", value);
+  }
+
+  /// <summary>
+  /// If the drill indicators expand collapse buttons should be printed.
+  /// </summary>
+  public bool PrintDrill {
+    get => GetXmlNodeBool("@printDrill");
+    set => SetXmlNodeBool("@printDrill", value);
+  }
+
+  /// <summary>
+  /// Indicates whether to show error messages in cells.
+  /// </summary>
+  public bool ShowError {
+    get => GetXmlNodeBool("@showError");
+    set => SetXmlNodeBool("@showError", value);
+  }
+
+  /// <summary>
+  /// The string to be displayed in cells that contain errors.
+  /// </summary>
+  public string ErrorCaption {
+    get => GetXmlNodeString("@errorCaption");
+    set => SetXmlNodeString("@errorCaption", value);
+  }
+
+  /// <summary>
+  /// Specifies the name of the value area field header in the PivotTable.
+  /// This caption is shown when the PivotTable when two or more fields are in the values area.
+  /// </summary>
+  public string DataCaption {
+    get => GetXmlNodeString("@dataCaption");
+    set => SetXmlNodeString("@dataCaption", value);
+  }
+
+  /// <summary>
+  /// Show field headers
+  /// </summary>
+  public bool ShowHeaders {
+    get => GetXmlNodeBool("@showHeaders");
+    set => SetXmlNodeBool("@showHeaders", value);
+  }
+
+  /// <summary>
+  /// The number of page fields to display before starting another row or column
+  /// </summary>
+  public int PageWrap {
+    get => GetXmlNodeInt("@pageWrap");
+    set {
+      if (value < 0) {
+        throw new("Value can't be negative");
+      }
+      SetXmlNodeString("@pageWrap", value.ToString());
+    }
+  }
+
+  /// <summary>
+  /// A boolean that indicates whether legacy auto formatting has been applied to the PivotTable view
+  /// </summary>
+  public bool UseAutoFormatting {
+    get => GetXmlNodeBool("@useAutoFormatting");
+    set => SetXmlNodeBool("@useAutoFormatting", value);
+  }
+
+  /// <summary>
+  /// A boolean that indicates whether the in-grid drop zones should be displayed at runtime, and whether classic layout is applied
+  /// </summary>
+  public bool GridDropZones {
+    get => GetXmlNodeBool("@gridDropZones");
+    set => SetXmlNodeBool("@gridDropZones", value);
+  }
+
+  /// <summary>
+  /// Specifies the indentation increment for compact axis and can be used to set the Report Layout to Compact Form
+  /// </summary>
+  public int Indent {
+    get => GetXmlNodeInt("@indent");
+    set => SetXmlNodeString("@indent", value.ToString());
+  }
+
+  /// <summary>
+  /// A boolean that indicates whether data fields in the PivotTable should be displayed in outline form
+  /// </summary>
+  public bool OutlineData {
+    get => GetXmlNodeBool("@outlineData");
+    set => SetXmlNodeBool("@outlineData", value);
+  }
+
+  /// <summary>
+  /// a boolean that indicates whether new fields should have their outline flag set to true
+  /// </summary>
+  public bool Outline {
+    get => GetXmlNodeBool("@outline");
+    set => SetXmlNodeBool("@outline", value);
+  }
+
+  /// <summary>
+  /// A boolean that indicates whether the fields of a PivotTable can have multiple filters set on them
+  /// </summary>
+  public bool MultipleFieldFilters {
+    get => GetXmlNodeBool("@multipleFieldFilters");
+    set => SetXmlNodeBool("@multipleFieldFilters", value);
+  }
+
+  /// <summary>
+  /// A boolean that indicates whether new fields should have their compact flag set to true
+  /// </summary>
+  public bool Compact {
+    get => GetXmlNodeBool("@compact");
+    set => SetXmlNodeBool("@compact", value);
+  }
+
+  /// <summary>
+  /// A boolean that indicates whether the field next to the data field in the PivotTable should be displayed in the same column of the spreadsheet
+  /// </summary>
+  public bool CompactData {
+    get => GetXmlNodeBool("@compactData");
+    set => SetXmlNodeBool("@compactData", value);
+  }
+
+  /// <summary>
+  /// Specifies the string to be displayed for grand totals.
+  /// </summary>
+  public string GrandTotalCaption {
+    get => GetXmlNodeString("@grandTotalCaption");
+    set => SetXmlNodeString("@grandTotalCaption", value);
+  }
+
+  /// <summary>
+  /// Specifies the string to be displayed in row header in compact mode.
+  /// </summary>
+  public string RowHeaderCaption {
+    get => GetXmlNodeString("@rowHeaderCaption");
+    set => SetXmlNodeString("@rowHeaderCaption", value);
+  }
+
+  /// <summary>
+  /// Specifies the string to be displayed in cells with no value
+  /// </summary>
+  public string MissingCaption {
+    get => GetXmlNodeString("@missingCaption");
+    set => SetXmlNodeString("@missingCaption", value);
+  }
+
+  private const string _firstheaderrowPath = "d:location/@firstHeaderRow";
+
+  /// <summary>
+  /// Specifies the first row of the PivotTable header, relative to the top left cell in the ref value
+  /// </summary>
+  public int FirstHeaderRow {
+    get => GetXmlNodeInt(_firstheaderrowPath);
+    set => SetXmlNodeString(_firstheaderrowPath, value.ToString());
+  }
+
+  private const string _firstdatarowPath = "d:location/@firstDataRow";
+
+  /// <summary>
+  /// Specifies the first column of the PivotTable data, relative to the top left cell in the ref value
+  /// </summary>
+  public int FirstDataRow {
+    get => GetXmlNodeInt(_firstdatarowPath);
+    set => SetXmlNodeString(_firstdatarowPath, value.ToString());
+  }
+
+  private const string _firstdatacolPath = "d:location/@firstDataCol";
+
+  /// <summary>
+  /// Specifies the first column of the PivotTable data, relative to the top left cell in the ref value
+  /// </summary>
+  public int FirstDataCol {
+    get => GetXmlNodeInt(_firstdatacolPath);
+    set => SetXmlNodeString(_firstdatacolPath, value.ToString());
+  }
+
+  private ExcelPivotTableFieldCollection _fields;
+
+  /// <summary>
+  /// The fields in the table
+  /// </summary>
+  public ExcelPivotTableFieldCollection Fields {
+    get {
+      if (_fields == null) {
+        _fields = new(this, "");
+      }
+      return _fields;
+    }
+  }
+
+  private ExcelPivotTableRowColumnFieldCollection _rowFields;
+
+  /// <summary>
+  /// Row label fields
+  /// </summary>
+  public ExcelPivotTableRowColumnFieldCollection RowFields {
+    get {
+      if (_rowFields == null) {
+        _rowFields = new(this, "rowFields");
+      }
+      return _rowFields;
+    }
+  }
+
+  private ExcelPivotTableRowColumnFieldCollection _columnFields;
+
+  /// <summary>
+  /// Column label fields
+  /// </summary>
+  public ExcelPivotTableRowColumnFieldCollection ColumnFields {
+    get {
+      if (_columnFields == null) {
+        _columnFields = new(this, "colFields");
+      }
+      return _columnFields;
+    }
+  }
+
+  private ExcelPivotTableDataFieldCollection _dataFields;
+
+  /// <summary>
+  /// Value fields
+  /// </summary>
+  public ExcelPivotTableDataFieldCollection DataFields {
+    get {
+      if (_dataFields == null) {
+        _dataFields = new(this);
+      }
+      return _dataFields;
+    }
+  }
+
+  private ExcelPivotTableRowColumnFieldCollection _pageFields;
+
+  /// <summary>
+  /// Report filter fields
+  /// </summary>
+  public ExcelPivotTableRowColumnFieldCollection PageFields {
+    get {
+      if (_pageFields == null) {
+        _pageFields = new(this, "pageFields");
+      }
+      return _pageFields;
+    }
+  }
+
+  private const string _stylenamePath = "d:pivotTableStyleInfo/@name";
+
+  /// <summary>
+  /// Pivot style name. Used for custom styles
+  /// </summary>
+  public string StyleName {
+    get => GetXmlNodeString(_stylenamePath);
+    set {
+      if (value.StartsWith("PivotStyle")) {
+        try {
+          _tableStyle = (TableStyles)
+            Enum.Parse(typeof(TableStyles), value.Substring(10, value.Length - 10), true);
+        } catch {
+          _tableStyle = TableStyles.Custom;
+        }
+      } else if (value == "None") {
+        _tableStyle = TableStyles.None;
+        value = "";
+      } else {
+        _tableStyle = TableStyles.Custom;
+      }
+      SetXmlNodeString(_stylenamePath, value, true);
+    }
+  }
+
+  private TableStyles _tableStyle = TableStyles.Medium6;
+
+  /// <summary>
+  /// The table style. If this property is cusom the style from the StyleName propery is used.
+  /// </summary>
+  public TableStyles TableStyle {
+    get => _tableStyle;
+    set {
+      _tableStyle = value;
+      if (value != TableStyles.Custom) {
+        SetXmlNodeString(_stylenamePath, "PivotStyle" + value);
+      }
+    }
+  }
+
+  internal int CacheID {
+    get => GetXmlNodeInt("@cacheId");
+    set => SetXmlNodeString("@cacheId", value.ToString());
+  }
+}
diff --git a/AppsheetEpplus/Table/PivotTable/ExcelPivotTableCollection.cs b/AppsheetEpplus/Table/PivotTable/ExcelPivotTableCollection.cs
new file mode 100644
index 0000000..702107c
--- /dev/null
+++ b/AppsheetEpplus/Table/PivotTable/ExcelPivotTableCollection.cs
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		Added		21-MAR-2011
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// A collection of pivottable objects
+/// </summary>
+public class ExcelPivotTableCollection : IEnumerable<ExcelPivotTable> {
+  private readonly List<ExcelPivotTable> _pivotTables = new();
+  internal readonly Dictionary<string, int> _pivotTableNames = new();
+
+  internal ExcelPivotTableCollection(ExcelWorksheet ws) {
+    foreach (var rel in ws.Part.GetRelationships()) {
+      if (rel.RelationshipType == ExcelPackage._schemaRelationships + "/pivotTable") {
+        var tbl = new ExcelPivotTable(rel, ws);
+        _pivotTableNames.Add(tbl.Name, _pivotTables.Count);
+        _pivotTables.Add(tbl);
+      }
+    }
+  }
+
+  public int Count => _pivotTables.Count;
+
+  /// <summary>
+  /// The pivottable Index. Base 0.
+  /// </summary>
+  /// <param name="index"></param>
+  /// <returns></returns>
+  public ExcelPivotTable this[int index] {
+    get {
+      if (index < 0 || index >= _pivotTables.Count) {
+        throw (new ArgumentOutOfRangeException("PivotTable index out of range"));
+      }
+      return _pivotTables[index];
+    }
+  }
+
+  /// <summary>
+  /// Pivottabes accesed by name
+  /// </summary>
+  /// <param name="name">The name of the pivottable</param>
+  /// <returns>The Pivotable. Null if the no match is found</returns>
+  public ExcelPivotTable this[string name] {
+    get {
+      if (_pivotTableNames.ContainsKey(name)) {
+        return _pivotTables[_pivotTableNames[name]];
+      }
+      return null;
+    }
+  }
+
+  public IEnumerator<ExcelPivotTable> GetEnumerator() {
+    return _pivotTables.GetEnumerator();
+  }
+
+  IEnumerator IEnumerable.GetEnumerator() {
+    return _pivotTables.GetEnumerator();
+  }
+}
diff --git a/AppsheetEpplus/Table/PivotTable/ExcelPivotTableDataField.cs b/AppsheetEpplus/Table/PivotTable/ExcelPivotTableDataField.cs
new file mode 100644
index 0000000..1e1b955
--- /dev/null
+++ b/AppsheetEpplus/Table/PivotTable/ExcelPivotTableDataField.cs
@@ -0,0 +1,189 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		Added		21-MAR-2011
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System;
+using System.Globalization;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// A pivo table data field
+/// </summary>
+public class ExcelPivotTableDataField : XmlHelper {
+  internal ExcelPivotTableDataField(
+      XmlNamespaceManager ns,
+      XmlNode topNode,
+      ExcelPivotTableField field)
+      : base(ns, topNode) {
+    if (topNode.Attributes.Count == 0) {
+      Index = field.Index;
+      BaseField = 0;
+      BaseItem = 0;
+    }
+
+    Field = field;
+  }
+
+  /// <summary>
+  /// The field
+  /// </summary>
+  public ExcelPivotTableField Field { get; private set; }
+
+  /// <summary>
+  /// The index of the datafield
+  /// </summary>
+  public int Index {
+    get => GetXmlNodeInt("@fld");
+    internal set => SetXmlNodeString("@fld", value.ToString());
+  }
+
+  /// <summary>
+  /// The name of the datafield
+  /// </summary>
+  public string Name {
+    get => GetXmlNodeString("@name");
+    set {
+      if (Field._table.DataFields.ExistsDfName(value, this)) {
+        throw (new InvalidOperationException("Duplicate datafield name"));
+      }
+      SetXmlNodeString("@name", value);
+    }
+  }
+
+  /// <summary>
+  /// Field index. Reference to the field collection
+  /// </summary>
+  public int BaseField {
+    get => GetXmlNodeInt("@baseField");
+    set => SetXmlNodeString("@baseField", value.ToString());
+  }
+
+  /// <summary>
+  /// Specifies the index to the base item when the ShowDataAs calculation is in use
+  /// </summary>
+  public int BaseItem {
+    get => GetXmlNodeInt("@baseItem");
+    set => SetXmlNodeString("@baseItem", value.ToString());
+  }
+
+  /// <summary>
+  /// Number format id.
+  /// </summary>
+  internal int NumFmtId {
+    get => GetXmlNodeInt("@numFmtId");
+    set => SetXmlNodeString("@numFmtId", value.ToString());
+  }
+
+  /// <summary>
+  /// Number format for the data column
+  /// </summary>
+  public string Format {
+    get {
+      foreach (var nf in Field._table.WorkSheet.Workbook.Styles.NumberFormats) {
+        if (nf.NumFmtId == NumFmtId) {
+          return nf.Format;
+        }
+      }
+      return Field._table.WorkSheet.Workbook.Styles.NumberFormats[0].Format;
+    }
+    set {
+      var styles = Field._table.WorkSheet.Workbook.Styles;
+
+      ExcelNumberFormatXml nf = null;
+      if (!styles.NumberFormats.FindById(value, ref nf)) {
+        nf = new(NameSpaceManager) {
+          Format = value,
+          NumFmtId = styles.NumberFormats.NextId++,
+        };
+        styles.NumberFormats.Add(value, nf);
+      }
+      NumFmtId = nf.NumFmtId;
+    }
+  }
+
+  /// <summary>
+  /// Type of aggregate function
+  /// </summary>
+  public DataFieldFunctions Function {
+    get {
+      string s = GetXmlNodeString("@subtotal");
+      if (s == "") {
+        return DataFieldFunctions.None;
+      }
+      return (DataFieldFunctions)Enum.Parse(typeof(DataFieldFunctions), s, true);
+    }
+    set {
+      string v;
+      switch (value) {
+        case DataFieldFunctions.None:
+          DeleteNode("@subtotal");
+          return;
+        case DataFieldFunctions.CountNums:
+          v = "CountNums";
+          break;
+        case DataFieldFunctions.StdDev:
+          v = "stdDev";
+          break;
+        case DataFieldFunctions.StdDevP:
+          v = "stdDevP";
+          break;
+        default:
+          v = value.ToString().ToLower(CultureInfo.InvariantCulture);
+          break;
+      }
+      SetXmlNodeString("@subtotal", v);
+    }
+  }
+  /////Since we have no items, Excel will crash when we use showDataAs options that require baseItem's
+  //public eShowDataAs ShowDataAs
+  //{
+  //    get
+  //    {
+  //        string s = GetXmlNodeString("@showDataAs");
+  //        if (s == "")
+  //        {
+  //            return eShowDataAs.Normal;
+  //        }
+  //        else
+  //        {
+  //            return (eShowDataAs)Enum.Parse(typeof(eShowDataAs), s, true);
+  //        }
+  //    }
+  //    set
+  //    {
+  //        string v = value.ToString();
+  //        v = v.Substring(0, 1).ToLower() + v.Substring(1);
+  //        SetXmlNodeString("@showDataAs", v);
+  //    }
+  //}
+}
diff --git a/AppsheetEpplus/Table/PivotTable/ExcelPivotTableField.cs b/AppsheetEpplus/Table/PivotTable/ExcelPivotTableField.cs
new file mode 100644
index 0000000..993277e
--- /dev/null
+++ b/AppsheetEpplus/Table/PivotTable/ExcelPivotTableField.cs
@@ -0,0 +1,566 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		Added		21-MAR-2011
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System;
+using System.Globalization;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Defines the axis for a PivotTable
+/// </summary>
+public enum ePivotFieldAxis {
+  /// <summary>
+  /// None
+  /// </summary>
+  None = -1,
+
+  /// <summary>
+  /// Column axis
+  /// </summary>
+  Column,
+
+  /// <summary>
+  /// Page axis (Include Count Filter)
+  ///
+  /// </summary>
+  Page,
+
+  /// <summary>
+  /// Row axis
+  /// </summary>
+  Row,
+
+  /// <summary>
+  /// Values axis
+  /// </summary>
+  Values,
+}
+
+/// <summary>
+/// Build-in table row functions
+/// </summary>
+public enum DataFieldFunctions {
+  Average,
+  Count,
+  CountNums,
+  Max,
+  Min,
+  Product,
+  None,
+  StdDev,
+  StdDevP,
+  Sum,
+  Var,
+  VarP,
+}
+
+/// <summary>
+/// Defines the data formats for a field in the PivotTable
+/// </summary>
+public enum eShowDataAs {
+  /// <summary>
+  /// Indicates the field is shown as the "difference from" a value.
+  /// </summary>
+  Difference,
+
+  /// <summary>
+  /// Indicates the field is shown as the "index.
+  /// </summary>
+  Index,
+
+  /// <summary>
+  /// Indicates that the field is shown as its normal datatype.
+  /// </summary>
+  Normal,
+
+  /// <summary>
+  /// /Indicates the field is show as the "percentage of" a value
+  /// </summary>
+  Percent,
+
+  /// <summary>
+  /// Indicates the field is shown as the "percentage difference from" a value.
+  /// </summary>
+  PercentDiff,
+
+  /// <summary>
+  /// Indicates the field is shown as the percentage of column.
+  /// </summary>
+  PercentOfCol,
+
+  /// <summary>
+  /// Indicates the field is shown as the percentage of row
+  /// </summary>
+  PercentOfRow,
+
+  /// <summary>
+  /// Indicates the field is shown as percentage of total.
+  /// </summary>
+  PercentOfTotal,
+
+  /// <summary>
+  /// Indicates the field is shown as running total in the table.
+  /// </summary>
+  RunTotal,
+}
+
+/// <summary>
+/// Built-in subtotal functions
+/// </summary>
+[Flags]
+public enum eSubTotalFunctions {
+  None = 1,
+  Count = 2,
+  CountA = 4,
+  Avg = 8,
+  Default = 16,
+  Min = 32,
+  Max = 64,
+  Product = 128,
+  StdDev = 256,
+  StdDevP = 512,
+  Sum = 1024,
+  Var = 2048,
+  VarP = 4096,
+}
+
+/// <summary>
+/// Data grouping
+/// </summary>
+[Flags]
+public enum eDateGroupBy {
+  Years = 1,
+  Quarters = 2,
+  Months = 4,
+  Days = 8,
+  Hours = 16,
+  Minutes = 32,
+  Seconds = 64,
+}
+
+/// <summary>
+/// Sorting
+/// </summary>
+public enum eSortType {
+  None,
+  Ascending,
+  Descending,
+}
+
+/// <summary>
+/// A pivot table field.
+/// </summary>
+public class ExcelPivotTableField : XmlHelper {
+  internal ExcelPivotTable _table;
+
+  internal ExcelPivotTableField(
+      XmlNamespaceManager ns,
+      XmlNode topNode,
+      ExcelPivotTable table,
+      int index,
+      int baseIndex)
+      : base(ns, topNode) {
+    Index = index;
+    BaseIndex = baseIndex;
+    _table = table;
+  }
+
+  public int Index { get; set; }
+
+  internal int BaseIndex { get; set; }
+
+  /// <summary>
+  /// Name of the field
+  /// </summary>
+  public string Name {
+    get {
+      string v = GetXmlNodeString("@name");
+      if (v == "") {
+        return _cacheFieldHelper.GetXmlNodeString("@name");
+      }
+      return v;
+    }
+    set => SetXmlNodeString("@name", value);
+  }
+
+  /// <summary>
+  /// Compact mode
+  /// </summary>
+  public bool Compact {
+    get => GetXmlNodeBool("@compact");
+    set => SetXmlNodeBool("@compact", value);
+  }
+
+  /// <summary>
+  /// A boolean that indicates whether the items in this field should be shown in Outline form
+  /// </summary>
+  public bool Outline {
+    get => GetXmlNodeBool("@outline");
+    set => SetXmlNodeBool("@outline", value);
+  }
+
+  /// <summary>
+  /// The custom text that is displayed for the subtotals label
+  /// </summary>
+  public bool SubtotalTop {
+    get => GetXmlNodeBool("@subtotalTop");
+    set => SetXmlNodeBool("@subtotalTop", value);
+  }
+
+  /// <summary>
+  /// A boolean that indicates whether to show all items for this field
+  /// </summary>
+  public bool ShowAll {
+    get => GetXmlNodeBool("@showAll");
+    set => SetXmlNodeBool("@showAll", value);
+  }
+
+  /// <summary>
+  /// The type of sort that is applied to this field
+  /// </summary>
+  public eSortType Sort {
+    get {
+      string v = GetXmlNodeString("@sortType");
+      return v == "" ? eSortType.None : (eSortType)Enum.Parse(typeof(eSortType), v, true);
+    }
+    set {
+      if (value == eSortType.None) {
+        DeleteNode("@sortType");
+      } else {
+        SetXmlNodeString("@sortType", value.ToString().ToLower(CultureInfo.InvariantCulture));
+      }
+    }
+  }
+
+  /// <summary>
+  /// A boolean that indicates whether manual filter is in inclusive mode
+  /// </summary>
+  public bool IncludeNewItemsInFilter {
+    get => GetXmlNodeBool("@includeNewItemsInFilter");
+    set => SetXmlNodeBool("@includeNewItemsInFilter", value);
+  }
+
+  /// <summary>
+  /// Enumeration of the different subtotal operations that can be applied to page, row or column fields
+  /// </summary>
+  public eSubTotalFunctions SubTotalFunctions {
+    get {
+      eSubTotalFunctions ret = 0;
+      XmlNodeList nl = TopNode.SelectNodes("d:items/d:item/@t", NameSpaceManager);
+      if (nl.Count == 0) {
+        return eSubTotalFunctions.None;
+      }
+      foreach (XmlAttribute item in nl) {
+        try {
+          ret |= (eSubTotalFunctions)Enum.Parse(typeof(eSubTotalFunctions), item.Value, true);
+        } catch (ArgumentException ex) {
+          throw new ArgumentException(
+              "Unable to parse value of "
+                  + item.Value
+                  + " to a valid pivot table subtotal function",
+              ex);
+        }
+      }
+      return ret;
+    }
+    set {
+      if ((value & eSubTotalFunctions.None) == eSubTotalFunctions.None
+          && (value != eSubTotalFunctions.None)) {
+        throw (new ArgumentException("Value None can not be combined with other values."));
+      }
+      if ((value & eSubTotalFunctions.Default) == eSubTotalFunctions.Default
+          && (value != eSubTotalFunctions.Default)) {
+        throw (new ArgumentException("Value Default can not be combined with other values."));
+      }
+
+      // remove old attribute
+      XmlNodeList nl = TopNode.SelectNodes("d:items/d:item/@t", NameSpaceManager);
+      if (nl.Count > 0) {
+        foreach (XmlAttribute item in nl) {
+          DeleteNode("@" + item.Value + "Subtotal");
+          item.OwnerElement.ParentNode.RemoveChild(item.OwnerElement);
+        }
+      }
+
+      if (value == eSubTotalFunctions.None) {
+        // for no subtotals, set defaultSubtotal to off
+        SetXmlNodeBool("@defaultSubtotal", false);
+        TopNode.InnerXml = "";
+      } else {
+        string innerXml = "";
+        int count = 0;
+        foreach (eSubTotalFunctions e in Enum.GetValues(typeof(eSubTotalFunctions))) {
+          if ((value & e) == e) {
+            var newTotalType = e.ToString();
+            var totalType =
+                char.ToLower(newTotalType[0], CultureInfo.InvariantCulture)
+                    + newTotalType.Substring(1);
+            // add new attribute
+            SetXmlNodeBool("@" + totalType + "Subtotal", true);
+            innerXml += "<item t=\"" + totalType + "\" />";
+            count++;
+          }
+        }
+        TopNode.InnerXml = string.Format("<items count=\"{0}\">{1}</items>", count, innerXml);
+      }
+    }
+  }
+
+  /// <summary>
+  /// Type of axis
+  /// </summary>
+  public ePivotFieldAxis Axis {
+    get {
+      switch (GetXmlNodeString("@axis")) {
+        case "axisRow":
+          return ePivotFieldAxis.Row;
+        case "axisCol":
+          return ePivotFieldAxis.Column;
+        case "axisPage":
+          return ePivotFieldAxis.Page;
+        case "axisValues":
+          return ePivotFieldAxis.Values;
+        default:
+          return ePivotFieldAxis.None;
+      }
+    }
+    internal set {
+      switch (value) {
+        case ePivotFieldAxis.Row:
+          SetXmlNodeString("@axis", "axisRow");
+          break;
+        case ePivotFieldAxis.Column:
+          SetXmlNodeString("@axis", "axisCol");
+          break;
+        case ePivotFieldAxis.Values:
+          SetXmlNodeString("@axis", "axisValues");
+          break;
+        case ePivotFieldAxis.Page:
+          SetXmlNodeString("@axis", "axisPage");
+          break;
+        default:
+          DeleteNode("@axis");
+          break;
+      }
+    }
+  }
+
+  /// <summary>
+  /// If the field is a row field
+  /// </summary>
+  public bool IsRowField {
+    get =>
+      (TopNode.SelectSingleNode(
+              string.Format("../../d:rowFields/d:field[@x={0}]", Index),
+              NameSpaceManager) != null);
+    internal set {
+      if (value) {
+        var rowsNode = TopNode.SelectSingleNode("../../d:rowFields", NameSpaceManager);
+        if (rowsNode == null) {
+          _table.CreateNode("d:rowFields");
+        }
+        rowsNode = TopNode.SelectSingleNode("../../d:rowFields", NameSpaceManager);
+
+        AppendField(rowsNode, Index, "field", "x");
+        if (BaseIndex == Index) {
+          TopNode.InnerXml = "<items count=\"1\"><item t=\"default\" /></items>";
+        } else {
+          TopNode.InnerXml = "<items count=\"0\"></items>";
+        }
+      } else {
+        XmlElement node =
+            TopNode.SelectSingleNode(
+                string.Format("../../d:rowFields/d:field[@x={0}]", Index),
+                NameSpaceManager) as XmlElement;
+        if (node != null) {
+          node.ParentNode.RemoveChild(node);
+        }
+      }
+    }
+  }
+
+  /// <summary>
+  /// If the field is a column field
+  /// </summary>
+  public bool IsColumnField {
+    get =>
+      (TopNode.SelectSingleNode(
+              string.Format("../../d:colFields/d:field[@x={0}]", Index),
+              NameSpaceManager) != null);
+    internal set {
+      if (value) {
+        var columnsNode = TopNode.SelectSingleNode("../../d:colFields", NameSpaceManager);
+        if (columnsNode == null) {
+          _table.CreateNode("d:colFields");
+        }
+        columnsNode = TopNode.SelectSingleNode("../../d:colFields", NameSpaceManager);
+
+        AppendField(columnsNode, Index, "field", "x");
+        if (BaseIndex == Index) {
+          TopNode.InnerXml = "<items count=\"1\"><item t=\"default\" /></items>";
+        } else {
+          TopNode.InnerXml = "<items count=\"0\"></items>";
+        }
+      } else {
+        XmlElement node =
+            TopNode.SelectSingleNode(
+                string.Format("../../d:colFields/d:field[@x={0}]", Index),
+                NameSpaceManager) as XmlElement;
+        if (node != null) {
+          node.ParentNode.RemoveChild(node);
+        }
+      }
+    }
+  }
+
+  /// <summary>
+  /// If the field is a datafield
+  /// </summary>
+  public bool IsDataField => GetXmlNodeBool("@dataField", false);
+
+  /// <summary>
+  /// If the field is a page field.
+  /// </summary>
+  public bool IsPageField {
+    get => (Axis == ePivotFieldAxis.Page);
+    internal set {
+      if (value) {
+        var dataFieldsNode = TopNode.SelectSingleNode("../../d:pageFields", NameSpaceManager);
+        if (dataFieldsNode == null) {
+          _table.CreateNode("d:pageFields");
+          dataFieldsNode = TopNode.SelectSingleNode("../../d:pageFields", NameSpaceManager);
+        }
+
+        TopNode.InnerXml = "<items count=\"1\"><item t=\"default\" /></items>";
+
+        XmlElement node = AppendField(dataFieldsNode, Index, "pageField", "fld");
+        _pageFieldSettings = new(NameSpaceManager, node, this, Index);
+      } else {
+        _pageFieldSettings = null;
+        XmlElement node =
+            TopNode.SelectSingleNode(
+                string.Format("../../d:pageFields/d:pageField[@fld={0}]", Index),
+                NameSpaceManager) as XmlElement;
+        if (node != null) {
+          node.ParentNode.RemoveChild(node);
+        }
+      }
+    }
+  }
+
+  //public ExcelPivotGrouping DateGrouping
+  //{
+
+  //}
+  internal ExcelPivotTablePageFieldSettings _pageFieldSettings;
+
+  public ExcelPivotTablePageFieldSettings PageFieldSettings => _pageFieldSettings;
+
+  internal eDateGroupBy DateGrouping { get; set; }
+
+  private ExcelPivotTableFieldGroup _grouping;
+
+  /// <summary>
+  /// Grouping settings.
+  /// Null if the field has no grouping otherwise ExcelPivotTableFieldNumericGroup or ExcelPivotTableFieldNumericGroup.
+  /// </summary>
+  public ExcelPivotTableFieldGroup Grouping => _grouping;
+
+  internal XmlElement AppendField(
+      XmlNode rowsNode,
+      int index,
+      string fieldNodeText,
+      string indexAttrText) {
+    XmlElement prevField = null,
+        newElement;
+    foreach (XmlElement field in rowsNode.ChildNodes) {
+      string x = field.GetAttribute(indexAttrText);
+      if (int.TryParse(x, out var fieldIndex)) {
+        if (fieldIndex
+            == index) //Row already exists
+        {
+          return field;
+        }
+        //else if (fieldIndex > index)
+        //{
+        //    newElement = rowsNode.OwnerDocument.CreateElement(fieldNodeText, ExcelPackage.schemaMain);
+        //    newElement.SetAttribute(indexAttrText, index.ToString());
+        //    rowsNode.InsertAfter(newElement, field);
+        //}
+      }
+      prevField = field;
+    }
+    newElement = rowsNode.OwnerDocument.CreateElement(fieldNodeText, ExcelPackage._schemaMain);
+    newElement.SetAttribute(indexAttrText, index.ToString());
+    rowsNode.InsertAfter(newElement, prevField);
+
+    return newElement;
+  }
+
+  internal XmlHelperInstance _cacheFieldHelper;
+
+  internal void SetCacheFieldNode(XmlNode cacheField) {
+    _cacheFieldHelper = new(NameSpaceManager, cacheField);
+    var groupNode = cacheField.SelectSingleNode("d:fieldGroup", NameSpaceManager);
+    if (groupNode != null) {
+      var groupBy = groupNode.SelectSingleNode("d:rangePr/@groupBy", NameSpaceManager);
+      if (groupBy == null) {
+        _grouping = new ExcelPivotTableFieldNumericGroup(NameSpaceManager, cacheField);
+      } else {
+        DateGrouping = (eDateGroupBy)Enum.Parse(typeof(eDateGroupBy), groupBy.Value, true);
+        _grouping = new ExcelPivotTableFieldDateGroup(NameSpaceManager, groupNode);
+      }
+    }
+  }
+
+  internal ExcelPivotTableFieldCollectionBase<ExcelPivotTableFieldItem> _items;
+
+  /// <summary>
+  /// Pivottable field Items. Used for grouping.
+  /// </summary>
+  public ExcelPivotTableFieldCollectionBase<ExcelPivotTableFieldItem> Items {
+    get {
+      if (_items == null) {
+        _items = new(_table);
+        foreach (XmlNode node in TopNode.SelectNodes("d:items//d:item", NameSpaceManager)) {
+          var item = new ExcelPivotTableFieldItem(NameSpaceManager, node, this);
+          if (item.T == "") {
+            _items.AddInternal(item);
+          }
+        }
+      }
+      return _items;
+    }
+  }
+}
diff --git a/AppsheetEpplus/Table/PivotTable/ExcelPivotTableFieldCollection.cs b/AppsheetEpplus/Table/PivotTable/ExcelPivotTableFieldCollection.cs
new file mode 100644
index 0000000..f69bef6
--- /dev/null
+++ b/AppsheetEpplus/Table/PivotTable/ExcelPivotTableFieldCollection.cs
@@ -0,0 +1,302 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		Added		21-MAR-2011
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Base collection class for pivottable fields
+/// </summary>
+/// <typeparam name="T"></typeparam>
+public class ExcelPivotTableFieldCollectionBase<T> : IEnumerable<T> {
+  protected ExcelPivotTable _table;
+  internal List<T> _list = new();
+
+  internal ExcelPivotTableFieldCollectionBase(ExcelPivotTable table) {
+    _table = table;
+  }
+
+  public IEnumerator<T> GetEnumerator() {
+    return _list.GetEnumerator();
+  }
+
+  IEnumerator IEnumerable.GetEnumerator() {
+    return _list.GetEnumerator();
+  }
+
+  public int Count => _list.Count;
+
+  internal void AddInternal(T field) {
+    _list.Add(field);
+  }
+
+  internal void Clear() {
+    _list.Clear();
+  }
+
+  public T this[int index] {
+    get {
+      if (index < 0 || index >= _list.Count) {
+        throw (new ArgumentOutOfRangeException("Index out of range"));
+      }
+      return _list[index];
+    }
+  }
+}
+
+public class ExcelPivotTableFieldCollection
+    : ExcelPivotTableFieldCollectionBase<ExcelPivotTableField> {
+  internal ExcelPivotTableFieldCollection(ExcelPivotTable table, string topNode)
+      : base(table) {}
+
+  /// <summary>
+  /// Indexer by name
+  /// </summary>
+  /// <param name="name"></param>
+  /// <returns></returns>
+  public ExcelPivotTableField this[string name] {
+    get {
+      foreach (var field in _list) {
+        if (field.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)) {
+          return field;
+        }
+      }
+      return null;
+    }
+  }
+
+  /// <summary>
+  /// Returns the date group field.
+  /// </summary>
+  /// <param name="groupBy">The type of grouping</param>
+  /// <returns>The matching field. If none is found null is returned</returns>
+  public ExcelPivotTableField GetDateGroupField(eDateGroupBy groupBy) {
+    foreach (var fld in _list) {
+      if (fld.Grouping is ExcelPivotTableFieldDateGroup group && (group.GroupBy) == groupBy) {
+        return fld;
+      }
+    }
+    return null;
+  }
+
+  /// <summary>
+  /// Returns the numeric group field.
+  /// </summary>
+  /// <returns>The matching field. If none is found null is returned</returns>
+  public ExcelPivotTableField GetNumericGroupField() {
+    foreach (var fld in _list) {
+      if (fld.Grouping is ExcelPivotTableFieldNumericGroup) {
+        return fld;
+      }
+    }
+    return null;
+  }
+}
+
+/// <summary>
+/// Collection class for Row and column fields in a Pivottable
+/// </summary>
+public class ExcelPivotTableRowColumnFieldCollection
+    : ExcelPivotTableFieldCollectionBase<ExcelPivotTableField> {
+  internal string _topNode;
+
+  internal ExcelPivotTableRowColumnFieldCollection(ExcelPivotTable table, string topNode)
+      : base(table) {
+    _topNode = topNode;
+  }
+
+  /// <summary>
+  /// Add a new row/column field
+  /// </summary>
+  /// <param name="field">The field</param>
+  /// <returns>The new field</returns>
+  public ExcelPivotTableField Add(ExcelPivotTableField field) {
+    SetFlag(field, true);
+    _list.Add(field);
+    return field;
+  }
+
+  /// <summary>
+  /// Insert a new row/column field
+  /// </summary>
+  /// <param name="field">The field</param>
+  /// <param name="index">The position to insert the field</param>
+  /// <returns>The new field</returns>
+  internal ExcelPivotTableField Insert(ExcelPivotTableField field, int index) {
+    SetFlag(field, true);
+    _list.Insert(index, field);
+    return field;
+  }
+
+  private void SetFlag(ExcelPivotTableField field, bool value) {
+    switch (_topNode) {
+      case "rowFields":
+        if (field.IsColumnField || field.IsPageField) {
+          throw (new(
+                  "This field is a column or page field. Can't add it to the RowFields collection"));
+        }
+        field.IsRowField = value;
+        field.Axis = ePivotFieldAxis.Row;
+        break;
+      case "colFields":
+        if (field.IsRowField || field.IsPageField) {
+          throw (new(
+                  "This field is a row or page field. Can't add it to the ColumnFields collection"));
+        }
+        field.IsColumnField = value;
+        field.Axis = ePivotFieldAxis.Column;
+        break;
+      case "pageFields":
+        if (field.IsColumnField || field.IsRowField) {
+          throw (new("Field is a column or row field. Can't add it to the PageFields collection"));
+        }
+        if (_table.Address._fromRow < 3) {
+          throw (new(
+                  string.Format(
+                      "A pivot table with page fields must be located above row 3. Currenct location is {0}",
+                      _table.Address.Address)));
+        }
+        field.IsPageField = value;
+        field.Axis = ePivotFieldAxis.Page;
+        break;
+      case "dataFields":
+
+        break;
+    }
+  }
+
+  /// <summary>
+  /// Remove a field
+  /// </summary>
+  /// <param name="field"></param>
+  public void Remove(ExcelPivotTableField field) {
+    if (!_list.Contains(field)) {
+      throw new ArgumentException("Field not in collection");
+    }
+    SetFlag(field, false);
+    _list.Remove(field);
+  }
+
+  /// <summary>
+  /// Remove a field at a specific position
+  /// </summary>
+  /// <param name="index"></param>
+  public void RemoveAt(int index) {
+    if (index > -1 && index < _list.Count) {
+      throw (new IndexOutOfRangeException());
+    }
+    SetFlag(_list[index], false);
+    _list.RemoveAt(index);
+  }
+}
+
+/// <summary>
+/// Collection class for data fields in a Pivottable
+/// </summary>
+public class ExcelPivotTableDataFieldCollection
+    : ExcelPivotTableFieldCollectionBase<ExcelPivotTableDataField> {
+  internal ExcelPivotTableDataFieldCollection(ExcelPivotTable table)
+      : base(table) {}
+
+  /// <summary>
+  /// Add a new datafield
+  /// </summary>
+  /// <param name="field">The field</param>
+  /// <returns>The new datafield</returns>
+  public ExcelPivotTableDataField Add(ExcelPivotTableField field) {
+    var dataFieldsNode = field.TopNode.SelectSingleNode(
+        "../../d:dataFields",
+        field.NameSpaceManager);
+    if (dataFieldsNode == null) {
+      _table.CreateNode("d:dataFields");
+      dataFieldsNode = field.TopNode.SelectSingleNode("../../d:dataFields", field.NameSpaceManager);
+    }
+
+    XmlElement node = _table.PivotTableXml.CreateElement("dataField", ExcelPackage._schemaMain);
+    node.SetAttribute("fld", field.Index.ToString());
+    dataFieldsNode.AppendChild(node);
+
+    //XmlElement node = field.AppendField(dataFieldsNode, field.Index, "dataField", "fld");
+    field.SetXmlNodeBool("@dataField", true, false);
+
+    var dataField = new ExcelPivotTableDataField(field.NameSpaceManager, node, field);
+    ValidateDupName(dataField);
+
+    _list.Add(dataField);
+    return dataField;
+  }
+
+  private void ValidateDupName(ExcelPivotTableDataField dataField) {
+    if (ExistsDfName(dataField.Field.Name, null)) {
+      var index = 2;
+      string name;
+      do {
+        name = dataField.Field.Name + "_" + index++;
+      } while (ExistsDfName(name, null));
+      dataField.Name = name;
+    }
+  }
+
+  internal bool ExistsDfName(string name, ExcelPivotTableDataField datafield) {
+    foreach (var df in _list) {
+      if (((!string.IsNullOrEmpty(df.Name)
+                      && df.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)
+                      || (string.IsNullOrEmpty(df.Name)
+                              && df.Field.Name.Equals(
+                                  name,
+                                  StringComparison.InvariantCultureIgnoreCase))))
+          && datafield != df) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /// <summary>
+  /// Remove a datafield
+  /// </summary>
+  /// <param name="dataField"></param>
+  public void Remove(ExcelPivotTableDataField dataField) {
+    XmlElement node =
+        dataField.Field.TopNode.SelectSingleNode(
+            string.Format("../../d:dataFields/d:dataField[@fld={0}]", dataField.Index),
+            dataField.NameSpaceManager) as XmlElement;
+    if (node != null) {
+      node.ParentNode.RemoveChild(node);
+    }
+    _list.Remove(dataField);
+  }
+}
diff --git a/AppsheetEpplus/Table/PivotTable/ExcelPivotTableFieldGroup.cs b/AppsheetEpplus/Table/PivotTable/ExcelPivotTableFieldGroup.cs
new file mode 100644
index 0000000..6cfa457
--- /dev/null
+++ b/AppsheetEpplus/Table/PivotTable/ExcelPivotTableFieldGroup.cs
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		Added		21-MAR-2011
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System;
+using System.Globalization;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Base class for pivot table field groups
+/// </summary>
+public class ExcelPivotTableFieldGroup : XmlHelper {
+  internal ExcelPivotTableFieldGroup(XmlNamespaceManager ns, XmlNode topNode)
+      : base(ns, topNode) {}
+}
+
+/// <summary>
+/// A date group
+/// </summary>
+public class ExcelPivotTableFieldDateGroup : ExcelPivotTableFieldGroup {
+  internal ExcelPivotTableFieldDateGroup(XmlNamespaceManager ns, XmlNode topNode)
+      : base(ns, topNode) {}
+
+  private const string _groupByPath = "d:fieldGroup/d:rangePr/@groupBy";
+
+  /// <summary>
+  /// How to group the date field
+  /// </summary>
+  public eDateGroupBy GroupBy {
+    get {
+      string v = GetXmlNodeString(_groupByPath);
+      if (v != "") {
+        return (eDateGroupBy)Enum.Parse(typeof(eDateGroupBy), v, true);
+      }
+      throw (new("Invalid date Groupby"));
+    }
+    private set =>
+      SetXmlNodeString(_groupByPath, value.ToString().ToLower(CultureInfo.InvariantCulture));
+  }
+
+  /// <summary>
+  /// Auto detect start date
+  /// </summary>
+  public bool AutoStart => GetXmlNodeBool("@autoStart", false);
+
+  /// <summary>
+  /// Auto detect end date
+  /// </summary>
+  public bool AutoEnd => GetXmlNodeBool("@autoStart", false);
+}
+
+/// <summary>
+/// A pivot table field numeric grouping
+/// </summary>
+public class ExcelPivotTableFieldNumericGroup : ExcelPivotTableFieldGroup {
+  internal ExcelPivotTableFieldNumericGroup(XmlNamespaceManager ns, XmlNode topNode)
+      : base(ns, topNode) {}
+
+  private const string _startPath = "d:fieldGroup/d:rangePr/@startNum";
+
+  /// <summary>
+  /// Start value
+  /// </summary>
+  public double Start => (double)GetXmlNodeDoubleNull(_startPath);
+
+  private const string _endPath = "d:fieldGroup/d:rangePr/@endNum";
+
+  /// <summary>
+  /// End value
+  /// </summary>
+  public double End => (double)GetXmlNodeDoubleNull(_endPath);
+
+  private const string _groupIntervalPath = "d:fieldGroup/d:rangePr/@groupInterval";
+
+  /// <summary>
+  /// Interval
+  /// </summary>
+  public double Interval => (double)GetXmlNodeDoubleNull(_groupIntervalPath);
+}
diff --git a/AppsheetEpplus/Table/PivotTable/ExcelPivotTableFieldItem.cs b/AppsheetEpplus/Table/PivotTable/ExcelPivotTableFieldItem.cs
new file mode 100644
index 0000000..f1343f6
--- /dev/null
+++ b/AppsheetEpplus/Table/PivotTable/ExcelPivotTableFieldItem.cs
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		Added		21-MAR-2011
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// A field Item. Used for grouping
+/// </summary>
+public class ExcelPivotTableFieldItem : XmlHelper {
+  private readonly ExcelPivotTableField _field;
+
+  internal ExcelPivotTableFieldItem(
+      XmlNamespaceManager ns,
+      XmlNode topNode,
+      ExcelPivotTableField field)
+      : base(ns, topNode) {
+    _field = field;
+  }
+
+  /// <summary>
+  /// The text. Unique values only
+  /// </summary>
+  public string Text {
+    get => GetXmlNodeString("@n");
+    set {
+      if (string.IsNullOrEmpty(value)) {
+        DeleteNode("@n");
+        return;
+      }
+      foreach (var item in _field.Items) {
+        if (item.Text == value) {
+          throw (new ArgumentException("Duplicate Text"));
+        }
+      }
+      SetXmlNodeString("@n", value);
+    }
+  }
+
+  internal int X => GetXmlNodeInt("@x");
+
+  internal string T => GetXmlNodeString("@t");
+}
diff --git a/AppsheetEpplus/Table/PivotTable/ExcelPivotTablePageFieldSettings.cs b/AppsheetEpplus/Table/PivotTable/ExcelPivotTablePageFieldSettings.cs
new file mode 100644
index 0000000..a90de61
--- /dev/null
+++ b/AppsheetEpplus/Table/PivotTable/ExcelPivotTablePageFieldSettings.cs
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		Added		21-MAR-2011
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// A page / report filter field
+/// </summary>
+public class ExcelPivotTablePageFieldSettings : XmlHelper {
+  private ExcelPivotTableField _field;
+
+  internal ExcelPivotTablePageFieldSettings(
+      XmlNamespaceManager ns,
+      XmlNode topNode,
+      ExcelPivotTableField field,
+      int index)
+      : base(ns, topNode) {
+    if (GetXmlNodeString("@hier") == "") {
+      Hier = -1;
+    }
+    _field = field;
+  }
+
+  internal int Index {
+    get => GetXmlNodeInt("@fld");
+    set => SetXmlNodeString("@fld", value.ToString());
+  }
+
+  /// <summary>
+  /// The Name of the field
+  /// </summary>
+  public string Name {
+    get => GetXmlNodeString("@name");
+    set => SetXmlNodeString("@name", value);
+  }
+
+  /***** Dont work. Need items to be populated. ****/
+  ///// <summary>
+  ///// The selected item
+  ///// </summary>
+  //public int SelectedItem
+  //{
+  //    get
+  //    {
+  //        return GetXmlNodeInt("@item");
+  //    }
+  //    set
+  //    {
+  //        if (value < 0) throw new InvalidOperationException("Can't be negative");
+  //        SetXmlNodeString("@item", value.ToString());
+  //    }
+  //}
+  internal int NumFmtId {
+    get => GetXmlNodeInt("@numFmtId");
+    set => SetXmlNodeString("@numFmtId", value.ToString());
+  }
+
+  internal int Hier {
+    get => GetXmlNodeInt("@hier");
+    set => SetXmlNodeString("@hier", value.ToString());
+  }
+}
diff --git a/AppsheetEpplus/Utils/AddressUtility.cs b/AppsheetEpplus/Utils/AddressUtility.cs
new file mode 100644
index 0000000..5f1a5d8
--- /dev/null
+++ b/AppsheetEpplus/Utils/AddressUtility.cs
@@ -0,0 +1,20 @@
+using System.Text.RegularExpressions;
+
+namespace AppsheetEpplus;
+
+public static class AddressUtility {
+  public static string ParseEntireColumnSelections(string address) {
+    string parsedAddress = address;
+    var matches = Regex.Matches(address, "[A-Z]+:[A-Z]+");
+    foreach (Match match in matches) {
+      AddRowNumbersToEntireColumnRange(ref parsedAddress, match.Value);
+    }
+    return parsedAddress;
+  }
+
+  private static void AddRowNumbersToEntireColumnRange(ref string address, string range) {
+    var parsedRange = string.Format("{0}{1}", range, ExcelPackage.MaxRows);
+    var splitArr = parsedRange.Split([':']);
+    address = address.Replace(range, string.Format("{0}1:{1}", splitArr[0], splitArr[1]));
+  }
+}
diff --git a/AppsheetEpplus/Utils/Argument.cs b/AppsheetEpplus/Utils/Argument.cs
new file mode 100644
index 0000000..72afd32
--- /dev/null
+++ b/AppsheetEpplus/Utils/Argument.cs
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-01
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+internal class Argument<T> : IArgument<T> {
+  public Argument(T value) {
+    _value = value;
+  }
+
+  private readonly T _value;
+
+  T IArgument<T>.Value => _value;
+}
diff --git a/AppsheetEpplus/Utils/ArgumentExtensions.cs b/AppsheetEpplus/Utils/ArgumentExtensions.cs
new file mode 100644
index 0000000..d2cf41e
--- /dev/null
+++ b/AppsheetEpplus/Utils/ArgumentExtensions.cs
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-01
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+using System;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Extension methods for guarding
+/// </summary>
+public static class ArgumentExtensions {
+  /// <summary>
+  /// Throws an ArgumentNullException if argument is null
+  /// </summary>
+  /// <typeparam name="T">Argument type</typeparam>
+  /// <param name="argument">Argument to check</param>
+  /// <param name="argumentName">parameter/argument name</param>
+  /// <exception cref="ArgumentNullException"></exception>
+  public static void IsNotNull<T>(this IArgument<T> argument, string argumentName)
+      where T : class {
+    argumentName = string.IsNullOrEmpty(argumentName) ? "value" : argumentName;
+    if (argument.Value == null) {
+      throw new ArgumentNullException(argumentName);
+    }
+  }
+
+  /// <summary>
+  /// Throws an <see cref="ArgumentNullException"/> if the string argument is null or empty
+  /// </summary>
+  /// <param name="argument">Argument to check</param>
+  /// <param name="argumentName">parameter/argument name</param>
+  /// <exception cref="ArgumentNullException"></exception>
+  public static void IsNotNullOrEmpty(this IArgument<string> argument, string argumentName) {
+    if (string.IsNullOrEmpty(argument.Value)) {
+      throw new ArgumentNullException(argumentName);
+    }
+  }
+
+  /// <summary>
+  /// Throws an ArgumentOutOfRangeException if the value of the argument is out of the supplied range
+  /// </summary>
+  /// <typeparam name="T">Type implementing <see cref="IComparable"/></typeparam>
+  /// <param name="argument">The argument to check</param>
+  /// <param name="min">Min value of the supplied range</param>
+  /// <param name="max">Max value of the supplied range</param>
+  /// <param name="argumentName">parameter/argument name</param>
+  /// <exception cref="ArgumentOutOfRangeException"></exception>
+  public static void IsInRange<T>(this IArgument<T> argument, T min, T max, string argumentName)
+      where T : IComparable {
+    if (!(argument.Value.CompareTo(min) >= 0 && argument.Value.CompareTo(max) <= 0)) {
+      throw new ArgumentOutOfRangeException(argumentName);
+    }
+  }
+}
diff --git a/AppsheetEpplus/Utils/ConvertUtil.cs b/AppsheetEpplus/Utils/ConvertUtil.cs
new file mode 100644
index 0000000..ecdf789
--- /dev/null
+++ b/AppsheetEpplus/Utils/ConvertUtil.cs
@@ -0,0 +1,171 @@
+using System;
+using System.Globalization;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace AppsheetEpplus;
+
+internal static class ConvertUtil {
+  internal static bool IsNumeric(object candidate) {
+    if (candidate == null) {
+      return false;
+    }
+    return (candidate.GetType().IsPrimitive
+            || candidate is double
+            || candidate is decimal
+            || candidate is DateTime
+            || candidate is TimeSpan
+            || candidate is long);
+  }
+
+  internal static bool IsNumericString(object candidate) {
+    if (candidate != null) {
+      return Regex.IsMatch(candidate.ToString(), @"^[\d]+(\,[\d])?");
+    }
+    return false;
+  }
+
+  /// <summary>
+  /// Convert an object value to a double
+  /// </summary>
+  /// <param name="v"></param>
+  /// <param name="ignoreBool"></param>
+  /// <returns></returns>
+  internal static double GetValueDouble(object v, bool ignoreBool = false) {
+    double d;
+    try {
+      if (ignoreBool && v is bool) {
+        return 0;
+      }
+      if (IsNumeric(v)) {
+        if (v is DateTime time) {
+          d = time.ToOADate();
+        } else if (v is TimeSpan span) {
+          d = DateTime.FromOADate(0).Add(span).ToOADate();
+        } else {
+          d = Convert.ToDouble(v, CultureInfo.InvariantCulture);
+        }
+      } else {
+        d = 0;
+      }
+    } catch {
+      d = 0;
+    }
+    return d;
+  }
+
+  /// <summary>
+  /// OOXML requires that "," , and &amp; be escaped, but ' and " should *not* be escaped, nor should
+  /// any extended Unicode characters. This function only encodes the required characters.
+  /// System.Security.SecurityElement.Escape() escapes ' and " as  &apos; and &quot;, so it cannot
+  /// be used reliably. System.Web.HttpUtility.HtmlEncode overreaches as well and uses the numeric
+  /// escape equivalent.
+  /// </summary>
+  /// <param name="s"></param>
+  /// <returns></returns>
+  internal static string ExcelEscapeString(string s) {
+    return s.Replace("&", "&amp;").Replace("<", "&lt;").Replace(">", "&gt;");
+  }
+
+  /// <summary>
+  /// Return true if preserve space attribute is set.
+  /// </summary>
+  /// <param name="sw"></param>
+  /// <param name="t"></param>
+  /// <returns></returns>
+  internal static void ExcelEncodeString(StreamWriter sw, string t) {
+    if (Regex.IsMatch(t, "(_x[0-9A-F]{4,4}_)")) {
+      var match = Regex.Match(t, "(_x[0-9A-F]{4,4}_)");
+      int indexAdd = 0;
+      while (match.Success) {
+        t = t.Insert(match.Index + indexAdd, "_x005F");
+        indexAdd += 6;
+        match = match.NextMatch();
+      }
+    }
+    for (int i = 0; i < t.Length; i++) {
+      if (t[i] <= 0x1f
+          && t[i] != '\t'
+          && t[i] != '\n'
+          && t[i]
+              != '\r') //Not Tab, CR or LF
+      {
+        sw.Write("_x00{0}_", (t[i] < 0xf ? "0" : "") + ((int)t[i]).ToString("X"));
+      } else {
+        sw.Write(t[i]);
+      }
+    }
+  }
+
+  /// <summary>
+  /// Return true if preserve space attribute is set.
+  /// </summary>
+  /// <param name="sb"></param>
+  /// <param name="t"></param>
+  /// <returns></returns>
+  internal static void ExcelEncodeString(StringBuilder sb, string t, bool encodeTabCrlf = false) {
+    if (Regex.IsMatch(t, "(_x[0-9A-F]{4,4}_)")) {
+      var match = Regex.Match(t, "(_x[0-9A-F]{4,4}_)");
+      int indexAdd = 0;
+      while (match.Success) {
+        t = t.Insert(match.Index + indexAdd, "_x005F");
+        indexAdd += 6;
+        match = match.NextMatch();
+      }
+    }
+    for (int i = 0; i < t.Length; i++) {
+      if (t[i] <= 0x1f
+          && ((t[i] != '\t' && t[i] != '\n' && t[i] != '\r' && encodeTabCrlf == false)
+                  || encodeTabCrlf)) //Not Tab, CR or LF
+      {
+        sb.AppendFormat("_x00{0}_", (t[i] < 0xf ? "0" : "") + ((int)t[i]).ToString("X"));
+      } else {
+        sb.Append(t[i]);
+      }
+    }
+  }
+
+  /// <summary>
+  /// Return true if preserve space attribute is set.
+  /// </summary>
+  /// <param name="sb"></param>
+  /// <param name="t"></param>
+  /// <returns></returns>
+  internal static string ExcelEncodeString(string t) {
+    StringBuilder sb = new StringBuilder();
+    t = t.Replace("\r\n", "\n"); //For some reason can't table name have cr in them. Replace with nl
+    ExcelEncodeString(sb, t, true);
+    return sb.ToString();
+  }
+
+  internal static string ExcelDecodeString(string t) {
+    var match = Regex.Match(t, "(_x005F|_x[0-9A-F]{4,4}_)");
+    if (!match.Success) {
+      return t;
+    }
+
+    var useNextValue = false;
+    var ret = new StringBuilder();
+    var prevIndex = 0;
+    while (match.Success) {
+      if (prevIndex < match.Index) {
+        ret.Append(t.Substring(prevIndex, match.Index - prevIndex));
+      }
+      if (!useNextValue && match.Value == "_x005F") {
+        useNextValue = true;
+      } else {
+        if (useNextValue) {
+          ret.Append(match.Value);
+          useNextValue = false;
+        } else {
+          ret.Append((char)int.Parse(match.Value.Substring(2, 4), NumberStyles.AllowHexSpecifier));
+        }
+      }
+      prevIndex = match.Index + match.Length;
+      match = match.NextMatch();
+    }
+    ret.Append(t.Substring(prevIndex, t.Length - prevIndex));
+    return ret.ToString();
+  }
+}
diff --git a/AppsheetEpplus/Utils/IArgument.cs b/AppsheetEpplus/Utils/IArgument.cs
new file mode 100644
index 0000000..9622d01
--- /dev/null
+++ b/AppsheetEpplus/Utils/IArgument.cs
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm   		                Added       		        2011-01-01
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// An argument
+/// </summary>
+/// <typeparam name="T">Argument Type</typeparam>
+public interface IArgument<T> {
+  T Value { get; }
+}
diff --git a/AppsheetEpplus/Utils/IExcelCell.cs b/AppsheetEpplus/Utils/IExcelCell.cs
new file mode 100644
index 0000000..005ed03
--- /dev/null
+++ b/AppsheetEpplus/Utils/IExcelCell.cs
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Jan Källman		                Initial Release		        2009-10-01
+ * Jan Källman		License changed GPL-->LGPL 2011-12-16
+ *******************************************************************************/
+
+using System;
+
+namespace AppsheetEpplus;
+
+internal interface IExcelCell {
+  object Value { get; set; }
+
+  string StyleName { get; }
+
+  int StyleID { get; set; }
+
+  ExcelStyle Style { get; }
+
+  Uri Hyperlink { get; set; }
+
+  string Formula { get; set; }
+
+  string FormulaR1C1 { get; set; }
+}
diff --git a/AppsheetEpplus/Utils/IValidationResult.cs b/AppsheetEpplus/Utils/IValidationResult.cs
new file mode 100644
index 0000000..70c1df9
--- /dev/null
+++ b/AppsheetEpplus/Utils/IValidationResult.cs
@@ -0,0 +1,7 @@
+namespace AppsheetEpplus;
+
+public interface IValidationResult {
+  void IsTrue();
+
+  void IsFalse();
+}
diff --git a/AppsheetEpplus/Utils/SqRefUtility.cs b/AppsheetEpplus/Utils/SqRefUtility.cs
new file mode 100644
index 0000000..94f853e
--- /dev/null
+++ b/AppsheetEpplus/Utils/SqRefUtility.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Text.RegularExpressions;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Class for handling translation between ExcelAddresses and sqref addresses.
+/// </summary>
+public static class SqRefUtility {
+  /// <summary>
+  /// Transforms an address to a valid sqRef address.
+  /// </summary>
+  /// <param name="address">The address to transform</param>
+  /// <returns>A valid SqRef address</returns>
+  public static string ToSqRefAddress(string address) {
+    ArgumentException.ThrowIfNullOrEmpty(address);
+    address = address.Replace(",", " ");
+    address = new Regex("[ ]+").Replace(address, " ");
+    return address;
+  }
+
+  /// <summary>
+  /// Transforms an sqRef address into a excel address
+  /// </summary>
+  /// <param name="address">The address to transform</param>
+  /// <returns>A valid excel address</returns>
+  public static string FromSqRefAddress(string address) {
+    ArgumentException.ThrowIfNullOrEmpty(address);
+    address = address.Replace(" ", ",");
+    return address;
+  }
+}
diff --git a/AppsheetEpplus/Utils/UriHelper.cs b/AppsheetEpplus/Utils/UriHelper.cs
new file mode 100644
index 0000000..8356ab1
--- /dev/null
+++ b/AppsheetEpplus/Utils/UriHelper.cs
@@ -0,0 +1,69 @@
+using System;
+
+namespace AppsheetEpplus;
+
+internal class UriHelper {
+  internal static Uri ResolvePartUri(Uri sourceUri, Uri targetUri) {
+    if (targetUri.OriginalString.StartsWith("/")) {
+      return targetUri;
+    }
+    string[] source = sourceUri.OriginalString.Split('/');
+    string[] target = targetUri.OriginalString.Split('/');
+
+    int t = target.Length - 1;
+    int s;
+    if (sourceUri.OriginalString.EndsWith(
+        "/")) //is the source a directory?
+    {
+      s = source.Length - 1;
+    } else {
+      s = source.Length - 2;
+    }
+
+    string file = target[t--];
+
+    while (t >= 0) {
+      if (target[t] == ".") {
+        break;
+      }
+      if (target[t] == "..") {
+        s--;
+        t--;
+      } else {
+        file = target[t--] + "/" + file;
+      }
+    }
+    if (s >= 0) {
+      for (int i = s; i >= 0; i--) {
+        file = source[i] + "/" + file;
+      }
+    }
+    return new(file, UriKind.RelativeOrAbsolute);
+  }
+
+  internal static Uri GetRelativeUri(Uri worksheetUri, Uri uri) {
+    string[] source = worksheetUri.OriginalString.Split('/');
+    string[] target = uri.OriginalString.Split('/');
+
+    int slen;
+    if (worksheetUri.OriginalString.EndsWith("/")) {
+      slen = source.Length;
+    } else {
+      slen = source.Length - 1;
+    }
+    int i = 0;
+    while (i < slen && i < target.Length && source[i] == target[i]) {
+      i++;
+    }
+
+    string dirUp = "";
+    for (int s = i; s < slen; s++) {
+      dirUp += "../";
+    }
+    string file = "";
+    for (int t = i; t < target.Length; t++) {
+      file += (file == "" ? "" : "/") + target[t];
+    }
+    return new(dirUp + file, UriKind.Relative);
+  }
+}
diff --git a/AppsheetEpplus/Utils/ValidationResult.cs b/AppsheetEpplus/Utils/ValidationResult.cs
new file mode 100644
index 0000000..73086ee
--- /dev/null
+++ b/AppsheetEpplus/Utils/ValidationResult.cs
@@ -0,0 +1,35 @@
+using System;
+
+namespace AppsheetEpplus;
+
+public class ValidationResult : IValidationResult {
+  public ValidationResult(bool result)
+      : this(result, null) {}
+
+  public ValidationResult(bool result, string errorMessage) {
+    _result = result;
+    _errorMessage = errorMessage;
+  }
+
+  private readonly bool _result;
+  private readonly string _errorMessage;
+
+  private void Throw() {
+    if (string.IsNullOrEmpty(_errorMessage)) {
+      throw new InvalidOperationException();
+    }
+    throw new InvalidOperationException(_errorMessage);
+  }
+
+  void IValidationResult.IsTrue() {
+    if (!_result) {
+      Throw();
+    }
+  }
+
+  void IValidationResult.IsFalse() {
+    if (_result) {
+      Throw();
+    }
+  }
+}
diff --git a/AppsheetEpplus/XmlHelper.cs b/AppsheetEpplus/XmlHelper.cs
new file mode 100644
index 0000000..44e6905
--- /dev/null
+++ b/AppsheetEpplus/XmlHelper.cs
@@ -0,0 +1,627 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						         Date
+ * ******************************************************************************
+ * Jan Källman		    Initial Release		         2009-10-01
+ * Jan Källman		    License changed GPL-->LGPL 2011-12-27
+ * Eyal Seagull       Add "CreateComplexNode"    2012-04-03
+ * Eyal Seagull       Add "DeleteTopNode"        2012-04-13
+ *******************************************************************************/
+
+using System;
+using System.Collections.Immutable;
+using System.Globalization;
+using System.IO;
+using System.Text;
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+/// <summary>
+/// Help class containing XML functions.
+/// Can be Inherited
+/// </summary>
+public abstract class XmlHelper {
+  internal delegate int ChangedEventHandler(StyleBase sender, StyleChangeEventArgs e);
+
+  internal XmlHelper(XmlNamespaceManager nameSpaceManager) {
+    TopNode = null;
+    NameSpaceManager = nameSpaceManager;
+  }
+
+  internal XmlHelper(XmlNamespaceManager nameSpaceManager, XmlNode topNode) {
+    TopNode = topNode;
+    NameSpaceManager = nameSpaceManager;
+  }
+
+  //internal bool ChangedFlag;
+  internal XmlNamespaceManager NameSpaceManager { get; set; }
+
+  internal XmlNode TopNode { get; set; }
+
+  /// <summary>
+  /// Schema order list
+  /// </summary>
+  protected virtual ImmutableArray<string> SchemaNodeOrder => ImmutableArray<string>.Empty;
+
+  internal XmlNode CreateNode(string path) {
+    if (path == "") {
+      return TopNode;
+    }
+    return CreateNode(path, false);
+  }
+
+  internal XmlNode CreateNode(string path, bool insertFirst) {
+    XmlNode node = TopNode;
+    XmlNode prependNode = null;
+    foreach (string subPath in path.Split('/')) {
+      XmlNode subNode = node.SelectSingleNode(subPath, NameSpaceManager);
+      if (subNode == null) {
+        string nodeName;
+        string nodePrefix;
+
+        string nameSpaceUri;
+        string[] nameSplit = subPath.Split(':');
+
+        if (SchemaNodeOrder.Length > 0 && subPath[0] != '@') {
+          insertFirst = false;
+          prependNode = GetPrependNode(subPath, node);
+        }
+
+        if (nameSplit.Length > 1) {
+          nodePrefix = nameSplit[0];
+          if (nodePrefix[0] == '@') {
+            nodePrefix = nodePrefix.Substring(1, nodePrefix.Length - 1);
+          }
+          nameSpaceUri = NameSpaceManager.LookupNamespace(nodePrefix);
+          nodeName = nameSplit[1];
+        } else {
+          nodePrefix = "";
+          nameSpaceUri = "";
+          nodeName = nameSplit[0];
+        }
+        if (subPath.StartsWith("@")) {
+          XmlAttribute addedAtt = node.OwnerDocument.CreateAttribute(
+              subPath.Substring(1, subPath.Length - 1),
+              nameSpaceUri); //nameSpaceURI
+          node.Attributes.Append(addedAtt);
+        } else {
+          if (nodePrefix == "") {
+            subNode = node.OwnerDocument.CreateElement(nodeName, nameSpaceUri);
+          } else {
+            if (nodePrefix == ""
+                || (node.OwnerDocument != null
+                        && node.OwnerDocument.DocumentElement != null
+                        && node.OwnerDocument.DocumentElement.NamespaceURI == nameSpaceUri
+                        && node.OwnerDocument.DocumentElement.Prefix == "")) {
+              subNode = node.OwnerDocument.CreateElement(nodeName, nameSpaceUri);
+            } else {
+              subNode = node.OwnerDocument.CreateElement(nodePrefix, nodeName, nameSpaceUri);
+            }
+          }
+          if (prependNode != null) {
+            node.InsertBefore(subNode, prependNode);
+            prependNode = null;
+          } else if (insertFirst) {
+            node.PrependChild(subNode);
+          } else {
+            node.AppendChild(subNode);
+          }
+        }
+      }
+      node = subNode;
+    }
+    return node;
+  }
+
+  /// <summary>
+  /// Options to insert a node in the XmlDocument
+  /// </summary>
+  internal enum eNodeInsertOrder {
+    /// <summary>
+    /// Insert as first node of "topNode"
+    /// </summary>
+    First,
+
+    /// <summary>
+    /// Insert as the last child of "topNode"
+    /// </summary>
+    Last,
+
+    /// <summary>
+    /// Insert after the "referenceNode"
+    /// </summary>
+    After,
+
+    /// <summary>
+    /// Insert before the "referenceNode"
+    /// </summary>
+    Before,
+
+    /// <summary>
+    /// Use the Schema List to insert in the right order. If the Schema list
+    /// is null or empty, consider "Last" as the selected option
+    /// </summary>
+    SchemaOrder,
+  }
+
+  /// <summary>
+  /// Create a complex node. Insert the node according to the <paramref name="path"/>
+  /// using the <paramref name="topNode"/> as the parent
+  /// </summary>
+  /// <param name="topNode"></param>
+  /// <param name="path"></param>
+  /// <returns></returns>
+  internal XmlNode CreateComplexNode(XmlNode topNode, string path) {
+    return CreateComplexNode(topNode, path, eNodeInsertOrder.SchemaOrder, null);
+  }
+
+  /// <summary>
+  /// Creates complex XML nodes
+  /// </summary>
+  /// <remarks>
+  /// 1. "d:conditionalFormatting"
+  ///		1.1. Creates/find the first "conditionalFormatting" node
+  ///
+  /// 2. "d:conditionalFormatting/@sqref"
+  ///		2.1. Creates/find the first "conditionalFormatting" node
+  ///		2.2. Creates (if not exists) the @sqref attribute
+  ///
+  /// 3. "d:conditionalFormatting/@id='7'/@sqref='A9:B99'"
+  ///		3.1. Creates/find the first "conditionalFormatting" node
+  ///		3.2. Creates/update its @id attribute to "7"
+  ///		3.3. Creates/update its @sqref attribute to "A9:B99"
+  ///
+  /// 4. "d:conditionalFormatting[@id='7']/@sqref='X1:X5'"
+  ///		4.1. Creates/find the first "conditionalFormatting" node with @id=7
+  ///		4.2. Creates/update its @sqref attribute to "X1:X5"
+  ///
+  /// 5. "d:conditionalFormatting[@id='7']/@id='8'/@sqref='X1:X5'/d:cfRule/@id='AB'"
+  ///		5.1. Creates/find the first "conditionalFormatting" node with @id=7
+  ///		5.2. Set its @id attribute to "8"
+  ///		5.2. Creates/update its @sqref attribute and set it to "X1:X5"
+  ///		5.3. Creates/find the first "cfRule" node (inside the node)
+  ///		5.4. Creates/update its @id attribute to "AB"
+  ///
+  /// 6. "d:cfRule/@id=''"
+  ///		6.1. Creates/find the first "cfRule" node
+  ///		6.1. Remove the @id attribute
+  ///	</remarks>
+  /// <param name="topNode"></param>
+  /// <param name="path"></param>
+  /// <param name="nodeInsertOrder"></param>
+  /// <param name="referenceNode"></param>
+  /// <returns>The last node creates/found</returns>
+  internal XmlNode CreateComplexNode(
+      XmlNode topNode,
+      string path,
+      eNodeInsertOrder nodeInsertOrder,
+      XmlNode referenceNode) {
+    // Path is obrigatory
+    if ((path == null) || (path == string.Empty)) {
+      return topNode;
+    }
+
+    XmlNode node = topNode;
+
+    //TODO: BUG: when the "path" contains "/" in an attrribue value, it gives an error.
+
+    // Separate the XPath to Nodes and Attributes
+    foreach (string subPath in path.Split('/')) {
+      // The subPath can be any one of those:
+      // nodeName
+      // x:nodeName
+      // nodeName[find criteria]
+      // x:nodeName[find criteria]
+      // @attribute
+      // @attribute='attribute value'
+
+      // Check if the subPath has at least one character
+      if (subPath.Length > 0) {
+        // Check if the subPath is an attribute (with or without value)
+        if (subPath.StartsWith("@")) {
+          // @attribute										--> Create attribute
+          // @attribute=''								--> Remove attribute
+          // @attribute='attribute value' --> Create attribute + update value
+          string[] attributeSplit = subPath.Split('=');
+          string attributeName = attributeSplit[0].Substring(1, attributeSplit[0].Length - 1);
+          string attributeValue = null; // Null means no attribute value
+
+          // Check if we have an attribute value to set
+          if (attributeSplit.Length > 1) {
+            // Remove the ' or " from the attribute value
+            attributeValue = attributeSplit[1].Replace("'", "").Replace("\"", "");
+          }
+
+          // Get the attribute (if exists)
+          XmlAttribute attribute = (XmlAttribute)(node.Attributes.GetNamedItem(attributeName));
+
+          // Remove the attribute if value is empty (not null)
+          if (attributeValue == string.Empty) {
+            // Only if the attribute exists
+            if (attribute != null) {
+              node.Attributes.Remove(attribute);
+            }
+          } else {
+            // Create the attribue if does not exists
+            if (attribute == null) {
+              // Create the attribute
+              attribute = node.OwnerDocument.CreateAttribute(attributeName);
+
+              // Add it to the current node
+              node.Attributes.Append(attribute);
+            }
+
+            // Update the attribute value
+            if (attributeValue != null) {
+              node.Attributes[attributeName].Value = attributeValue;
+            }
+          }
+        } else {
+          // nodeName
+          // x:nodeName
+          // nodeName[find criteria]
+          // x:nodeName[find criteria]
+
+          // Look for the node (with or without filter criteria)
+          XmlNode subNode = node.SelectSingleNode(subPath, NameSpaceManager);
+
+          // Check if the node does not exists
+          if (subNode == null) {
+            string nodeName;
+            string nodePrefix;
+            string[] nameSplit = subPath.Split(':');
+            string nameSpaceUri;
+
+            // Check if the name has a prefix like "d:nodeName"
+            if (nameSplit.Length > 1) {
+              nodePrefix = nameSplit[0];
+              nameSpaceUri = NameSpaceManager.LookupNamespace(nodePrefix);
+              nodeName = nameSplit[1];
+            } else {
+              nodePrefix = string.Empty;
+              nameSpaceUri = string.Empty;
+              nodeName = nameSplit[0];
+            }
+
+            // Check if we have a criteria part in the node name
+            if (nodeName.IndexOf("[") > 0) {
+              // remove the criteria from the node name
+              nodeName = nodeName.Substring(0, nodeName.IndexOf("["));
+            }
+
+            if (nodePrefix == string.Empty) {
+              subNode = node.OwnerDocument.CreateElement(nodeName, nameSpaceUri);
+            } else {
+              if (node.OwnerDocument != null
+                  && node.OwnerDocument.DocumentElement != null
+                  && node.OwnerDocument.DocumentElement.NamespaceURI == nameSpaceUri
+                  && node.OwnerDocument.DocumentElement.Prefix == string.Empty) {
+                subNode = node.OwnerDocument.CreateElement(nodeName, nameSpaceUri);
+              } else {
+                subNode = node.OwnerDocument.CreateElement(nodePrefix, nodeName, nameSpaceUri);
+              }
+            }
+
+            // Check if we need to use the "SchemaOrder"
+            if (nodeInsertOrder == eNodeInsertOrder.SchemaOrder) {
+              // Check if the Schema Order List is empty
+              if (SchemaNodeOrder.Length == 0) {
+                // Use the "Insert Last" option when Schema Order List is empty
+                nodeInsertOrder = eNodeInsertOrder.Last;
+              } else {
+                // Find the prepend node in order to insert
+                referenceNode = GetPrependNode(nodeName, node);
+
+                if (referenceNode != null) {
+                  nodeInsertOrder = eNodeInsertOrder.Before;
+                } else {
+                  nodeInsertOrder = eNodeInsertOrder.Last;
+                }
+              }
+            }
+
+            switch (nodeInsertOrder) {
+              case eNodeInsertOrder.After:
+                node.InsertAfter(subNode, referenceNode);
+                referenceNode = null;
+                break;
+
+              case eNodeInsertOrder.Before:
+                node.InsertBefore(subNode, referenceNode);
+                referenceNode = null;
+                break;
+
+              case eNodeInsertOrder.First:
+                node.PrependChild(subNode);
+                break;
+
+              case eNodeInsertOrder.Last:
+                node.AppendChild(subNode);
+                break;
+            }
+          }
+
+          // Make the newly created node the top node when the rest of the path
+          // is being evaluated. So newly created nodes will be the children of the
+          // one we just created.
+          node = subNode;
+        }
+      }
+    }
+
+    // Return the last created/found node
+    return node;
+  }
+
+  /// <summary>
+  /// return Prepend node
+  /// </summary>
+  /// <param name="nodeName">name of the node to check</param>
+  /// <param name="node">Topnode to check children</param>
+  /// <returns></returns>
+  private XmlNode GetPrependNode(string nodeName, XmlNode node) {
+    int pos = GetNodePos(nodeName);
+    if (pos < 0) {
+      return null;
+    }
+    XmlNode prependNode = null;
+    foreach (XmlNode childNode in node.ChildNodes) {
+      int childPos = GetNodePos(childNode.Name);
+      if (childPos
+          > -1) //Found?
+      {
+        if (childPos
+            > pos) //Position is before
+        {
+          prependNode = childNode;
+          break;
+        }
+      }
+    }
+    return prependNode;
+  }
+
+  private int GetNodePos(string nodeName) {
+    int ix = nodeName.IndexOf(":");
+    if (ix > 0) {
+      nodeName = nodeName.Substring(ix + 1, nodeName.Length - (ix + 1));
+    }
+    for (int i = 0; i < SchemaNodeOrder.Length; i++) {
+      if (nodeName == SchemaNodeOrder[i]) {
+        return i;
+      }
+    }
+    return -1;
+  }
+
+  internal void DeleteAllNode(string path) {
+    string[] split = path.Split('/');
+    XmlNode node = TopNode;
+    foreach (string s in split) {
+      node = node.SelectSingleNode(s, NameSpaceManager);
+      if (node != null) {
+        if (node is XmlAttribute attribute) {
+          attribute.OwnerElement.Attributes.Remove(attribute);
+        } else {
+          node.ParentNode.RemoveChild(node);
+        }
+      } else {
+        break;
+      }
+    }
+  }
+
+  internal void DeleteNode(string path) {
+    var node = TopNode.SelectSingleNode(path, NameSpaceManager);
+    if (node != null) {
+      if (node is XmlAttribute att) {
+        att.OwnerElement.Attributes.Remove(att);
+      } else {
+        node.ParentNode.RemoveChild(node);
+      }
+    }
+  }
+
+  internal void SetXmlNodeString(string path, string value) {
+    SetXmlNodeString(TopNode, path, value, false, false);
+  }
+
+  internal void SetXmlNodeString(string path, string value, bool removeIfBlank) {
+    SetXmlNodeString(TopNode, path, value, removeIfBlank, false);
+  }
+
+  internal void SetXmlNodeString(XmlNode node, string path, string value, bool removeIfBlank) {
+    SetXmlNodeString(node, path, value, removeIfBlank, false);
+  }
+
+  internal void SetXmlNodeString(
+      XmlNode node,
+      string path,
+      string value,
+      bool removeIfBlank,
+      bool insertFirst) {
+    if (node == null) {
+      return;
+    }
+    if (value == "" && removeIfBlank) {
+      DeleteAllNode(path);
+    } else {
+      XmlNode nameNode = node.SelectSingleNode(path, NameSpaceManager);
+      if (nameNode == null) {
+        CreateNode(path, insertFirst);
+        nameNode = node.SelectSingleNode(path, NameSpaceManager);
+      }
+      //if (nameNode.InnerText != value) HasChanged();
+      nameNode.InnerText = value;
+    }
+  }
+
+  internal void SetXmlNodeBool(string path, bool value) {
+    SetXmlNodeString(TopNode, path, value ? "1" : "0", false, false);
+  }
+
+  internal void SetXmlNodeBool(string path, bool value, bool removeIf) {
+    if (value == removeIf) {
+      var node = TopNode.SelectSingleNode(path, NameSpaceManager);
+      if (node != null) {
+        if (node is XmlAttribute attribute) {
+          var elem = attribute.OwnerElement;
+          elem.ParentNode.RemoveChild(elem);
+        } else {
+          TopNode.RemoveChild(node);
+        }
+      }
+    } else {
+      SetXmlNodeString(TopNode, path, value ? "1" : "0", false, false);
+    }
+  }
+
+  internal bool ExistNode(string path) {
+    if (TopNode == null || TopNode.SelectSingleNode(path, NameSpaceManager) == null) {
+      return false;
+    }
+    return true;
+  }
+
+  internal bool? GetXmlNodeBoolNullable(string path) {
+    var value = GetXmlNodeString(path);
+    if (string.IsNullOrEmpty(value)) {
+      return null;
+    }
+    return GetXmlNodeBool(path);
+  }
+
+  internal bool GetXmlNodeBool(string path) {
+    return GetXmlNodeBool(path, false);
+  }
+
+  internal bool GetXmlNodeBool(string path, bool blankValue) {
+    string value = GetXmlNodeString(path);
+    if (value == "1"
+        || value == "-1"
+        || value.Equals("true", StringComparison.InvariantCultureIgnoreCase)) {
+      return true;
+    }
+    if (value == "") {
+      return blankValue;
+    }
+    return false;
+  }
+
+  internal int GetXmlNodeInt(string path) {
+    if (int.TryParse(GetXmlNodeString(path), out var i)) {
+      return i;
+    }
+    return int.MinValue;
+  }
+
+  internal int? GetXmlNodeIntNull(string path) {
+    string s = GetXmlNodeString(path);
+    if (s != "" && int.TryParse(s, out var i)) {
+      return i;
+    }
+    return null;
+  }
+
+  internal decimal GetXmlNodeDecimal(string path) {
+    if (decimal.TryParse(
+        GetXmlNodeString(path),
+        NumberStyles.Any,
+        CultureInfo.InvariantCulture,
+        out var d)) {
+      return d;
+    }
+    return 0;
+  }
+
+  internal decimal? GetXmlNodeDecimalNull(string path) {
+    if (decimal.TryParse(
+        GetXmlNodeString(path),
+        NumberStyles.Any,
+        CultureInfo.InvariantCulture,
+        out var d)) {
+      return d;
+    }
+    return null;
+  }
+
+  internal double? GetXmlNodeDoubleNull(string path) {
+    string s = GetXmlNodeString(path);
+    if (s == "") {
+      return null;
+    }
+    if (double.TryParse(s, NumberStyles.Number, CultureInfo.InvariantCulture, out var v)) {
+      return v;
+    }
+    return null;
+  }
+
+  internal double GetXmlNodeDouble(string path) {
+    string s = GetXmlNodeString(path);
+    if (s == "") {
+      return double.NaN;
+    }
+    if (double.TryParse(s, NumberStyles.Number, CultureInfo.InvariantCulture, out var v)) {
+      return v;
+    }
+    return double.NaN;
+  }
+
+  internal string GetXmlNodeString(XmlNode node, string path) {
+    if (node == null) {
+      return "";
+    }
+
+    XmlNode nameNode = node.SelectSingleNode(path, NameSpaceManager);
+
+    if (nameNode != null) {
+      if (nameNode.NodeType == XmlNodeType.Attribute) {
+        return nameNode.Value ?? "";
+      }
+      return nameNode.InnerText;
+    }
+    return "";
+  }
+
+  internal string GetXmlNodeString(string path) {
+    return GetXmlNodeString(TopNode, path);
+  }
+
+  internal static void LoadXmlSafe(XmlDocument xmlDoc, Stream stream) {
+    XmlReaderSettings settings = new XmlReaderSettings();
+    //Disable entity parsing (to aviod xmlbombs, External Entity Attacks etc).
+    settings.ProhibitDtd = true;
+    XmlReader reader = XmlReader.Create(stream, settings);
+    xmlDoc.Load(reader);
+  }
+
+  internal static void LoadXmlSafe(XmlDocument xmlDoc, string xml, Encoding encoding) {
+    var stream = new MemoryStream(encoding.GetBytes(xml));
+    LoadXmlSafe(xmlDoc, stream);
+  }
+}
diff --git a/AppsheetEpplus/XmlHelperFactory.cs b/AppsheetEpplus/XmlHelperFactory.cs
new file mode 100644
index 0000000..9de58cf
--- /dev/null
+++ b/AppsheetEpplus/XmlHelperFactory.cs
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011  Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author							Change						Date
+ * ******************************************************************************
+ * Mats Alm 		    Initial Release		        2011-05-01
+ * Jan Källman		    License changed GPL-->LGPL  2011-12-27
+ *******************************************************************************/
+
+using System.Xml;
+
+namespace AppsheetEpplus;
+
+internal class XmlHelperInstance : XmlHelper {
+  internal XmlHelperInstance(XmlNamespaceManager namespaceManager)
+      : base(namespaceManager) {}
+
+  internal XmlHelperInstance(XmlNamespaceManager namespaceManager, XmlNode topNode)
+      : base(namespaceManager, topNode) {}
+}
+
+internal static class XmlHelperFactory {
+  internal static XmlHelper Create(XmlNamespaceManager namespaceManager) {
+    return new XmlHelperInstance(namespaceManager);
+  }
+
+  internal static XmlHelper Create(XmlNamespaceManager namespaceManager, XmlNode topNode) {
+    return new XmlHelperInstance(namespaceManager, topNode);
+  }
+}
diff --git a/EPPlus.sln b/EPPlus.sln
index d838aaf..f19d997 100644
--- a/EPPlus.sln
+++ b/EPPlus.sln
@@ -9,22 +9,18 @@
 		LocalTestRun.testrunconfig = LocalTestRun.testrunconfig
 	EndProjectSection
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPPlusSDK", "EPPlus\EPPlusSDK.csproj", "{256597F1-67E5-478D-B5B8-3BBB47CB3D3F}"
-EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetCoreTests", "NetCoreTests\NetCoreTests.csproj", "{7D59FAA6-A53F-4672-8387-9281731509F2}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpplusFormulaParser", "EpplusFormulaParser\EpplusFormulaParser.csproj", "{5411F24B-D58C-40F5-9300-E02C28154A4C}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppsheetEpplus", "AppsheetEpplus\AppsheetEpplus.csproj", "{7B288026-5502-4A39-BF41-77E086F3E4A3}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
 		Release|Any CPU = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{256597F1-67E5-478D-B5B8-3BBB47CB3D3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{256597F1-67E5-478D-B5B8-3BBB47CB3D3F}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{256597F1-67E5-478D-B5B8-3BBB47CB3D3F}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{256597F1-67E5-478D-B5B8-3BBB47CB3D3F}.Release|Any CPU.Build.0 = Release|Any CPU
 		{7D59FAA6-A53F-4672-8387-9281731509F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{7D59FAA6-A53F-4672-8387-9281731509F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{7D59FAA6-A53F-4672-8387-9281731509F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -33,6 +29,10 @@
 		{5411F24B-D58C-40F5-9300-E02C28154A4C}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{5411F24B-D58C-40F5-9300-E02C28154A4C}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{5411F24B-D58C-40F5-9300-E02C28154A4C}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7B288026-5502-4A39-BF41-77E086F3E4A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7B288026-5502-4A39-BF41-77E086F3E4A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7B288026-5502-4A39-BF41-77E086F3E4A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7B288026-5502-4A39-BF41-77E086F3E4A3}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
diff --git a/EPPlus/CellStore.cs b/EPPlus/CellStore.cs
deleted file mode 100644
index 684cf3b..0000000
--- a/EPPlus/CellStore.cs
+++ /dev/null
@@ -1,1491 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		    Added       		        2012-11-25
- *******************************************************************************/
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using OfficeOpenXml;
-
-internal class IndexBase : IComparable<IndexBase> {
-  internal short Index;
-
-  public int CompareTo(IndexBase other) {
-    return Index < other.Index
-        ? -1
-        : Index > other.Index
-            ? 1
-            : 0;
-  }
-}
-
-internal class IndexItem : IndexBase {
-  internal int IndexPointer { get; set; }
-}
-
-internal class ColumnIndex : IndexBase {
-  private readonly IndexBase _searchIx = new();
-
-  internal int GetPosition(int row) {
-    var page = (short)(row >> CellStore<int>._pageBits);
-    _searchIx.Index = page;
-    var res =
-        (_pages != null
-                && page >= 0
-                && page < PageCount
-                && page < _pages.Length
-                && _pages[page] != null
-                && _pages[page].Index == page)
-            ? page
-            : Array.BinarySearch(_pages, 0, PageCount, _searchIx);
-    if (res >= 0) {
-      GetPage(row, ref res);
-      return res;
-    }
-    var p = ~res;
-
-    if (GetPage(row, ref p)) {
-      return p;
-    }
-    return res;
-  }
-
-  private bool GetPage(int row, ref int res) {
-    if (res < PageCount && _pages[res].MinIndex <= row && _pages[res].MaxIndex >= row) {
-      return true;
-    }
-    if (res + 1 < PageCount && (_pages[res + 1].MinIndex <= row)) {
-      do {
-        res++;
-      } while (res + 1 < PageCount && _pages[res + 1].MinIndex <= row);
-      //if (res + 1 < PageCount && _pages[res + 1].MaxIndex >= Row)
-      //{
-      return true;
-      //}
-      //else
-      //{
-      //    return false;
-      //}
-    }
-    if (res - 1 >= 0 && _pages[res - 1].MaxIndex >= row) {
-      do {
-        res--;
-      } while (res - 1 > 0 && _pages[res - 1].MaxIndex >= row);
-      //if (res > 0)
-      //{
-      return true;
-      //}
-      //else
-      //{
-      //    return false;
-      //}
-    }
-    return false;
-  }
-
-  internal int GetNextRow(int row) {
-    //var page = (int)((ulong)row >> CellStore<int>.pageBits);
-    var p = GetPosition(row);
-    if (p < 0) {
-      p = ~p;
-      if (p >= PageCount) {
-        return -1;
-      }
-      if (_pages[p].IndexOffset + _pages[p].Rows[0].Index < row) {
-        if (p + 1 >= PageCount) {
-          return -1;
-        }
-        return _pages[p + 1].IndexOffset + _pages[p].Rows[0].Index;
-      }
-      return _pages[p].IndexOffset + _pages[p].Rows[0].Index;
-    }
-    if (p < PageCount) {
-      var r = _pages[p].GetNextRow(row);
-      if (r >= 0) {
-        return _pages[p].IndexOffset + _pages[p].Rows[r].Index;
-      } else {
-        if (++p < PageCount) {
-          return _pages[p].IndexOffset + _pages[p].Rows[0].Index;
-        } else {
-          return -1;
-        }
-      }
-    }
-    return -1;
-  }
-
-  internal PageIndex[] _pages = new PageIndex[CellStore<int>._pagesPerColumnMin];
-  internal int PageCount;
-}
-
-internal class PageIndex : IndexBase {
-  private readonly IndexBase _searchIx = new();
-
-  public PageIndex() {
-    Rows = new IndexItem[CellStore<int>._pageSizeMin];
-    RowCount = 0;
-  }
-
-  public PageIndex(IndexItem[] rows, int count) {
-    Rows = rows;
-    RowCount = count;
-  }
-
-  public PageIndex(PageIndex pageItem, int start, int size)
-      : this(pageItem, start, size, pageItem.Index, pageItem.Offset) {}
-
-  public PageIndex(PageIndex pageItem, int start, int size, short index, int offset) {
-    Rows = new IndexItem[CellStore<int>.GetSize(size)];
-    Array.Copy(pageItem.Rows, start, Rows, 0, size);
-    RowCount = size;
-    Index = index;
-    Offset = offset;
-  }
-
-  internal int Offset;
-
-  internal int IndexOffset => IndexExpanded + Offset;
-
-  internal int IndexExpanded => (Index << CellStore<int>._pageBits);
-
-  internal IndexItem[] Rows { get; set; }
-
-  internal int RowCount;
-
-  internal int GetPosition(int offset) {
-    _searchIx.Index = (short)offset;
-    return (Rows != null
-            && offset > 0
-            && offset - 1 < RowCount
-            && offset - 1 < Rows.Length
-            && Rows[offset - 1] != null
-            && Rows[offset - 1].Index == offset)
-        ? offset - 1
-        : Array.BinarySearch(Rows, 0, RowCount, _searchIx);
-  }
-
-  internal int GetNextRow(int row) {
-    int offset = row - IndexOffset;
-    var o = GetPosition(offset);
-    if (o < 0) {
-      o = ~o;
-      if (o < RowCount) {
-        return o;
-      }
-      return -1;
-    }
-    return o;
-  }
-
-  public int MinIndex {
-    get {
-      if (Rows.Length > 0) {
-        return IndexOffset + Rows[0].Index;
-      }
-      return -1;
-    }
-  }
-
-  public int MaxIndex {
-    get {
-      if (RowCount > 0) {
-        return IndexOffset + Rows[RowCount - 1].Index;
-      }
-      return -1;
-    }
-  }
-
-  public int GetIndex(int pos) {
-    return IndexOffset + Rows[pos].Index;
-  }
-}
-
-/// <summary>
-/// This is the store for all Rows, Columns and Cells.
-/// It is a Dictionary implementation that allows you to change the Key (the RowID, ColumnID or CellID )
-/// </summary>
-internal class CellStore<T> {
-  /**** Size constants ****/
-  internal const int _pageBits = 10; //13bits=8192  Note: Maximum is 13 bits since short is used (PageMax=16K)
-  internal const int _pageSize = 1 << _pageBits;
-  internal const int _pageSizeMin = 1 << 10;
-  internal const int _pageSizeMax = _pageSize << 1; //Double page size
-  internal const int _colSizeMin = 32;
-  internal const int _pagesPerColumnMin = 32;
-
-  private List<T> _values = new();
-  internal ColumnIndex[] _columnIndex = new ColumnIndex[_colSizeMin];
-  internal IndexBase _searchIx = new();
-  internal int ColumnCount;
-
-  ~CellStore() {
-    if (_values != null) {
-      _values.Clear();
-      _values = null;
-    }
-    _columnIndex = null;
-  }
-
-  internal int GetPosition(int column) {
-    _searchIx.Index = (short)column;
-    return (_columnIndex != null
-            && column > 0
-            && column - 1 < ColumnCount
-            && column - 1 < _columnIndex.Length
-            && _columnIndex[column - 1] != null
-            && _columnIndex[column - 1].Index == column)
-        ? column - 1
-        : Array.BinarySearch(_columnIndex, 0, ColumnCount, _searchIx);
-  }
-
-  internal bool GetDimension(out int fromRow, out int fromCol, out int toRow, out int toCol) {
-    if (ColumnCount == 0) {
-      fromRow = fromCol = toRow = toCol = 0;
-      return false;
-    }
-    fromCol = _columnIndex[0].Index;
-    var fromIndex = 0;
-    if (fromCol <= 0 && ColumnCount > 1) {
-      fromCol = _columnIndex[1].Index;
-      fromIndex = 1;
-    } else if (ColumnCount == 1 && fromCol <= 0) {
-      fromRow = fromCol = toRow = toCol = 0;
-      return false;
-    }
-    var col = ColumnCount - 1;
-    while (col > 0) {
-      if (_columnIndex[col].PageCount == 0
-          || _columnIndex[col]._pages[0].RowCount > 1
-          || _columnIndex[col]._pages[0].Rows[0].Index > 0) {
-        break;
-      }
-      col--;
-    }
-    toCol = _columnIndex[col].Index;
-    if (toCol == 0) {
-      fromRow = fromCol = toRow = toCol = 0;
-      return false;
-    }
-    fromRow = toRow = 0;
-
-    for (int c = fromIndex; c < ColumnCount; c++) {
-      int first,
-          last;
-      if (_columnIndex[c].PageCount == 0) {
-        continue;
-      }
-      if (_columnIndex[c]._pages[0].RowCount > 0 && _columnIndex[c]._pages[0].Rows[0].Index > 0) {
-        first = _columnIndex[c]._pages[0].IndexOffset + _columnIndex[c]._pages[0].Rows[0].Index;
-      } else {
-        if (_columnIndex[c]._pages[0].RowCount > 1) {
-          first = _columnIndex[c]._pages[0].IndexOffset + _columnIndex[c]._pages[0].Rows[1].Index;
-        } else if (_columnIndex[c].PageCount > 1) {
-          first = _columnIndex[c]._pages[0].IndexOffset + _columnIndex[c]._pages[1].Rows[0].Index;
-        } else {
-          first = 0;
-        }
-      }
-      var lp = _columnIndex[c].PageCount - 1;
-      while (_columnIndex[c]._pages[lp].RowCount == 0 && lp != 0) {
-        lp--;
-      }
-      var p = _columnIndex[c]._pages[lp];
-      if (p.RowCount > 0) {
-        last = p.IndexOffset + p.Rows[p.RowCount - 1].Index;
-      } else {
-        last = first;
-      }
-      if (first > 0 && (first < fromRow || fromRow == 0)) {
-        fromRow = first;
-      }
-      if (first > 0 && (last > toRow || toRow == 0)) {
-        toRow = last;
-      }
-    }
-    if (fromRow <= 0 || toRow <= 0) {
-      fromRow = fromCol = toRow = toCol = 0;
-      return false;
-    }
-    return true;
-  }
-
-  internal int FindNext(int column) {
-    var c = GetPosition(column);
-    if (c < 0) {
-      return ~c;
-    }
-    return c;
-  }
-
-  internal T GetValue(int row, int column) {
-    int i = GetPointer(row, column);
-    if (i >= 0) {
-      return _values[i];
-    }
-    return default(T);
-  }
-
-  private int GetPointer(int row, int column) {
-    var col = GetPosition(column);
-    if (col >= 0) {
-      var pos = _columnIndex[col].GetPosition(row);
-      if (pos >= 0 && pos < _columnIndex[col].PageCount) {
-        var pageItem = _columnIndex[col]._pages[pos];
-        if (pageItem.MinIndex > row) {
-          pos--;
-          if (pos < 0) {
-            return -1;
-          }
-          pageItem = _columnIndex[col]._pages[pos];
-        }
-        short ix = (short)(row - pageItem.IndexOffset);
-        _searchIx.Index = ix;
-        var cellPos =
-            (pageItem.Rows != null
-                    && ix > 0
-                    && ix - 1 < pageItem.RowCount
-                    && ix - 1 < pageItem.Rows.Length
-                    && pageItem.Rows[ix - 1] != null
-                    && pageItem.Rows[ix - 1].Index == ix)
-                ? ix - 1
-                : Array.BinarySearch(pageItem.Rows, 0, pageItem.RowCount, _searchIx);
-        if (cellPos >= 0) {
-          return pageItem.Rows[cellPos].IndexPointer;
-        } //Cell does not exist
-        return -1;
-      } //Page does not exist
-      return -1;
-    } //Column does not exist
-    return -1;
-  }
-
-  internal bool Exists(int row, int column) {
-    return GetPointer(row, column) >= 0;
-  }
-
-  internal bool Exists(int row, int column, ref T value) {
-    var p = GetPointer(row, column);
-    if (p >= 0) {
-      value = _values[p];
-      return true;
-    }
-    return false;
-  }
-
-  internal void SetValue(int row, int column, T value) {
-    var col =
-        (_columnIndex != null
-                && column > 0
-                && column - 1 < ColumnCount
-                && column - 1 < _columnIndex.Length
-                && _columnIndex[column - 1] != null
-                && _columnIndex[column - 1].Index == column)
-            ? column - 1
-            : Array.BinarySearch(
-                _columnIndex,
-                0,
-                ColumnCount,
-                new IndexBase {
-                  Index = (short)(column),
-                });
-    var page = (short)(row >> _pageBits);
-    if (col >= 0) {
-      //var pos = Array.BinarySearch(_columnIndex[col].Pages, 0, _columnIndex[col].Count, new IndexBase() { Index = page });
-      var pos = _columnIndex[col].GetPosition(row);
-      if (pos < 0) {
-        pos = ~pos;
-        if (pos - 1 < 0 || _columnIndex[col]._pages[pos - 1].IndexOffset + _pageSize - 1 < row) {
-          AddPage(_columnIndex[col], pos, page);
-        } else {
-          pos--;
-        }
-      }
-      if (pos >= _columnIndex[col].PageCount) {
-        AddPage(_columnIndex[col], pos, page);
-      }
-      var pageItem = _columnIndex[col]._pages[pos];
-      if (pageItem.IndexOffset > row) {
-        pos--;
-        page--;
-        if (pos < 0) {
-          throw (new("Unexpected error when setting value"));
-        }
-        pageItem = _columnIndex[col]._pages[pos];
-      }
-
-      short ix = (short)(row - ((pageItem.Index << _pageBits) + pageItem.Offset));
-      _searchIx.Index = ix;
-      var cellPos =
-          (pageItem.Rows != null
-                  && ix >= 0
-                  && ix < pageItem.RowCount
-                  && ix < pageItem.Rows.Length
-                  && pageItem.Rows[ix] != null
-                  && pageItem.Rows[ix].Index == ix)
-              ? ix
-              : Array.BinarySearch(pageItem.Rows, 0, pageItem.RowCount, _searchIx);
-      if (cellPos < 0) {
-        cellPos = ~cellPos;
-        AddCell(_columnIndex[col], pos, cellPos, ix, value);
-      } else {
-        _values[pageItem.Rows[cellPos].IndexPointer] = value;
-      }
-    } else //Column does not exist
-    {
-      col = ~col;
-      AddColumn(col, column);
-      AddPage(_columnIndex[col], 0, page);
-      short ix = (short)(row - (page << _pageBits));
-      AddCell(_columnIndex[col], 0, 0, ix, value);
-    }
-  }
-
-  internal void Insert(int fromRow, int fromCol, int rows, int columns) {
-    if (columns > 0) {
-      var col = GetPosition(fromCol);
-      if (col < 0) {
-        col = ~col;
-      }
-      for (var c = col; c < ColumnCount; c++) {
-        _columnIndex[c].Index += (short)columns;
-      }
-    } else {
-      var page = fromRow >> _pageBits;
-      for (int c = 0; c < ColumnCount; c++) {
-        var column = _columnIndex[c];
-        var pagePos = column.GetPosition(fromRow);
-        if (pagePos >= 0) {
-          if (fromRow >= column._pages[pagePos].MinIndex
-              && fromRow
-                  <= column._pages[pagePos].MaxIndex) //The row is inside the page
-          {
-            int offset = fromRow - column._pages[pagePos].IndexOffset;
-            var rowPos = column._pages[pagePos].GetPosition(offset);
-            if (rowPos < 0) {
-              rowPos = ~rowPos;
-            }
-            UpdateIndexOffset(column, pagePos, rowPos, fromRow, rows);
-          } else if (column._pages[pagePos].MinIndex > fromRow - 1
-              && pagePos
-                  > 0) //The row is on the page before.
-          {
-            int offset = fromRow - ((page - 1) << _pageBits);
-            var rowPos = column._pages[pagePos - 1].GetPosition(offset);
-            if (rowPos > 0 && pagePos > 0) {
-              UpdateIndexOffset(column, pagePos - 1, rowPos, fromRow, rows);
-            }
-          } else if (column.PageCount >= pagePos + 1) {
-            int offset = fromRow - column._pages[pagePos].IndexOffset;
-            var rowPos = column._pages[pagePos].GetPosition(offset);
-            if (rowPos < 0) {
-              rowPos = ~rowPos;
-            }
-            if (column._pages[pagePos].RowCount > rowPos) {
-              UpdateIndexOffset(column, pagePos, rowPos, fromRow, rows);
-            } else {
-              UpdateIndexOffset(column, pagePos + 1, 0, fromRow, rows);
-            }
-          }
-        } else {
-          UpdateIndexOffset(column, ~pagePos, 0, fromRow, rows);
-        }
-      }
-    }
-  }
-
-  internal void Clear(int fromRow, int fromCol, int rows, int columns) {
-    Delete(fromRow, fromCol, rows, columns, false);
-  }
-
-  internal void Delete(int fromRow, int fromCol, int rows, int columns) {
-    Delete(fromRow, fromCol, rows, columns, true);
-  }
-
-  internal void Delete(int fromRow, int fromCol, int rows, int columns, bool shift) {
-    if (columns > 0 && fromRow == 1 && rows >= ExcelPackage.MaxRows) {
-      DeleteColumns(fromCol, columns, shift);
-    } else {
-      var toCol = fromCol + columns - 1;
-      var pageFromRow = fromRow >> _pageBits;
-      for (int c = 0; c < ColumnCount; c++) {
-        var column = _columnIndex[c];
-        if (column.Index >= fromCol) {
-          if (column.Index > toCol) {
-            break;
-          }
-          var pagePos = column.GetPosition(fromRow);
-          if (pagePos < 0) {
-            pagePos = ~pagePos;
-          }
-          if (pagePos < column.PageCount) {
-            var page = column._pages[pagePos];
-            if (shift
-                && page.RowCount > 0
-                && page.MinIndex > fromRow
-                && page.MaxIndex >= fromRow + rows) {
-              var o = page.MinIndex - fromRow;
-              if (o < rows) {
-                rows -= o;
-                page.Offset -= o;
-                UpdatePageOffset(column, pagePos, o);
-              } else {
-                page.Offset -= rows;
-                UpdatePageOffset(column, pagePos, rows);
-                continue;
-              }
-            }
-            if (page.RowCount > 0
-                && page.MinIndex <= fromRow + rows - 1
-                && page.MaxIndex
-                    >= fromRow) //The row is inside the page
-            {
-              var endRow = fromRow + rows;
-              var delEndRow = DeleteCells(column._pages[pagePos], fromRow, endRow, shift);
-              if (shift && delEndRow != fromRow) {
-                UpdatePageOffset(column, pagePos, delEndRow - fromRow);
-              }
-              if (endRow > delEndRow
-                  && pagePos < column.PageCount
-                  && column._pages[pagePos].MinIndex < endRow) {
-                pagePos = (delEndRow == fromRow ? pagePos : pagePos + 1);
-                var rowsLeft = DeletePage(
-                    shift ? fromRow : delEndRow,
-                    endRow - delEndRow,
-                    column,
-                    pagePos,
-                    shift);
-                //if (shift) UpdatePageOffset(column, pagePos, endRow - fromRow - rowsLeft);
-                if (rowsLeft > 0) {
-                  var fr = shift ? fromRow : endRow - rowsLeft;
-                  pagePos = column.GetPosition(fr);
-                  DeleteCells(column._pages[pagePos], fr, shift ? fr + rowsLeft : endRow, shift);
-                  if (shift) {
-                    UpdatePageOffset(column, pagePos, rowsLeft);
-                  }
-                }
-              }
-            } else if (pagePos > 0
-                && column._pages[pagePos].IndexOffset
-                    > fromRow) //The row is on the page before.
-            {
-              int offset = fromRow + rows - 1 - ((pageFromRow - 1) << _pageBits);
-              var rowPos = column._pages[pagePos - 1].GetPosition(offset);
-              if (rowPos > 0 && pagePos > 0) {
-                if (shift) {
-                  UpdateIndexOffset(column, pagePos - 1, rowPos, fromRow + rows - 1, -rows);
-                }
-              }
-            } else {
-              if (shift && pagePos + 1 < column.PageCount) {
-                UpdateIndexOffset(
-                    column,
-                    pagePos + 1,
-                    0,
-                    column._pages[pagePos + 1].MinIndex,
-                    -rows);
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-
-  private void UpdatePageOffset(ColumnIndex column, int pagePos, int rows) {
-    //Update Pageoffset
-
-    if (++pagePos < column.PageCount) {
-      for (int p = pagePos; p < column.PageCount; p++) {
-        if (column._pages[p].Offset - rows <= -_pageSize) {
-          column._pages[p].Index--;
-          column._pages[p].Offset -= rows - _pageSize;
-        } else {
-          column._pages[p].Offset -= rows;
-        }
-      }
-
-      if (Math.Abs(column._pages[pagePos].Offset) > _pageSize
-          || Math.Abs(column._pages[pagePos].Rows[column._pages[pagePos].RowCount - 1].Index)
-              > _pageSizeMax) //Split or Merge???
-      {
-        ResetPageOffset(column, pagePos, rows);
-      }
-    }
-  }
-
-  private void ResetPageOffset(ColumnIndex column, int pagePos, int rows) {
-    PageIndex fromPage = column._pages[pagePos];
-    PageIndex toPage;
-    short pageAdd = 0;
-    if (fromPage.Offset < -_pageSize) {
-      toPage = column._pages[pagePos - 1];
-      pageAdd = -1;
-      if (fromPage.Index - 1 == toPage.Index) {
-        if (fromPage.IndexOffset
-                + fromPage.Rows[fromPage.RowCount - 1].Index
-                - toPage.IndexOffset
-                + toPage.Rows[0].Index
-            <= _pageSizeMax) {
-          MergePage(column, pagePos - 1);
-        }
-      } else //No page after
-      {
-        fromPage.Index -= pageAdd;
-        fromPage.Offset += _pageSize;
-      }
-    } else if (fromPage.Offset > _pageSize) {
-      toPage = column._pages[pagePos + 1];
-      pageAdd = 1;
-      if (fromPage.Index + 1 == toPage.Index) {} else {
-        fromPage.Index += pageAdd;
-        fromPage.Offset += _pageSize;
-      }
-    }
-  }
-
-  private int DeletePage(int fromRow, int rows, ColumnIndex column, int pagePos, bool shift) {
-    PageIndex page = column._pages[pagePos];
-    var startRows = rows;
-    while (page != null
-            && page.MinIndex >= fromRow
-            && ((shift && page.MaxIndex < fromRow + rows)
-                    || (!shift && page.MaxIndex < fromRow + startRows))) {
-      //Delete entire page.
-      var delSize = page.MaxIndex - page.MinIndex + 1;
-      rows -= delSize;
-      var prevOffset = page.Offset;
-      Array.Copy(
-          column._pages,
-          pagePos + 1,
-          column._pages,
-          pagePos,
-          column.PageCount - pagePos + 1);
-      column.PageCount--;
-      if (column.PageCount == 0) {
-        return 0;
-      }
-      if (shift) {
-        for (int i = pagePos; i < column.PageCount; i++) {
-          column._pages[i].Offset -= delSize;
-          if (column._pages[i].Offset <= -_pageSize) {
-            column._pages[i].Index--;
-            column._pages[i].Offset += _pageSize;
-          }
-        }
-      }
-      if (column.PageCount > pagePos) {
-        page = column._pages[pagePos];
-        //page.Offset = pagePos == 0 ? 1 : prevOffset;  //First page can only reference to rows starting from Index == 1
-      } else {
-        //No more pages, return 0
-        return 0;
-      }
-    }
-    return rows;
-  }
-
-  private int DeleteCells(PageIndex page, int fromRow, int toRow, bool shift) {
-    var fromPos = page.GetPosition(fromRow - (page.IndexOffset));
-    if (fromPos < 0) {
-      fromPos = ~fromPos;
-    }
-    var maxRow = page.MaxIndex;
-    var offset = toRow - page.IndexOffset;
-    if (offset > _pageSizeMax) {
-      offset = _pageSizeMax;
-    }
-    var toPos = page.GetPosition(offset);
-    if (toPos < 0) {
-      toPos = ~toPos;
-    }
-
-    if (fromPos <= toPos && fromPos < page.RowCount && page.GetIndex(fromPos) < toRow) {
-      if (toRow > page.MaxIndex) {
-        if (fromRow
-            == page.MinIndex) //Delete entire page, late in the page delete method
-        {
-          return fromRow;
-        }
-        var r = page.MaxIndex;
-        var deletedRow = page.RowCount - fromPos;
-        page.RowCount -= deletedRow;
-        return r + 1;
-      }
-      var rows = toRow - fromRow;
-      if (shift) {
-        UpdateRowIndex(page, toPos, rows);
-      }
-      Array.Copy(page.Rows, toPos, page.Rows, fromPos, page.RowCount - toPos);
-      page.RowCount -= toPos - fromPos;
-
-      return toRow;
-    }
-    if (shift) {
-      UpdateRowIndex(page, toPos, toRow - fromRow);
-    }
-    return toRow < maxRow ? toRow : maxRow;
-  }
-
-  private static void UpdateRowIndex(PageIndex page, int toPos, int rows) {
-    for (int r = toPos; r < page.RowCount; r++) {
-      page.Rows[r].Index -= (short)rows;
-    }
-  }
-
-  private void DeleteColumns(int fromCol, int columns, bool shift) {
-    var fPos = GetPosition(fromCol);
-    if (fPos < 0) {
-      fPos = ~fPos;
-    }
-    int tPos = fPos;
-    for (var c = fPos; c <= ColumnCount; c++) {
-      tPos = c;
-      if (tPos == ColumnCount || _columnIndex[c].Index >= fromCol + columns) {
-        break;
-      }
-    }
-
-    if (ColumnCount <= fPos) {
-      return;
-    }
-
-    if (_columnIndex[fPos].Index >= fromCol && _columnIndex[fPos].Index <= fromCol + columns) {
-      if (tPos < ColumnCount) {
-        Array.Copy(_columnIndex, tPos, _columnIndex, fPos, ColumnCount - tPos);
-      }
-      ColumnCount -= (tPos - fPos);
-    }
-    if (shift) {
-      for (var c = fPos; c < ColumnCount; c++) {
-        _columnIndex[c].Index -= (short)columns;
-      }
-    }
-  }
-
-  private void UpdateIndexOffset(ColumnIndex column, int pagePos, int rowPos, int row, int rows) {
-    if (pagePos >= column.PageCount) {
-      return; //A page after last cell.
-    }
-    var page = column._pages[pagePos];
-    if (rows > _pageSize) {
-      short addPages = (short)(rows >> _pageBits);
-      int offset = +(rows - (_pageSize * addPages));
-      for (int p = pagePos + 1; p < column.PageCount; p++) {
-        if (column._pages[p].Offset + offset > _pageSize) {
-          column._pages[p].Index += (short)(addPages + 1);
-          column._pages[p].Offset += offset - _pageSize;
-        } else {
-          column._pages[p].Index += addPages;
-          column._pages[p].Offset += offset;
-        }
-      }
-
-      var size = page.RowCount - rowPos;
-      if (page.RowCount > rowPos) {
-        if (column.PageCount - 1
-            == pagePos) //No page after, create a new one.
-        {
-          //Copy rows to next page.
-          var newPage = CopyNew(page, rowPos, size);
-          newPage.Index = (short)((row + rows) >> _pageBits);
-          newPage.Offset = row + rows - (newPage.Index * _pageSize) - newPage.Rows[0].Index;
-          if (newPage.Offset > _pageSize) {
-            newPage.Index++;
-            newPage.Offset -= _pageSize;
-          }
-          AddPage(column, pagePos + 1, newPage);
-          page.RowCount = rowPos;
-        } else {
-          if (column._pages[pagePos + 1].RowCount + size
-              > _pageSizeMax) //Split Page
-          {
-            SplitPageInsert(column, pagePos, rowPos, rows, size, addPages);
-          } else //Copy Page.
-          {
-            CopyMergePage(page, rowPos, rows, size, column._pages[pagePos + 1]);
-          }
-        }
-      }
-    } else {
-      //Add to Pages.
-      for (int r = rowPos; r < page.RowCount; r++) {
-        page.Rows[r].Index += (short)rows;
-      }
-      if (page.Offset + page.Rows[page.RowCount - 1].Index
-          >= _pageSizeMax) //Can not be larger than the max size of the page.
-      {
-        AdjustIndex(column, pagePos);
-        if (page.Offset + page.Rows[page.RowCount - 1].Index >= _pageSizeMax) {
-          pagePos = SplitPage(column, pagePos);
-        }
-        //IndexItem[] newRows = new IndexItem[GetSize(page.RowCount - page.Rows[r].Index)];
-        //var newPage = new PageIndex(newRows, r);
-        //newPage.Index = (short)(pagePos + 1);
-        //TODO: MoveRows to next page.
-      }
-
-      for (int p = pagePos + 1; p < column.PageCount; p++) {
-        if (column._pages[p].Offset + rows < _pageSize) {
-          column._pages[p].Offset += rows;
-        } else {
-          column._pages[p].Index++;
-          column._pages[p].Offset = (column._pages[p].Offset + rows) % _pageSize;
-        }
-      }
-    }
-  }
-
-  private void SplitPageInsert(
-      ColumnIndex column,
-      int pagePos,
-      int rowPos,
-      int rows,
-      int size,
-      int addPages) {
-    var newRows = new IndexItem[GetSize(size)];
-    var page = column._pages[pagePos];
-
-    var rStart = -1;
-    for (int r = rowPos; r < page.RowCount; r++) {
-      if (page.IndexExpanded - (page.Rows[r].Index + rows) > _pageSize) {
-        rStart = r;
-        break;
-      }
-      page.Rows[r].Index += (short)rows;
-    }
-    var rc = page.RowCount - rStart;
-    page.RowCount = rStart;
-    if (rc > 0) {
-      //Copy to a new page
-      var row = page.IndexOffset;
-      var newPage = CopyNew(page, rStart, rc);
-      var ix = (short)(page.Index + addPages);
-      var offset = page.IndexOffset + rows - (ix * _pageSize);
-      if (offset > _pageSize) {
-        ix += (short)(offset / _pageSize);
-        offset %= _pageSize;
-      }
-      newPage.Index = ix;
-      newPage.Offset = offset;
-      AddPage(column, pagePos + 1, newPage);
-    }
-
-    //Copy from next Row
-  }
-
-  private void CopyMergePage(PageIndex page, int rowPos, int rows, int size, PageIndex toPage) {
-    var startRow = page.IndexOffset + page.Rows[rowPos].Index + rows;
-    var newRows = new IndexItem[GetSize(toPage.RowCount + size)];
-    page.RowCount -= size;
-    Array.Copy(page.Rows, rowPos, newRows, 0, size);
-    for (int r = 0; r < size; r++) {
-      newRows[r].Index += (short)(page.IndexOffset + rows - toPage.IndexOffset);
-    }
-
-    Array.Copy(toPage.Rows, 0, newRows, size, toPage.RowCount);
-    toPage.Rows = newRows;
-    toPage.RowCount += size;
-  }
-
-  private void MergePage(ColumnIndex column, int pagePos) {
-    PageIndex page1 = column._pages[pagePos];
-    PageIndex page2 = column._pages[pagePos + 1];
-
-    var newPage = new PageIndex(page1, 0, page1.RowCount + page2.RowCount);
-    newPage.RowCount = page1.RowCount + page2.RowCount;
-    Array.Copy(page1.Rows, 0, newPage.Rows, 0, page1.RowCount);
-    Array.Copy(page2.Rows, 0, newPage.Rows, page1.RowCount, page2.RowCount);
-    for (int r = page1.RowCount; r < newPage.RowCount; r++) {
-      newPage.Rows[r].Index += (short)(page2.IndexOffset - page1.IndexOffset);
-    }
-
-    column._pages[pagePos] = newPage;
-    column.PageCount--;
-
-    if (column.PageCount > (pagePos + 1)) {
-      Array.Copy(
-          column._pages,
-          pagePos + 2,
-          column._pages,
-          pagePos + 1,
-          column.PageCount - (pagePos + 1));
-      for (int p = pagePos + 1; p < column.PageCount; p++) {
-        column._pages[p].Index--;
-        column._pages[p].Offset += _pageSize;
-      }
-    }
-  }
-
-  private PageIndex CopyNew(PageIndex pageFrom, int rowPos, int size) {
-    IndexItem[] newRows = new IndexItem[GetSize(size)];
-    Array.Copy(pageFrom.Rows, rowPos, newRows, 0, size);
-    return new(newRows, size);
-  }
-
-  internal static int GetSize(int size) {
-    var newSize = 256;
-    while (newSize < size) {
-      newSize <<= 1;
-    }
-    return newSize;
-  }
-
-  private void AddCell(ColumnIndex columnIndex, int pagePos, int pos, short ix, T value) {
-    PageIndex pageItem = columnIndex._pages[pagePos];
-    if (pageItem.RowCount == pageItem.Rows.Length) {
-      if (pageItem.RowCount
-          == _pageSizeMax) //Max size-->Split
-      {
-        pagePos = SplitPage(columnIndex, pagePos);
-        if (columnIndex._pages[pagePos - 1].RowCount > pos) {
-          pagePos--;
-        } else {
-          pos -= columnIndex._pages[pagePos - 1].RowCount;
-        }
-        pageItem = columnIndex._pages[pagePos];
-      } else //Expand to double size.
-      {
-        var rowsTmp = new IndexItem[pageItem.Rows.Length << 1];
-        Array.Copy(pageItem.Rows, 0, rowsTmp, 0, pageItem.RowCount);
-        pageItem.Rows = rowsTmp;
-      }
-    }
-    if (pos < pageItem.RowCount) {
-      Array.Copy(pageItem.Rows, pos, pageItem.Rows, pos + 1, pageItem.RowCount - pos);
-    }
-    pageItem.Rows[pos] = new() {
-      Index = ix,
-      IndexPointer = _values.Count,
-    };
-    _values.Add(value);
-    pageItem.RowCount++;
-  }
-
-  private int SplitPage(ColumnIndex columnIndex, int pagePos) {
-    var page = columnIndex._pages[pagePos];
-    if (page.Offset != 0) {
-      var offset = page.Offset;
-      page.Offset = 0;
-      for (int r = 0; r < page.RowCount; r++) {
-        page.Rows[r].Index -= (short)offset;
-      }
-    }
-    //Find Split pos
-    int splitPos = 0;
-    for (int r = 0; r < page.RowCount; r++) {
-      if (page.Rows[r].Index > _pageSize) {
-        splitPos = r;
-        break;
-      }
-    }
-    var newPage = new PageIndex(page, 0, splitPos);
-    var nextPage = new PageIndex(
-        page,
-        splitPos,
-        page.RowCount - splitPos,
-        (short)(page.Index + 1),
-        page.Offset);
-
-    for (int r = 0; r < nextPage.RowCount; r++) {
-      nextPage.Rows[r].Index = (short)(nextPage.Rows[r].Index - _pageSize);
-    }
-
-    columnIndex._pages[pagePos] = newPage;
-    if (columnIndex.PageCount + 1 > columnIndex._pages.Length) {
-      var pageTmp = new PageIndex[columnIndex._pages.Length << 1];
-      Array.Copy(columnIndex._pages, 0, pageTmp, 0, columnIndex.PageCount);
-      columnIndex._pages = pageTmp;
-    }
-    Array.Copy(
-        columnIndex._pages,
-        pagePos + 1,
-        columnIndex._pages,
-        pagePos + 2,
-        columnIndex.PageCount - pagePos - 1);
-    columnIndex._pages[pagePos + 1] = nextPage;
-    page = nextPage;
-    //pos -= PageSize;
-    columnIndex.PageCount++;
-    return pagePos + 1;
-  }
-
-  private PageIndex AdjustIndex(ColumnIndex columnIndex, int pagePos) {
-    PageIndex page = columnIndex._pages[pagePos];
-    //First Adjust indexes
-    if (page.Offset + page.Rows[0].Index >= _pageSize
-        || page.Offset >= _pageSize
-        || page.Rows[0].Index >= _pageSize) {
-      page.Index++;
-      page.Offset -= _pageSize;
-    } else if (page.Offset + page.Rows[0].Index <= -_pageSize
-        || page.Offset <= -_pageSize
-        || page.Rows[0].Index <= -_pageSize) {
-      page.Index--;
-      page.Offset += _pageSize;
-    }
-    return page;
-  }
-
-  private void AddPage(ColumnIndex column, int pos, short index) {
-    AddPage(column, pos);
-    column._pages[pos] = new() {
-      Index = index,
-    };
-    if (pos > 0) {
-      var pp = column._pages[pos - 1];
-      if (pp.RowCount > 0 && pp.Rows[pp.RowCount - 1].Index > _pageSize) {
-        column._pages[pos].Offset = pp.Rows[pp.RowCount - 1].Index - _pageSize;
-      }
-    }
-  }
-
-  /// <summary>
-  /// Add a new page to the collection
-  /// </summary>
-  /// <param name="column">The column</param>
-  /// <param name="pos">Position</param>
-  /// <param name="page">The new page object to add</param>
-  private void AddPage(ColumnIndex column, int pos, PageIndex page) {
-    AddPage(column, pos);
-    column._pages[pos] = page;
-  }
-
-  /// <summary>
-  /// Add a new page to the collection
-  /// </summary>
-  /// <param name="column">The column</param>
-  /// <param name="pos">Position</param>
-  private void AddPage(ColumnIndex column, int pos) {
-    if (column.PageCount == column._pages.Length) {
-      var pageTmp = new PageIndex[column._pages.Length * 2];
-      Array.Copy(column._pages, 0, pageTmp, 0, column.PageCount);
-      column._pages = pageTmp;
-    }
-    if (pos < column.PageCount) {
-      Array.Copy(column._pages, pos, column._pages, pos + 1, column.PageCount - pos);
-    }
-    column.PageCount++;
-  }
-
-  private void AddColumn(int pos, int column) {
-    if (ColumnCount == _columnIndex.Length) {
-      var colTmp = new ColumnIndex[_columnIndex.Length * 2];
-      Array.Copy(_columnIndex, 0, colTmp, 0, ColumnCount);
-      _columnIndex = colTmp;
-    }
-    if (pos < ColumnCount) {
-      Array.Copy(_columnIndex, pos, _columnIndex, pos + 1, ColumnCount - pos);
-    }
-    _columnIndex[pos] = new() {
-      Index = (short)(column),
-    };
-    ColumnCount++;
-  }
-
-  internal bool NextCell(ref int row, ref int col) {
-    return NextCell(ref row, ref col, 0, 0, ExcelPackage.MaxRows, ExcelPackage.MaxColumns);
-  }
-
-  internal bool NextCell(
-      ref int row,
-      ref int col,
-      int minRow,
-      int minColPos,
-      int maxRow,
-      int maxColPos) {
-    if (minColPos >= ColumnCount) {
-      return false;
-    }
-    if (maxColPos >= ColumnCount) {
-      maxColPos = ColumnCount - 1;
-    }
-    var c = GetPosition(col);
-    if (c >= 0) {
-      if (c > maxColPos) {
-        if (col <= minColPos) {
-          return false;
-        }
-        col = minColPos;
-        return NextCell(ref row, ref col);
-      }
-      var r = GetNextCell(ref row, ref c, minColPos, maxRow, maxColPos);
-      col = _columnIndex[c].Index;
-      return r;
-    }
-    c = ~c;
-    if (c > _columnIndex[c].Index) {
-      if (col <= minColPos) {
-        return false;
-      }
-      col = minColPos;
-      return NextCell(ref row, ref col, minRow, minColPos, maxRow, maxColPos);
-    }
-    {
-      var r = GetNextCell(ref c, ref row, minColPos, maxRow, maxColPos);
-      col = _columnIndex[c].Index;
-      return r;
-    }
-  }
-
-  internal bool GetNextCell(
-      ref int row,
-      ref int colPos,
-      int startColPos,
-      int endRow,
-      int endColPos) {
-    if (ColumnCount == 0) {
-      return false;
-    }
-    if (++colPos < ColumnCount && colPos <= endColPos) {
-      var r = _columnIndex[colPos].GetNextRow(row);
-      if (r
-          == row) //Exists next Row
-      {
-        return true;
-      }
-      int minRow,
-          minCol;
-      if (r > row) {
-        minRow = r;
-        minCol = colPos;
-      } else {
-        minRow = int.MaxValue;
-        minCol = 0;
-      }
-
-      var c = colPos + 1;
-      while (c < ColumnCount && c <= endColPos) {
-        r = _columnIndex[c].GetNextRow(row);
-        if (r
-            == row) //Exists next Row
-        {
-          colPos = c;
-          return true;
-        }
-        if (r > row && r < minRow) {
-          minRow = r;
-          minCol = c;
-        }
-        c++;
-      }
-      c = startColPos;
-      if (row < endRow) {
-        row++;
-        while (c < colPos) {
-          r = _columnIndex[c].GetNextRow(row);
-          if (r
-              == row) //Exists next Row
-          {
-            colPos = c;
-            return true;
-          }
-          if (r > row && (r < minRow || (r == minRow && c < minCol)) && r <= endRow) {
-            minRow = r;
-            minCol = c;
-          }
-          c++;
-        }
-      }
-
-      if (minRow == int.MaxValue || minRow > endRow) {
-        return false;
-      }
-      row = minRow;
-      colPos = minCol;
-      return true;
-    }
-    if (colPos <= startColPos || row >= endRow) {
-      return false;
-    }
-    colPos = startColPos - 1;
-    row++;
-    return GetNextCell(ref row, ref colPos, startColPos, endRow, endColPos);
-  }
-
-  internal bool PrevCell(ref int row, ref int col) {
-    return PrevCell(ref row, ref col, 0, 0, ExcelPackage.MaxRows, ExcelPackage.MaxColumns);
-  }
-
-  private bool PrevCell(
-      ref int row,
-      ref int col,
-      int minRow,
-      int minColPos,
-      int maxRow,
-      int maxColPos) {
-    if (minColPos >= ColumnCount) {
-      return false;
-    }
-    if (maxColPos >= ColumnCount) {
-      maxColPos = ColumnCount - 1;
-    }
-    var c = GetPosition(col);
-    if (c >= 0) {
-      if (c == 0) {
-        if (col >= maxColPos) {
-          return false;
-        }
-        if (row == minRow) {
-          return false;
-        }
-        row--;
-        col = maxColPos;
-        return PrevCell(ref row, ref col, minRow, minColPos, maxRow, maxColPos);
-      }
-      var ret = GetPrevCell(ref row, ref c, minRow, minColPos, maxColPos);
-      if (ret) {
-        col = _columnIndex[c].Index;
-      }
-      return ret;
-    }
-    c = ~c;
-    if (c == 0) {
-      if (col >= maxColPos || row <= 0) {
-        return false;
-      }
-      col = maxColPos;
-      row--;
-      return PrevCell(ref row, ref col, minRow, minColPos, maxRow, maxColPos);
-    }
-    {
-      var ret = GetPrevCell(ref row, ref c, minRow, minColPos, maxColPos);
-      if (ret) {
-        col = _columnIndex[c].Index;
-      }
-      return ret;
-    }
-  }
-
-  internal bool GetPrevCell(
-      ref int row,
-      ref int colPos,
-      int startRow,
-      int startColPos,
-      int endColPos) {
-    if (ColumnCount == 0) {
-      return false;
-    }
-    if (--colPos >= startColPos)
-    //                if (++colPos < ColumnCount && colPos <= endColPos)
-    {
-      var r = _columnIndex[colPos].GetNextRow(row);
-      if (r
-          == row) //Exists next Row
-      {
-        return true;
-      }
-      int minRow,
-          minCol;
-      if (r > row && r >= startRow) {
-        minRow = r;
-        minCol = colPos;
-      } else {
-        minRow = int.MaxValue;
-        minCol = 0;
-      }
-
-      var c = colPos - 1;
-      if (c >= startColPos) {
-        while (c >= startColPos) {
-          r = _columnIndex[c].GetNextRow(row);
-          if (r
-              == row) //Exists next Row
-          {
-            colPos = c;
-            return true;
-          }
-          if (r > row && r < minRow && r >= startRow) {
-            minRow = r;
-            minCol = c;
-          }
-          c--;
-        }
-      }
-      if (row > startRow) {
-        c = endColPos;
-        row--;
-        while (c > colPos) {
-          r = _columnIndex[c].GetNextRow(row);
-          if (r
-              == row) //Exists next Row
-          {
-            colPos = c;
-            return true;
-          }
-          if (r > row && r < minRow && r >= startRow) {
-            minRow = r;
-            minCol = c;
-          }
-          c--;
-        }
-      }
-      if (minRow == int.MaxValue || startRow < minRow) {
-        return false;
-      }
-      row = minRow;
-      colPos = minCol;
-      return true;
-    }
-    colPos = ColumnCount;
-    row--;
-    if (row < startRow) {
-      return false;
-    }
-    return GetPrevCell(ref colPos, ref row, startRow, startColPos, endColPos);
-  }
-}
-
-internal class CellsStoreEnumerator<T> : IEnumerable<T>, IEnumerator<T> {
-  private readonly CellStore<T> _cellStore;
-  private int row,
-      colPos;
-  private int[] pagePos,
-      cellPos;
-  private readonly int _startRow;
-  private readonly int _startCol;
-  private readonly int _endRow;
-  private readonly int _endCol;
-  private int minRow,
-      minColPos,
-      maxRow,
-      maxColPos;
-
-  public CellsStoreEnumerator(CellStore<T> cellStore)
-      : this(cellStore, 0, 0, ExcelPackage.MaxRows, ExcelPackage.MaxColumns) {}
-
-  public CellsStoreEnumerator(
-      CellStore<T> cellStore,
-      int startRow,
-      int startCol,
-      int endRow,
-      int endCol) {
-    _cellStore = cellStore;
-
-    _startRow = startRow;
-    _startCol = startCol;
-    _endRow = endRow;
-    _endCol = endCol;
-
-    Init();
-  }
-
-  internal void Init() {
-    minRow = _startRow;
-    maxRow = _endRow;
-
-    minColPos = _cellStore.GetPosition(_startCol);
-    if (minColPos < 0) {
-      minColPos = ~minColPos;
-    }
-    maxColPos = _cellStore.GetPosition(_endCol);
-    if (maxColPos < 0) {
-      maxColPos = ~maxColPos - 1;
-    }
-    row = minRow;
-    colPos = minColPos - 1;
-
-    var cols = maxColPos - minColPos + 1;
-    pagePos = new int[cols];
-    cellPos = new int[cols];
-    for (int i = 0; i < cols; i++) {
-      pagePos[i] = -1;
-      cellPos[i] = -1;
-    }
-  }
-
-  internal int Row => row;
-
-  internal int Column {
-    get {
-      if (colPos == -1) {
-        MoveNext();
-      }
-      if (colPos == -1) {
-        return 0;
-      }
-      return _cellStore._columnIndex[colPos].Index;
-    }
-  }
-
-  internal T Value {
-    get => _cellStore.GetValue(row, Column);
-    set => _cellStore.SetValue(row, Column, value);
-  }
-
-  internal bool Next() {
-    return _cellStore.GetNextCell(ref row, ref colPos, minColPos, maxRow, maxColPos);
-  }
-
-  public string CellAddress => ExcelCellBase.GetAddress(Row, Column);
-
-  public IEnumerator<T> GetEnumerator() {
-    Reset();
-    return this;
-  }
-
-  IEnumerator IEnumerable.GetEnumerator() {
-    Reset();
-    return this;
-  }
-
-  public T Current => Value;
-
-  public void Dispose() {}
-
-  object IEnumerator.Current {
-    get {
-      Reset();
-      return this;
-    }
-  }
-
-  public bool MoveNext() {
-    return Next();
-  }
-
-  public void Reset() {
-    Init();
-  }
-}
-
-internal class FlagCellStore : CellStore<byte> {
-  internal void SetFlagValue(int row, int col, bool value, CellFlags cellFlags) {
-    CellFlags currentValue = (CellFlags)GetValue(row, col);
-    if (value) {
-      SetValue(row, col, (byte)(currentValue | cellFlags)); // add the CellFlag bit
-    } else {
-      SetValue(row, col, (byte)(currentValue & ~cellFlags)); // remove the CellFlag bit
-    }
-  }
-
-  internal bool GetFlagValue(int row, int col, CellFlags cellFlags) {
-    return !(((byte)cellFlags & GetValue(row, col)) == 0);
-  }
-}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingAverageGroup.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingAverageGroup.cs
deleted file mode 100644
index 77efc3f..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingAverageGroup.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingAverageGroup
-/// </summary>
-public interface IExcelConditionalFormattingAverageGroup : IExcelConditionalFormattingRule {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingBeginsWith.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingBeginsWith.cs
deleted file mode 100644
index 8bc7c8f..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingBeginsWith.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingBeginsWith
-/// </summary>
-public interface IExcelConditionalFormattingBeginsWith
-    : IExcelConditionalFormattingRule,
-      IExcelConditionalFormattingWithText {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingBetween.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingBetween.cs
deleted file mode 100644
index 6d56a9e..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingBetween.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingBetween
-/// </summary>
-public interface IExcelConditionalFormattingBetween
-    : IExcelConditionalFormattingRule,
-      IExcelConditionalFormattingWithFormula2 {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingColorScaleGroup.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingColorScaleGroup.cs
deleted file mode 100644
index 8f33fc0..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingColorScaleGroup.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingColorScaleGroup
-/// </summary>
-public interface IExcelConditionalFormattingColorScaleGroup : IExcelConditionalFormattingRule {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsBlanks.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsBlanks.cs
deleted file mode 100644
index 4d05109..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsBlanks.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingContainsBlanks
-/// </summary>
-public interface IExcelConditionalFormattingContainsBlanks : IExcelConditionalFormattingRule {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsErrors.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsErrors.cs
deleted file mode 100644
index a668e11..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsErrors.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingContainsErrors
-/// </summary>
-public interface IExcelConditionalFormattingContainsErrors : IExcelConditionalFormattingRule {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsText.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsText.cs
deleted file mode 100644
index 5919f90..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsText.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingContainsText
-/// </summary>
-public interface IExcelConditionalFormattingContainsText
-    : IExcelConditionalFormattingRule,
-      IExcelConditionalFormattingWithText {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingDataBarGroup.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingDataBarGroup.cs
deleted file mode 100644
index 91abb7d..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingDataBarGroup.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingDataBar
-/// </summary>
-public interface IExcelConditionalFormattingDataBarGroup : IExcelConditionalFormattingRule {
-  /// <summary>
-  /// ShowValue
-  /// </summary>
-  bool ShowValue { get; set; }
-
-  /// <summary>
-  /// Databar Low Value
-  /// </summary>
-  ExcelConditionalFormattingIconDataBarValue LowValue { get; }
-
-  /// <summary>
-  /// Databar High Value
-  /// </summary>
-  ExcelConditionalFormattingIconDataBarValue HighValue { get; }
-}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingDuplicateValues.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingDuplicateValues.cs
deleted file mode 100644
index 32427f9..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingDuplicateValues.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingDuplicateValues
-/// </summary>
-public interface IExcelConditionalFormattingDuplicateValues : IExcelConditionalFormattingRule {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingEndsWith.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingEndsWith.cs
deleted file mode 100644
index d45c296..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingEndsWith.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingEndsWith
-/// </summary>
-public interface IExcelConditionalFormattingEndsWith
-    : IExcelConditionalFormattingRule,
-      IExcelConditionalFormattingWithText {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingEqual.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingEqual.cs
deleted file mode 100644
index 91c9663..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingEqual.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingEqual
-/// </summary>
-public interface IExcelConditionalFormattingEqual
-    : IExcelConditionalFormattingRule,
-      IExcelConditionalFormattingWithFormula {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingExpression.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingExpression.cs
deleted file mode 100644
index aa23a69..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingExpression.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingExpression
-/// </summary>
-public interface IExcelConditionalFormattingExpression
-    : IExcelConditionalFormattingRule,
-      IExcelConditionalFormattingWithFormula {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingFiveIconSet.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingFiveIconSet.cs
deleted file mode 100644
index 2954b3e..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingFiveIconSet.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingFiveIconSet
-/// </summary>eExcelconditionalFormatting4IconsSetType
-public interface IExcelConditionalFormattingFiveIconSet
-    : IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting5IconsSetType> {
-  /// <summary>
-  /// Icon5 (part of the 5 Icon Set)
-  /// </summary>
-  ExcelConditionalFormattingIconDataBarValue Icon5 { get; }
-}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingFourIconSet.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingFourIconSet.cs
deleted file mode 100644
index 67da2ba..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingFourIconSet.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingFourIconSet
-/// </summary>
-public interface IExcelConditionalFormattingFourIconSet<T>
-    : IExcelConditionalFormattingThreeIconSet<T> {
-  /// <summary>
-  /// Icon4 (part of the 4 ou 5 Icon Set)
-  /// </summary>
-  ExcelConditionalFormattingIconDataBarValue Icon4 { get; }
-}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingGreaterThan.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingGreaterThan.cs
deleted file mode 100644
index 9287f3f..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingGreaterThan.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingGreaterThan
-/// </summary>
-public interface IExcelConditionalFormattingGreaterThan
-    : IExcelConditionalFormattingRule,
-      IExcelConditionalFormattingWithFormula {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingGreaterThanOrEqual.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingGreaterThanOrEqual.cs
deleted file mode 100644
index aa084cc..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingGreaterThanOrEqual.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingGreaterThanOrEqual
-/// </summary>
-public interface IExcelConditionalFormattingGreaterThanOrEqual
-    : IExcelConditionalFormattingRule,
-      IExcelConditionalFormattingWithFormula {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingIconSetGroup.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingIconSetGroup.cs
deleted file mode 100644
index 770d75b..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingIconSetGroup.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingIconSetGroup
-/// </summary>
-public interface IExcelConditionalFormattingIconSetGroup<T> : IExcelConditionalFormattingRule {
-  /// <summary>
-  /// Reverse
-  /// </summary>
-  bool Reverse { get; set; }
-
-  /// <summary>
-  /// ShowValue
-  /// </summary>
-  bool ShowValue { get; set; }
-}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingLessThan.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingLessThan.cs
deleted file mode 100644
index 162a16c..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingLessThan.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingLessThan
-/// </summary>
-public interface IExcelConditionalFormattingLessThan
-    : IExcelConditionalFormattingRule,
-      IExcelConditionalFormattingWithFormula {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingLessThanOrEqual.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingLessThanOrEqual.cs
deleted file mode 100644
index fce6064..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingLessThanOrEqual.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingGreaterThanOrEqual
-/// </summary>
-public interface IExcelConditionalFormattingLessThanOrEqual
-    : IExcelConditionalFormattingRule,
-      IExcelConditionalFormattingWithFormula {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotBetween.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotBetween.cs
deleted file mode 100644
index a017b81..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotBetween.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingNotBetween
-/// </summary>
-public interface IExcelConditionalFormattingNotBetween
-    : IExcelConditionalFormattingRule,
-      IExcelConditionalFormattingWithFormula2 {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsBlanks.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsBlanks.cs
deleted file mode 100644
index 4743b3b..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsBlanks.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingNotContainsBlanks
-/// </summary>
-public interface IExcelConditionalFormattingNotContainsBlanks : IExcelConditionalFormattingRule {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsErrors.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsErrors.cs
deleted file mode 100644
index aa42a1c..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsErrors.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingNotContainsErrors
-/// </summary>
-public interface IExcelConditionalFormattingNotContainsErrors : IExcelConditionalFormattingRule {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsText.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsText.cs
deleted file mode 100644
index 5a427f4..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsText.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingNotContainsText
-/// </summary>
-public interface IExcelConditionalFormattingNotContainsText
-    : IExcelConditionalFormattingRule,
-      IExcelConditionalFormattingWithText {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotEqual.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotEqual.cs
deleted file mode 100644
index f20f33a..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotEqual.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingNotEqual
-/// </summary>
-public interface IExcelConditionalFormattingNotEqual
-    : IExcelConditionalFormattingRule,
-      IExcelConditionalFormattingWithFormula {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingRule.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingRule.cs
deleted file mode 100644
index e88b5af..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingRule.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						              Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting         2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.Style.Dxf;
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// Interface for conditional formatting rule
-/// </summary>
-public interface IExcelConditionalFormattingRule {
-  /// <summary>
-  /// The 'cfRule' XML node
-  /// </summary>
-  XmlNode Node { get; }
-
-  /// <summary>
-  /// Type of conditional formatting rule. ST_CfType §18.18.12.
-  /// </summary>
-  eExcelConditionalFormattingRuleType Type { get; }
-
-  /// <summary>
-  /// <para>Range over which these conditional formatting rules apply.</para>
-  /// <para>The possible values for this attribute are defined by the
-  /// ST_Sqref simple type (§18.18.76).</para>
-  /// </summary>
-  ExcelAddress Address { get; set; }
-
-  /// <summary>
-  /// The priority of this conditional formatting rule. This value is used to determine
-  /// which format should be evaluated and rendered. Lower numeric values are higher
-  /// priority than higher numeric values, where 1 is the highest priority.
-  /// </summary>
-  int Priority { get; set; }
-
-  /// <summary>
-  /// If this flag is 1, no rules with lower priority shall be applied over this rule,
-  /// when this rule evaluates to true.
-  /// </summary>
-  bool StopIfTrue { get; set; }
-
-  ///// <summary>
-  ///// <para>This is an index to a dxf element in the Styles Part indicating which cell
-  ///// formatting to apply when the conditional formatting rule criteria is met.</para>
-  ///// <para>The possible values for this attribute are defined by the ST_DxfId simple type
-  ///// (§18.18.25).</para>
-  ///// </summary>
-  //    int DxfId { get; set; }
-  /// <summary>
-  /// Gives access to the differencial styling (DXF) for the rule.
-  /// </summary>
-  ExcelDxfStyleConditionalFormatting Style { get; }
-}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingStdDevGroup.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingStdDevGroup.cs
deleted file mode 100644
index 1aca982..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingStdDevGroup.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingStdDevGroup
-/// </summary>
-public interface IExcelConditionalFormattingStdDevGroup
-    : IExcelConditionalFormattingRule,
-      IExcelConditionalFormattingWithStdDev {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingThreeColorScale.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingThreeColorScale.cs
deleted file mode 100644
index eca66d1..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingThreeColorScale.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingThreeColorScale
-/// </summary>
-public interface IExcelConditionalFormattingThreeColorScale
-    : IExcelConditionalFormattingTwoColorScale {
-  /// <summary>
-  /// Three Color Scale Middle Value
-  /// </summary>
-  ExcelConditionalFormattingColorScaleValue MiddleValue { get; set; }
-}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingThreeIconSet.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingThreeIconSet.cs
deleted file mode 100644
index 0fdc397..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingThreeIconSet.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingThreeIconSet
-/// </summary>
-public interface IExcelConditionalFormattingThreeIconSet<T>
-    : IExcelConditionalFormattingIconSetGroup<T> {
-  /// <summary>
-  /// Icon1 (part of the 3, 4 ou 5 Icon Set)
-  /// </summary>
-  ExcelConditionalFormattingIconDataBarValue Icon1 { get; }
-
-  /// <summary>
-  /// Icon2 (part of the 3, 4 ou 5 Icon Set)
-  /// </summary>
-  ExcelConditionalFormattingIconDataBarValue Icon2 { get; }
-
-  /// <summary>
-  /// Icon3 (part of the 3, 4 ou 5 Icon Set)
-  /// </summary>
-  ExcelConditionalFormattingIconDataBarValue Icon3 { get; }
-}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTimePeriodGroup.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTimePeriodGroup.cs
deleted file mode 100644
index 266c1b8..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTimePeriodGroup.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingTimePeriod
-/// </summary>
-public interface IExcelConditionalFormattingTimePeriodGroup : IExcelConditionalFormattingRule {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTopBottomGroup.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTopBottomGroup.cs
deleted file mode 100644
index 234d925..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTopBottomGroup.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingTopBottomGroup
-/// </summary>
-public interface IExcelConditionalFormattingTopBottomGroup
-    : IExcelConditionalFormattingRule,
-      IExcelConditionalFormattingWithRank {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTwoColorScale.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTwoColorScale.cs
deleted file mode 100644
index 2662b9a..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTwoColorScale.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingTwoColorScale
-/// </summary>
-public interface IExcelConditionalFormattingTwoColorScale
-    : IExcelConditionalFormattingColorScaleGroup {
-  /// <summary>
-  /// Two Color Scale Low Value
-  /// </summary>
-  ExcelConditionalFormattingColorScaleValue LowValue { get; set; }
-
-  /// <summary>
-  /// Two Color Scale High Value
-  /// </summary>
-  ExcelConditionalFormattingColorScaleValue HighValue { get; set; }
-}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingUniqueValues.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingUniqueValues.cs
deleted file mode 100644
index ee55553..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingUniqueValues.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingUniqueValues
-/// </summary>
-public interface IExcelConditionalFormattingUniqueValues : IExcelConditionalFormattingRule {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithFormula.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithFormula.cs
deleted file mode 100644
index d612008..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithFormula.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingWithFormula
-/// </summary>
-public interface IExcelConditionalFormattingWithFormula {
-  /// <summary>
-  /// Formula Attribute
-  /// </summary>
-  string Formula { get; set; }
-}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithFormula2.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithFormula2.cs
deleted file mode 100644
index b7a940a..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithFormula2.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingWithFormula2
-/// </summary>
-public interface IExcelConditionalFormattingWithFormula2 : IExcelConditionalFormattingWithFormula {
-  /// <summary>
-  /// Formula2 Attribute
-  /// </summary>
-  string Formula2 { get; set; }
-}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithRank.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithRank.cs
deleted file mode 100644
index de220ed..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithRank.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-using System;
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingWithRank
-/// </summary>
-public interface IExcelConditionalFormattingWithRank {
-  /// <summary>
-  /// Rank Attribute
-  /// </summary>
-  UInt16 Rank { get; set; }
-}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithReverse.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithReverse.cs
deleted file mode 100644
index 405a8a5..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithReverse.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingWithReverse
-/// </summary>
-public interface IExcelConditionalFormattingWithReverse {
-  /// <summary>
-  /// Reverse Attribute
-  /// </summary>
-  bool Reverse { get; set; }
-}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithShowValue.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithShowValue.cs
deleted file mode 100644
index 479627b..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithShowValue.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingWithShowValue
-/// </summary>
-public interface IExcelConditionalFormattingWithShowValue {
-  /// <summary>
-  /// ShowValue Attribute
-  /// </summary>
-  bool ShowValue { get; set; }
-}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithStdDev.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithStdDev.cs
deleted file mode 100644
index d3cf330..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithStdDev.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-using System;
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingWithStdDev
-/// </summary>
-public interface IExcelConditionalFormattingWithStdDev {
-  /// <summary>
-  /// StdDev Attribute
-  /// </summary>
-  UInt16 StdDev { get; set; }
-}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithText.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithText.cs
deleted file mode 100644
index bfe91a4..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithText.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting.Contracts;
-
-/// <summary>
-/// IExcelConditionalFormattingWithText
-/// </summary>
-public interface IExcelConditionalFormattingWithText {
-  /// <summary>
-  /// Text Attribute
-  /// </summary>
-  string Text { get; set; }
-}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IRangeConditionalFormatting.cs b/EPPlus/ConditionalFormatting/Contracts/IRangeConditionalFormatting.cs
deleted file mode 100644
index bd84006..0000000
--- a/EPPlus/ConditionalFormatting/Contracts/IRangeConditionalFormatting.cs
+++ /dev/null
@@ -1,286 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author             Change                    Date
- * ******************************************************************************
- * Eyal Seagull		    Conditional Formatting    2012-04-03
- *******************************************************************************/
-
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// Provides functionality for adding Conditional Formatting to a range (<see cref="ExcelRangeBase"/>).
-/// Each method will return a configurable condtional formatting type.
-/// </summary>
-public interface IRangeConditionalFormatting {
-  /// <summary>
-  /// Adds a Above Average rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingAverageGroup AddAboveAverage();
-
-  /// <summary>
-  /// Adds a Above Or Equal Average rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingAverageGroup AddAboveOrEqualAverage();
-
-  /// <summary>
-  /// Adds a Below Average rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingAverageGroup AddBelowAverage();
-
-  /// <summary>
-  /// Adds a Below Or Equal Average rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingAverageGroup AddBelowOrEqualAverage();
-
-  /// <summary>
-  /// Adds a Above StdDev rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingStdDevGroup AddAboveStdDev();
-
-  /// <summary>
-  /// Adds a Below StdDev rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingStdDevGroup AddBelowStdDev();
-
-  /// <summary>
-  /// Adds a Bottom rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingTopBottomGroup AddBottom();
-
-  /// <summary>
-  /// Adds a Bottom Percent rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingTopBottomGroup AddBottomPercent();
-
-  /// <summary>
-  /// Adds a Top rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingTopBottomGroup AddTop();
-
-  /// <summary>
-  /// Adds a Top Percent rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingTopBottomGroup AddTopPercent();
-
-  /// <summary>
-  /// Adds a Last 7 Days rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingTimePeriodGroup AddLast7Days();
-
-  /// <summary>
-  /// Adds a Last Month rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingTimePeriodGroup AddLastMonth();
-
-  /// <summary>
-  /// Adds a Last Week rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingTimePeriodGroup AddLastWeek();
-
-  /// <summary>
-  /// Adds a Next Month rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingTimePeriodGroup AddNextMonth();
-
-  /// <summary>
-  /// Adds a Next Week rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingTimePeriodGroup AddNextWeek();
-
-  /// <summary>
-  /// Adds a This Month rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingTimePeriodGroup AddThisMonth();
-
-  /// <summary>
-  /// Adds a This Week rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingTimePeriodGroup AddThisWeek();
-
-  /// <summary>
-  /// Adds a Today rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingTimePeriodGroup AddToday();
-
-  /// <summary>
-  /// Adds a Tomorrow rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingTimePeriodGroup AddTomorrow();
-
-  /// <summary>
-  /// Adds a Yesterday rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingTimePeriodGroup AddYesterday();
-
-  /// <summary>
-  /// Adds a Begins With rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingBeginsWith AddBeginsWith();
-
-  /// <summary>
-  /// Adds a Between rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingBetween AddBetween();
-
-  /// <summary>
-  /// Adds a ContainsBlanks rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingContainsBlanks AddContainsBlanks();
-
-  /// <summary>
-  /// Adds a ContainsErrors rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingContainsErrors AddContainsErrors();
-
-  /// <summary>
-  /// Adds a ContainsText rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingContainsText AddContainsText();
-
-  /// <summary>
-  /// Adds a DuplicateValues rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingDuplicateValues AddDuplicateValues();
-
-  /// <summary>
-  /// Adds a EndsWith rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingEndsWith AddEndsWith();
-
-  /// <summary>
-  /// Adds a Equal rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingEqual AddEqual();
-
-  /// <summary>
-  /// Adds a Expression rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingExpression AddExpression();
-
-  /// <summary>
-  /// Adds a GreaterThan rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingGreaterThan AddGreaterThan();
-
-  /// <summary>
-  /// Adds a GreaterThanOrEqual rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingGreaterThanOrEqual AddGreaterThanOrEqual();
-
-  /// <summary>
-  /// Adds a LessThan rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingLessThan AddLessThan();
-
-  /// <summary>
-  /// Adds a LessThanOrEqual rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingLessThanOrEqual AddLessThanOrEqual();
-
-  /// <summary>
-  /// Adds a NotBetween rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingNotBetween AddNotBetween();
-
-  /// <summary>
-  /// Adds a NotContainsBlanks rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingNotContainsBlanks AddNotContainsBlanks();
-
-  /// <summary>
-  /// Adds a NotContainsErrors rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingNotContainsErrors AddNotContainsErrors();
-
-  /// <summary>
-  /// Adds a NotContainsText rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingNotContainsText AddNotContainsText();
-
-  /// <summary>
-  /// Adds a NotEqual rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingNotEqual AddNotEqual();
-
-  /// <summary>
-  /// Adds a UniqueValues rule to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingUniqueValues AddUniqueValues();
-
-  /// <summary>
-  /// Adds a <see cref="ExcelConditionalFormattingThreeColorScale"/> to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingThreeColorScale AddThreeColorScale();
-
-  /// <summary>
-  /// Adds a <see cref="ExcelConditionalFormattingTwoColorScale"/> to the range
-  /// </summary>
-  /// <returns></returns>
-  IExcelConditionalFormattingTwoColorScale AddTwoColorScale();
-}
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingCollection.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingCollection.cs
deleted file mode 100644
index 8717d2e..0000000
--- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingCollection.cs
+++ /dev/null
@@ -1,781 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author					Change						                Date
- * ******************************************************************************
- * Eyal Seagull		Conditional Formatting            2012-04-03
- *******************************************************************************/
-
-using System.Collections;
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// Collection of <see cref="ExcelConditionalFormattingRule"/>.
-/// This class is providing the API for EPPlus conditional formatting.
-/// </summary>
-/// <remarks>
-/// <para>
-/// The public methods of this class (Add[...]ConditionalFormatting) will create a ConditionalFormatting/CfRule entry in the worksheet. When this
-/// Conditional Formatting has been created changes to the properties will affect the workbook immediately.
-/// </para>
-/// <para>
-/// Each type of Conditional Formatting Rule has diferente set of properties.
-/// </para>
-/// <code>
-/// // Add a Three Color Scale conditional formatting
-/// var cf = worksheet.ConditionalFormatting.AddThreeColorScale(new ExcelAddress("A1:C10"));
-/// // Set the conditional formatting properties
-/// cf.LowValue.Type = ExcelConditionalFormattingValueObjectType.Min;
-/// cf.LowValue.Color = Color.White;
-/// cf.MiddleValue.Type = ExcelConditionalFormattingValueObjectType.Percent;
-/// cf.MiddleValue.Value = 50;
-/// cf.MiddleValue.Color = Color.Blue;
-/// cf.HighValue.Type = ExcelConditionalFormattingValueObjectType.Max;
-/// cf.HighValue.Color = Color.Black;
-/// </code>
-/// </remarks>
-public class ExcelConditionalFormattingCollection
-    : XmlHelper,
-      IEnumerable<IExcelConditionalFormattingRule> {
-  private readonly List<IExcelConditionalFormattingRule> _rules = new();
-  private readonly ExcelWorksheet _worksheet;
-
-  protected override ImmutableArray<string> SchemaNodeOrder =>
-    ExcelWorksheet.WorksheetSchemaNodeOrder;
-
-  /// <summary>
-  /// Initialize the <see cref="ExcelConditionalFormattingCollection"/>
-  /// </summary>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingCollection(ExcelWorksheet worksheet)
-      : base(worksheet.NameSpaceManager, worksheet.WorksheetXml.DocumentElement) {
-    Require.Argument(worksheet).IsNotNull("worksheet");
-
-    _worksheet = worksheet;
-
-    // Look for all the <conditionalFormatting>
-    var conditionalFormattingNodes = TopNode.SelectNodes(
-        "//" + ExcelConditionalFormattingConstants.Paths._conditionalFormatting,
-        _worksheet.NameSpaceManager);
-
-    // Check if we found at least 1 node
-    if ((conditionalFormattingNodes != null) && (conditionalFormattingNodes.Count > 0)) {
-      // Foreach <conditionalFormatting>
-      foreach (XmlNode conditionalFormattingNode in conditionalFormattingNodes) {
-        // Check if @sqref attribute exists
-        if (conditionalFormattingNode.Attributes[ExcelConditionalFormattingConstants
-                  .Attributes
-                  ._sqref] == null) {
-          throw new(ExcelConditionalFormattingConstants.Errors._missingSqrefAttribute);
-        }
-
-        // Get the @sqref attribute
-        ExcelAddress address = new ExcelAddress(
-            conditionalFormattingNode.Attributes[ExcelConditionalFormattingConstants
-                  .Attributes
-                  ._sqref].Value);
-
-        // Check for all the <cfRules> nodes and load them
-        var cfRuleNodes = conditionalFormattingNode.SelectNodes(
-            ExcelConditionalFormattingConstants.Paths._cfRule,
-            _worksheet.NameSpaceManager);
-
-        // Foreach <cfRule> inside the current <conditionalFormatting>
-        foreach (XmlNode cfRuleNode in cfRuleNodes) {
-          // Check if @type attribute exists
-          if (cfRuleNode.Attributes[ExcelConditionalFormattingConstants.Attributes._type] == null) {
-            throw new(ExcelConditionalFormattingConstants.Errors._missingTypeAttribute);
-          }
-
-          // Check if @priority attribute exists
-          if (cfRuleNode.Attributes[ExcelConditionalFormattingConstants.Attributes._priority]
-              == null) {
-            throw new(ExcelConditionalFormattingConstants.Errors._missingPriorityAttribute);
-          }
-
-          // Get the <cfRule> main attributes
-          string typeAttribute = ExcelConditionalFormattingHelper.GetAttributeString(
-              cfRuleNode,
-              ExcelConditionalFormattingConstants.Attributes._type);
-
-          int priority = ExcelConditionalFormattingHelper.GetAttributeInt(
-              cfRuleNode,
-              ExcelConditionalFormattingConstants.Attributes._priority);
-
-          // Transform the @type attribute to EPPlus Rule Type (slighty diferente)
-          var type = ExcelConditionalFormattingRuleType.GetTypeByAttrbiute(
-              typeAttribute,
-              cfRuleNode,
-              _worksheet.NameSpaceManager);
-
-          // Create the Rule according to the correct type, address and priority
-          var cfRule = ExcelConditionalFormattingRuleFactory.Create(
-              type,
-              address,
-              priority,
-              _worksheet,
-              cfRuleNode);
-
-          // Add the new rule to the list
-          if (cfRule != null) {
-            _rules.Add(cfRule);
-          }
-        }
-      }
-    }
-  }
-
-  private void EnsureRootElementExists() {
-    // Find the <worksheet> node
-    if (_worksheet.WorksheetXml.DocumentElement == null) {
-      throw new(ExcelConditionalFormattingConstants.Errors._missingWorksheetNode);
-    }
-  }
-
-  /// <summary>
-  /// Validates address - not empty (collisions are allowded)
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  private ExcelAddress ValidateAddress(ExcelAddress address) {
-    Require.Argument(address).IsNotNull("address");
-
-    //TODO: Are there any other validation we need to do?
-    return address;
-  }
-
-  /// <summary>
-  /// Get the next priority sequencial number
-  /// </summary>
-  /// <returns></returns>
-  private int GetNextPriority() {
-    // Consider zero as the last priority when we have no CF rules
-    int lastPriority = 0;
-
-    // Search for the last priority
-    foreach (var cfRule in _rules) {
-      if (cfRule.Priority > lastPriority) {
-        lastPriority = cfRule.Priority;
-      }
-    }
-
-    // Our next priority is the last plus one
-    return lastPriority + 1;
-  }
-
-  /// <summary>
-  /// Number of validations
-  /// </summary>
-  public int Count => _rules.Count;
-
-  /// <summary>
-  /// Index operator, returns by 0-based index
-  /// </summary>
-  /// <param name="index"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingRule this[int index] {
-    get => _rules[index];
-    set => _rules[index] = value;
-  }
-
-  /// <summary>
-  /// Get the 'cfRule' enumerator
-  /// </summary>
-  /// <returns></returns>
-  IEnumerator<IExcelConditionalFormattingRule> IEnumerable<IExcelConditionalFormattingRule>.GetEnumerator() {
-    return _rules.GetEnumerator();
-  }
-
-  /// <summary>
-  /// Get the 'cfRule' enumerator
-  /// </summary>
-  /// <returns></returns>
-  IEnumerator IEnumerable.GetEnumerator() {
-    return _rules.GetEnumerator();
-  }
-
-  /// <summary>
-  /// Removes all 'cfRule' from the collection and from the XML.
-  /// <remarks>
-  /// This is the same as removing all the 'conditionalFormatting' nodes.
-  /// </remarks>
-  /// </summary>
-  public void RemoveAll() {
-    // Look for all the <conditionalFormatting> nodes
-    var conditionalFormattingNodes = TopNode.SelectNodes(
-        "//" + ExcelConditionalFormattingConstants.Paths._conditionalFormatting,
-        _worksheet.NameSpaceManager);
-
-    // Remove all the <conditionalFormatting> nodes one by one
-    foreach (XmlNode conditionalFormattingNode in conditionalFormattingNodes) {
-      conditionalFormattingNode.ParentNode.RemoveChild(conditionalFormattingNode);
-    }
-
-    // Clear the <cfRule> item list
-    _rules.Clear();
-  }
-
-  /// <summary>
-  /// Remove a Conditional Formatting Rule by its object
-  /// </summary>
-  /// <param name="item"></param>
-  public void Remove(IExcelConditionalFormattingRule item) {
-    Require.Argument(item).IsNotNull("item");
-
-    try {
-      // Point to the parent node
-      var oldParentNode = item.Node.ParentNode;
-
-      // Remove the <cfRule> from the old <conditionalFormatting> parent node
-      oldParentNode.RemoveChild(item.Node);
-
-      // Check if the old <conditionalFormatting> parent node has <cfRule> node inside it
-      if (!oldParentNode.HasChildNodes) {
-        // Remove the old parent node
-        oldParentNode.ParentNode.RemoveChild(oldParentNode);
-      }
-
-      _rules.Remove(item);
-    } catch {
-      throw new(ExcelConditionalFormattingConstants.Errors._invalidRemoveRuleOperation);
-    }
-  }
-
-  /// <summary>
-  /// Remove a Conditional Formatting Rule by its 0-based index
-  /// </summary>
-  /// <param name="index"></param>
-  public void RemoveAt(int index) {
-    Require.Argument(index).IsInRange(0, Count - 1, "index");
-
-    Remove(this[index]);
-  }
-
-  /// <summary>
-  /// Remove a Conditional Formatting Rule by its priority
-  /// </summary>
-  /// <param name="priority"></param>
-  public void RemoveByPriority(int priority) {
-    try {
-      Remove(RulesByPriority(priority));
-    } catch {}
-  }
-
-  /// <summary>
-  /// Get a rule by its priority
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingRule RulesByPriority(int priority) {
-    return _rules.Find(x => x.Priority == priority);
-  }
-
-  /// <summary>
-  /// Add rule (internal)
-  /// </summary>
-  /// <param name="type"></param>
-  /// <param name="address"></param>
-  /// <returns></returns>F
-  internal IExcelConditionalFormattingRule AddRule(
-      eExcelConditionalFormattingRuleType type,
-      ExcelAddress address) {
-    Require.Argument(address).IsNotNull("address");
-
-    address = ValidateAddress(address);
-    EnsureRootElementExists();
-
-    // Create the Rule according to the correct type, address and priority
-    IExcelConditionalFormattingRule cfRule = ExcelConditionalFormattingRuleFactory.Create(
-        type,
-        address,
-        GetNextPriority(),
-        _worksheet,
-        null);
-
-    // Add the newly created rule to the list
-    _rules.Add(cfRule);
-
-    // Return the newly created rule
-    return cfRule;
-  }
-
-  /// <summary>
-  /// Add AboveAverage Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingAverageGroup AddAboveAverage(ExcelAddress address) {
-    return (IExcelConditionalFormattingAverageGroup)AddRule(
-        eExcelConditionalFormattingRuleType.AboveAverage,
-        address);
-  }
-
-  /// <summary>
-  /// Add AboveOrEqualAverage Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingAverageGroup AddAboveOrEqualAverage(ExcelAddress address) {
-    return (IExcelConditionalFormattingAverageGroup)AddRule(
-        eExcelConditionalFormattingRuleType.AboveOrEqualAverage,
-        address);
-  }
-
-  /// <summary>
-  /// Add BelowAverage Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingAverageGroup AddBelowAverage(ExcelAddress address) {
-    return (IExcelConditionalFormattingAverageGroup)AddRule(
-        eExcelConditionalFormattingRuleType.BelowAverage,
-        address);
-  }
-
-  /// <summary>
-  /// Add BelowOrEqualAverage Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingAverageGroup AddBelowOrEqualAverage(ExcelAddress address) {
-    return (IExcelConditionalFormattingAverageGroup)AddRule(
-        eExcelConditionalFormattingRuleType.BelowOrEqualAverage,
-        address);
-  }
-
-  /// <summary>
-  /// Add AboveStdDev Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingStdDevGroup AddAboveStdDev(ExcelAddress address) {
-    return (IExcelConditionalFormattingStdDevGroup)AddRule(
-        eExcelConditionalFormattingRuleType.AboveStdDev,
-        address);
-  }
-
-  /// <summary>
-  /// Add BelowStdDev Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingStdDevGroup AddBelowStdDev(ExcelAddress address) {
-    return (IExcelConditionalFormattingStdDevGroup)AddRule(
-        eExcelConditionalFormattingRuleType.BelowStdDev,
-        address);
-  }
-
-  /// <summary>
-  /// Add Bottom Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingTopBottomGroup AddBottom(ExcelAddress address) {
-    return (IExcelConditionalFormattingTopBottomGroup)AddRule(
-        eExcelConditionalFormattingRuleType.Bottom,
-        address);
-  }
-
-  /// <summary>
-  /// Add BottomPercent Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingTopBottomGroup AddBottomPercent(ExcelAddress address) {
-    return (IExcelConditionalFormattingTopBottomGroup)AddRule(
-        eExcelConditionalFormattingRuleType.BottomPercent,
-        address);
-  }
-
-  /// <summary>
-  /// Add Top Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingTopBottomGroup AddTop(ExcelAddress address) {
-    return (IExcelConditionalFormattingTopBottomGroup)AddRule(
-        eExcelConditionalFormattingRuleType.Top,
-        address);
-  }
-
-  /// <summary>
-  /// Add TopPercent Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingTopBottomGroup AddTopPercent(ExcelAddress address) {
-    return (IExcelConditionalFormattingTopBottomGroup)AddRule(
-        eExcelConditionalFormattingRuleType.TopPercent,
-        address);
-  }
-
-  /// <summary>
-  /// Add Last7Days Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingTimePeriodGroup AddLast7Days(ExcelAddress address) {
-    return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
-        eExcelConditionalFormattingRuleType.Last7Days,
-        address);
-  }
-
-  /// <summary>
-  /// Add LastMonth Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingTimePeriodGroup AddLastMonth(ExcelAddress address) {
-    return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
-        eExcelConditionalFormattingRuleType.LastMonth,
-        address);
-  }
-
-  /// <summary>
-  /// Add LastWeek Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingTimePeriodGroup AddLastWeek(ExcelAddress address) {
-    return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
-        eExcelConditionalFormattingRuleType.LastWeek,
-        address);
-  }
-
-  /// <summary>
-  /// Add NextMonth Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingTimePeriodGroup AddNextMonth(ExcelAddress address) {
-    return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
-        eExcelConditionalFormattingRuleType.NextMonth,
-        address);
-  }
-
-  /// <summary>
-  /// Add NextWeek Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingTimePeriodGroup AddNextWeek(ExcelAddress address) {
-    return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
-        eExcelConditionalFormattingRuleType.NextWeek,
-        address);
-  }
-
-  /// <summary>
-  /// Add ThisMonth Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingTimePeriodGroup AddThisMonth(ExcelAddress address) {
-    return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
-        eExcelConditionalFormattingRuleType.ThisMonth,
-        address);
-  }
-
-  /// <summary>
-  /// Add ThisWeek Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingTimePeriodGroup AddThisWeek(ExcelAddress address) {
-    return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
-        eExcelConditionalFormattingRuleType.ThisWeek,
-        address);
-  }
-
-  /// <summary>
-  /// Add Today Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingTimePeriodGroup AddToday(ExcelAddress address) {
-    return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
-        eExcelConditionalFormattingRuleType.Today,
-        address);
-  }
-
-  /// <summary>
-  /// Add Tomorrow Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingTimePeriodGroup AddTomorrow(ExcelAddress address) {
-    return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
-        eExcelConditionalFormattingRuleType.Tomorrow,
-        address);
-  }
-
-  /// <summary>
-  /// Add Yesterday Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingTimePeriodGroup AddYesterday(ExcelAddress address) {
-    return (IExcelConditionalFormattingTimePeriodGroup)AddRule(
-        eExcelConditionalFormattingRuleType.Yesterday,
-        address);
-  }
-
-  /// <summary>
-  /// Add BeginsWith Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingBeginsWith AddBeginsWith(ExcelAddress address) {
-    return (IExcelConditionalFormattingBeginsWith)AddRule(
-        eExcelConditionalFormattingRuleType.BeginsWith,
-        address);
-  }
-
-  /// <summary>
-  /// Add Between Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingBetween AddBetween(ExcelAddress address) {
-    return (IExcelConditionalFormattingBetween)AddRule(
-        eExcelConditionalFormattingRuleType.Between,
-        address);
-  }
-
-  /// <summary>
-  /// Add ContainsBlanks Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingContainsBlanks AddContainsBlanks(ExcelAddress address) {
-    return (IExcelConditionalFormattingContainsBlanks)AddRule(
-        eExcelConditionalFormattingRuleType.ContainsBlanks,
-        address);
-  }
-
-  /// <summary>
-  /// Add ContainsErrors Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingContainsErrors AddContainsErrors(ExcelAddress address) {
-    return (IExcelConditionalFormattingContainsErrors)AddRule(
-        eExcelConditionalFormattingRuleType.ContainsErrors,
-        address);
-  }
-
-  /// <summary>
-  /// Add ContainsText Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingContainsText AddContainsText(ExcelAddress address) {
-    return (IExcelConditionalFormattingContainsText)AddRule(
-        eExcelConditionalFormattingRuleType.ContainsText,
-        address);
-  }
-
-  /// <summary>
-  /// Add DuplicateValues Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingDuplicateValues AddDuplicateValues(ExcelAddress address) {
-    return (IExcelConditionalFormattingDuplicateValues)AddRule(
-        eExcelConditionalFormattingRuleType.DuplicateValues,
-        address);
-  }
-
-  /// <summary>
-  /// Add EndsWith Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingEndsWith AddEndsWith(ExcelAddress address) {
-    return (IExcelConditionalFormattingEndsWith)AddRule(
-        eExcelConditionalFormattingRuleType.EndsWith,
-        address);
-  }
-
-  /// <summary>
-  /// Add Equal Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingEqual AddEqual(ExcelAddress address) {
-    return (IExcelConditionalFormattingEqual)AddRule(
-        eExcelConditionalFormattingRuleType.Equal,
-        address);
-  }
-
-  /// <summary>
-  /// Add Expression Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingExpression AddExpression(ExcelAddress address) {
-    return (IExcelConditionalFormattingExpression)AddRule(
-        eExcelConditionalFormattingRuleType.Expression,
-        address);
-  }
-
-  /// <summary>
-  /// Add GreaterThan Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingGreaterThan AddGreaterThan(ExcelAddress address) {
-    return (IExcelConditionalFormattingGreaterThan)AddRule(
-        eExcelConditionalFormattingRuleType.GreaterThan,
-        address);
-  }
-
-  /// <summary>
-  /// Add GreaterThanOrEqual Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingGreaterThanOrEqual AddGreaterThanOrEqual(ExcelAddress address) {
-    return (IExcelConditionalFormattingGreaterThanOrEqual)AddRule(
-        eExcelConditionalFormattingRuleType.GreaterThanOrEqual,
-        address);
-  }
-
-  /// <summary>
-  /// Add LessThan Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingLessThan AddLessThan(ExcelAddress address) {
-    return (IExcelConditionalFormattingLessThan)AddRule(
-        eExcelConditionalFormattingRuleType.LessThan,
-        address);
-  }
-
-  /// <summary>
-  /// Add LessThanOrEqual Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingLessThanOrEqual AddLessThanOrEqual(ExcelAddress address) {
-    return (IExcelConditionalFormattingLessThanOrEqual)AddRule(
-        eExcelConditionalFormattingRuleType.LessThanOrEqual,
-        address);
-  }
-
-  /// <summary>
-  /// Add NotBetween Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingNotBetween AddNotBetween(ExcelAddress address) {
-    return (IExcelConditionalFormattingNotBetween)AddRule(
-        eExcelConditionalFormattingRuleType.NotBetween,
-        address);
-  }
-
-  /// <summary>
-  /// Add NotContainsBlanks Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingNotContainsBlanks AddNotContainsBlanks(ExcelAddress address) {
-    return (IExcelConditionalFormattingNotContainsBlanks)AddRule(
-        eExcelConditionalFormattingRuleType.NotContainsBlanks,
-        address);
-  }
-
-  /// <summary>
-  /// Add NotContainsErrors Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingNotContainsErrors AddNotContainsErrors(ExcelAddress address) {
-    return (IExcelConditionalFormattingNotContainsErrors)AddRule(
-        eExcelConditionalFormattingRuleType.NotContainsErrors,
-        address);
-  }
-
-  /// <summary>
-  /// Add NotContainsText Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingNotContainsText AddNotContainsText(ExcelAddress address) {
-    return (IExcelConditionalFormattingNotContainsText)AddRule(
-        eExcelConditionalFormattingRuleType.NotContainsText,
-        address);
-  }
-
-  /// <summary>
-  /// Add NotEqual Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingNotEqual AddNotEqual(ExcelAddress address) {
-    return (IExcelConditionalFormattingNotEqual)AddRule(
-        eExcelConditionalFormattingRuleType.NotEqual,
-        address);
-  }
-
-  /// <summary>
-  /// Add Unique Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingUniqueValues AddUniqueValues(ExcelAddress address) {
-    return (IExcelConditionalFormattingUniqueValues)AddRule(
-        eExcelConditionalFormattingRuleType.UniqueValues,
-        address);
-  }
-
-  /// <summary>
-  /// Add ThreeColorScale Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingThreeColorScale AddThreeColorScale(ExcelAddress address) {
-    return (IExcelConditionalFormattingThreeColorScale)AddRule(
-        eExcelConditionalFormattingRuleType.ThreeColorScale,
-        address);
-  }
-
-  /// <summary>
-  /// Add TwoColorScale Rule
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public IExcelConditionalFormattingTwoColorScale AddTwoColorScale(ExcelAddress address) {
-    return (IExcelConditionalFormattingTwoColorScale)AddRule(
-        eExcelConditionalFormattingRuleType.TwoColorScale,
-        address);
-  }
-}
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingColorScaleValue.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingColorScaleValue.cs
deleted file mode 100644
index 59376e7..0000000
--- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingColorScaleValue.cs
+++ /dev/null
@@ -1,408 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System;
-using System.Collections.Immutable;
-using System.Xml;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// 18.3.1.11 cfvo (Conditional Format Value Object)
-/// Describes the values of the interpolation points in a gradient scale.
-/// </summary>
-public class ExcelConditionalFormattingColorScaleValue : XmlHelper {
-  private eExcelConditionalFormattingValueObjectPosition _position;
-  private eExcelConditionalFormattingRuleType _ruleType;
-  private readonly ExcelWorksheet _worksheet;
-
-  protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
-    ExcelConditionalFormattingConstants.Nodes._cfvo,
-    ExcelConditionalFormattingConstants.Nodes._color,
-  ];
-
-  /// <summary>
-  /// Initialize the cfvo (§18.3.1.11) node
-  /// </summary>
-  /// <param name="position"></param>
-  /// <param name="type"></param>
-  /// <param name="color"></param>
-  /// <param name="value"></param>
-  /// <param name="formula"></param>
-  /// <param name="ruleType"></param>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode">The cfvo (§18.3.1.11) node parent. Can be any of the following:
-  /// colorScale (§18.3.1.16); dataBar (§18.3.1.28); iconSet (§18.3.1.49)</param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingColorScaleValue(
-      eExcelConditionalFormattingValueObjectPosition position,
-      eExcelConditionalFormattingValueObjectType type,
-      double value,
-      string formula,
-      eExcelConditionalFormattingRuleType ruleType,
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(namespaceManager, itemElementNode) {
-    Require.Argument(priority).IsInRange(1, int.MaxValue, "priority");
-    Require.Argument(address).IsNotNull("address");
-    Require.Argument(worksheet).IsNotNull("worksheet");
-
-    // Save the worksheet for private methods to use
-    _worksheet = worksheet;
-
-    // Check if the parent does not exists
-    if (itemElementNode == null) {
-      // Get the parent node path by the rule type
-      string parentNodePath = ExcelConditionalFormattingValueObjectType.GetParentPathByRuleType(
-          ruleType);
-
-      // Check for en error (rule type does not have <cfvo>)
-      if (parentNodePath == string.Empty) {
-        throw new(ExcelConditionalFormattingConstants.Errors._missingCfvoParentNode);
-      }
-
-      // Point to the <cfvo> parent node
-      itemElementNode = _worksheet.WorksheetXml.SelectSingleNode(
-          string.Format(
-              "//{0}[{1}='{2}']/{3}[{4}='{5}']/{6}",
-              // {0}
-              ExcelConditionalFormattingConstants.Paths._conditionalFormatting,
-              // {1}
-              ExcelConditionalFormattingConstants.Paths._sqrefAttribute,
-              // {2}
-              address.Address,
-              // {3}
-              ExcelConditionalFormattingConstants.Paths._cfRule,
-              // {4}
-              ExcelConditionalFormattingConstants.Paths._priorityAttribute,
-              // {5}
-              priority,
-              // {6}
-              parentNodePath),
-          _worksheet.NameSpaceManager);
-
-      // Check for en error (rule type does not have <cfvo>)
-      if (itemElementNode == null) {
-        throw new(ExcelConditionalFormattingConstants.Errors._missingCfvoParentNode);
-      }
-    }
-
-    // Point to the <cfvo> parent node (<colorScale>, <dataBar> or <iconSet>)
-    // This is different than normal, as TopNode does not point to the node itself but to
-    // its PARENT. Later, in the CreateNodeByOrdem method the TopNode will be updated.
-    TopNode = itemElementNode;
-
-    // Save the attributes
-    Position = position;
-    RuleType = ruleType;
-    Type = type;
-    Value = value;
-    Formula = formula;
-  }
-
-  /// <summary>
-  /// Initialize the <see cref="ExcelConditionalFormattingColorScaleValue"/>
-  /// </summary>
-  /// <param name="position"></param>
-  /// <param name="type"></param>
-  /// <param name="color"></param>
-  /// <param name="value"></param>
-  /// <param name="formula"></param>
-  /// <param name="ruleType"></param>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingColorScaleValue(
-      eExcelConditionalFormattingValueObjectPosition position,
-      eExcelConditionalFormattingValueObjectType type,
-      double value,
-      string formula,
-      eExcelConditionalFormattingRuleType ruleType,
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNamespaceManager namespaceManager)
-      : this(
-          position,
-          type,
-          value,
-          formula,
-          ruleType,
-          address,
-          priority,
-          worksheet,
-          null,
-          namespaceManager) {}
-
-  /// <summary>
-  /// Initialize the <see cref="ExcelConditionalFormattingColorScaleValue"/>
-  /// </summary>
-  /// <param name="position"></param>
-  /// <param name="type"></param>
-  /// <param name="color"></param>
-  /// <param name="ruleType"></param>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingColorScaleValue(
-      eExcelConditionalFormattingValueObjectPosition position,
-      eExcelConditionalFormattingValueObjectType type,
-      eExcelConditionalFormattingRuleType ruleType,
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNamespaceManager namespaceManager)
-      : this(
-          position,
-          type,
-          0,
-          null,
-          ruleType,
-          address,
-          priority,
-          worksheet,
-          null,
-          namespaceManager) {}
-
-  /// <summary>
-  /// Get the node order (1, 2 ou 3) according to the Position (Low, Middle and High)
-  /// and the Rule Type (TwoColorScale ou ThreeColorScale).
-  /// </summary>
-  /// <returns></returns>
-  private int GetNodeOrder() {
-    return ExcelConditionalFormattingValueObjectType.GetOrderByPosition(Position, RuleType);
-  }
-
-  /// <summary>
-  /// Create the 'cfvo'/'color' nodes in the right order. They should appear like this:
-  ///		"cfvo"   --> Low Value (value object)
-  ///		"cfvo"   --> Middle Value (value object)
-  ///		"cfvo"   --> High Value (value object)
-  ///		"color"  --> Low Value (color)
-  ///		"color"  --> Middle Value (color)
-  ///		"color"  --> High Value (color)
-  /// </summary>
-  /// <param name="nodeType"></param>
-  /// <param name="attributePath"></param>
-  /// <param name="attributeValue"></param>
-  private void CreateNodeByOrdem(
-      eExcelConditionalFormattingValueObjectNodeType nodeType,
-      string attributePath,
-      string attributeValue) {
-    // Save the current TopNode
-    XmlNode currentTopNode = TopNode;
-
-    string nodePath = ExcelConditionalFormattingValueObjectType.GetNodePathByNodeType(nodeType);
-    int nodeOrder = GetNodeOrder();
-    eNodeInsertOrder nodeInsertOrder = eNodeInsertOrder.SchemaOrder;
-    XmlNode referenceNode = null;
-
-    if (nodeOrder > 1) {
-      // Find the node just before the one we need to include
-      referenceNode = TopNode.SelectSingleNode(
-          string.Format(
-              "{0}[position()={1}]",
-              // {0}
-              nodePath,
-              // {1}
-              nodeOrder - 1),
-          _worksheet.NameSpaceManager);
-
-      // Only if the prepend node exists than insert after
-      if (referenceNode != null) {
-        nodeInsertOrder = eNodeInsertOrder.After;
-      }
-    }
-
-    // Create the node in the right order
-    var node = CreateComplexNode(
-        TopNode,
-        string.Format(
-            "{0}[position()={1}]",
-            // {0}
-            nodePath,
-            // {1}
-            nodeOrder),
-        nodeInsertOrder,
-        referenceNode);
-
-    // Point to the new node as the temporary TopNode (we need it for the XmlHelper functions)
-    TopNode = node;
-
-    // Add/Remove the attribute (if the attributeValue is empty then it will be removed)
-    SetXmlNodeString(node, attributePath, attributeValue, true);
-
-    // Point back to the <cfvo>/<color> parent node
-    TopNode = currentTopNode;
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  internal eExcelConditionalFormattingValueObjectPosition Position {
-    get => _position;
-    set => _position = value;
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  internal eExcelConditionalFormattingRuleType RuleType {
-    get => _ruleType;
-    set => _ruleType = value;
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  public eExcelConditionalFormattingValueObjectType Type {
-    get {
-      var typeAttribute = GetXmlNodeString(
-          string.Format(
-              "{0}[position()={1}]/{2}",
-              // {0}
-              ExcelConditionalFormattingConstants.Paths._cfvo,
-              // {1}
-              GetNodeOrder(),
-              // {2}
-              ExcelConditionalFormattingConstants.Paths._typeAttribute));
-
-      return ExcelConditionalFormattingValueObjectType.GetTypeByAttrbiute(typeAttribute);
-    }
-    set {
-      CreateNodeByOrdem(
-          eExcelConditionalFormattingValueObjectNodeType.Cfvo,
-          ExcelConditionalFormattingConstants.Paths._typeAttribute,
-          ExcelConditionalFormattingValueObjectType.GetAttributeByType(value));
-
-      bool removeValAttribute = false;
-
-      // Make sure unnecessary attributes are removed (occures when we change
-      // the value object type)
-      switch (Type) {
-        case eExcelConditionalFormattingValueObjectType.Min:
-        case eExcelConditionalFormattingValueObjectType.Max:
-          removeValAttribute = true;
-          break;
-      }
-
-      // Check if we need to remove the @val attribute
-      if (removeValAttribute) {
-        string nodePath = ExcelConditionalFormattingValueObjectType.GetNodePathByNodeType(
-            eExcelConditionalFormattingValueObjectNodeType.Cfvo);
-        int nodeOrder = GetNodeOrder();
-
-        // Remove the attribute (removed when the value = '')
-        CreateComplexNode(
-            TopNode,
-            string.Format(
-                "{0}[position()={1}]/{2}=''",
-                // {0}
-                nodePath,
-                // {1}
-                nodeOrder,
-                // {2}
-                ExcelConditionalFormattingConstants.Paths._valAttribute));
-      }
-    }
-  }
-
-  /// <summary>
-  /// Get/Set the 'cfvo' node @val attribute
-  /// </summary>
-  public Double Value {
-    get =>
-      GetXmlNodeDouble(
-          string.Format(
-              "{0}[position()={1}]/{2}",
-              // {0}
-              ExcelConditionalFormattingConstants.Paths._cfvo,
-              // {1}
-              GetNodeOrder(),
-              // {2}
-              ExcelConditionalFormattingConstants.Paths._valAttribute));
-    set {
-      string valueToStore = string.Empty;
-
-      // Only some types use the @val attribute
-      if ((Type == eExcelConditionalFormattingValueObjectType.Num)
-          || (Type == eExcelConditionalFormattingValueObjectType.Percent)
-          || (Type == eExcelConditionalFormattingValueObjectType.Percentile)) {
-        valueToStore = value.ToString();
-      }
-
-      CreateNodeByOrdem(
-          eExcelConditionalFormattingValueObjectNodeType.Cfvo,
-          ExcelConditionalFormattingConstants.Paths._valAttribute,
-          valueToStore);
-    }
-  }
-
-  /// <summary>
-  /// Get/Set the Formula of the Object Value (uses the same attribute as the Value)
-  /// </summary>
-  public string Formula {
-    get {
-      // Return empty if the Object Value type is not Formula
-      if (Type != eExcelConditionalFormattingValueObjectType.Formula) {
-        return string.Empty;
-      }
-
-      // Excel stores the formula in the @val attribute
-      return GetXmlNodeString(
-          string.Format(
-              "{0}[position()={1}]/{2}",
-              // {0}
-              ExcelConditionalFormattingConstants.Paths._cfvo,
-              // {1}
-              GetNodeOrder(),
-              // {2}
-              ExcelConditionalFormattingConstants.Paths._valAttribute));
-    }
-    set {
-      // Only store the formula if the Object Value type is Formula
-      if (Type == eExcelConditionalFormattingValueObjectType.Formula) {
-        CreateNodeByOrdem(
-            eExcelConditionalFormattingValueObjectNodeType.Cfvo,
-            ExcelConditionalFormattingConstants.Paths._valAttribute,
-            value ?? string.Empty);
-      }
-    }
-  }
-}
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingConstants.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingConstants.cs
deleted file mode 100644
index 938c6cd..0000000
--- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingConstants.cs
+++ /dev/null
@@ -1,259 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// The conditional formatting constants
-/// </summary>
-internal static class ExcelConditionalFormattingConstants {
-  internal class Errors {
-    internal const string _commaSeparatedAddresses =
-        "Multiple addresses may not be commaseparated, use space instead";
-    internal const string _invalidPriority = "Invalid priority number. Must be bigger than zero";
-    internal const string _invalidRemoveRuleOperation = "Invalid remove rule operation";
-    internal const string _missingCfvoNode = "Missing 'cfvo' node in Conditional Formatting";
-    internal const string _missingCfvoParentNode =
-        "Missing 'cfvo' parent node in Conditional Formatting";
-    internal const string _missingConditionalFormattingNode =
-        "Missing 'conditionalFormatting' node in Conditional Formatting";
-    internal const string _missingItemRuleList =
-        "Missing item with address '{0}' in Conditional Formatting Rule List";
-    internal const string _missingPriorityAttribute =
-        "Missing 'priority' attribute in Conditional Formatting Rule";
-    internal const string _missingRuleType =
-        "Missing eExcelConditionalFormattingRuleType Type in Conditional Formatting";
-    internal const string _missingSqrefAttribute =
-        "Missing 'sqref' attribute in Conditional Formatting";
-    internal const string _missingTypeAttribute =
-        "Missing 'type' attribute in Conditional Formatting Rule";
-    internal const string _missingWorksheetNode = "Missing 'worksheet' node";
-    internal const string _nonSupportedRuleType = "Non supported conditionalFormattingType: {0}";
-    internal const string _unexistentCfvoTypeAttribute =
-        "Unexistent eExcelConditionalFormattingValueObjectType attribute in Conditional Formatting";
-    internal const string _unexistentOperatorTypeAttribute =
-        "Unexistent eExcelConditionalFormattingOperatorType attribute in Conditional Formatting";
-    internal const string _unexistentTimePeriodTypeAttribute =
-        "Unexistent eExcelConditionalFormattingTimePeriodType attribute in Conditional Formatting";
-    internal const string _unexpectedRuleTypeAttribute =
-        "Unexpected eExcelConditionalFormattingRuleType attribute in Conditional Formatting Rule";
-    internal const string _wrongNumberCfvoColorNodes =
-        "Wrong number of 'cfvo'/'color' nodes in Conditional Formatting Rule";
-  }
-
-  internal class Nodes {
-    internal const string _worksheet = "worksheet";
-    internal const string _conditionalFormatting = "conditionalFormatting";
-    internal const string _cfRule = "cfRule";
-    internal const string _colorScale = "colorScale";
-    internal const string _cfvo = "cfvo";
-    internal const string _color = "color";
-    internal const string _dataBar = "dataBar";
-    internal const string _iconSet = "iconSet";
-    internal const string _formula = "formula";
-  }
-
-  internal class Attributes {
-    internal const string _aboveAverage = "aboveAverage";
-    internal const string _bottom = "bottom";
-    internal const string _dxfId = "dxfId";
-    internal const string _equalAverage = "equalAverage";
-    internal const string _iconSet = "iconSet";
-    internal const string _operator = "operator";
-    internal const string _percent = "percent";
-    internal const string _priority = "priority";
-    internal const string _rank = "rank";
-    internal const string _reverse = "reverse";
-    internal const string _rgb = "rgb";
-    internal const string _showValue = "showValue";
-    internal const string _sqref = "sqref";
-    internal const string _stdDev = "stdDev";
-    internal const string _stopIfTrue = "stopIfTrue";
-    internal const string _text = "text";
-    internal const string _theme = "theme";
-    internal const string _timePeriod = "timePeriod";
-    internal const string _tint = "tint";
-    internal const string _type = "type";
-    internal const string _val = "val";
-  }
-
-  internal class Paths {
-    // Main node and attributes
-    internal const string _worksheet = "d:" + Nodes._worksheet;
-
-    // <conditionalFormatting> §18.3.1.18 node
-    // can appear more than once in a worksheet
-    internal const string _conditionalFormatting = "d:" + Nodes._conditionalFormatting;
-
-    // <cfRule> §18.3.1.10 node
-    // can appear more than once in a <conditionalFormatting>
-    internal const string _cfRule = "d:" + Nodes._cfRule;
-
-    // <colorScale> §18.3.1.16 node
-    internal const string _colorScale = "d:" + Nodes._colorScale;
-
-    // <cfvo> §18.3.1.11 node
-    internal const string _cfvo = "d:" + Nodes._cfvo;
-
-    // <color> §18.3.1.15 node
-    internal const string _color = "d:" + Nodes._color;
-
-    // <dataBar> §18.3.1.28 node
-    internal const string _dataBar = "d:" + Nodes._dataBar;
-
-    // <iconSet> §18.3.1.49 node
-    internal const string _iconSet = "d:" + Nodes._iconSet;
-
-    // <formula> §18.3.1.43 node
-    internal const string _formula = "d:" + Nodes._formula;
-
-    // Attributes (for all the nodes)
-    internal const string _aboveAverageAttribute = "@" + Attributes._aboveAverage;
-    internal const string _bottomAttribute = "@" + Attributes._bottom;
-    internal const string _dxfIdAttribute = "@" + Attributes._dxfId;
-    internal const string _equalAverageAttribute = "@" + Attributes._equalAverage;
-    internal const string _iconSetAttribute = "@" + Attributes._iconSet;
-    internal const string _operatorAttribute = "@" + Attributes._operator;
-    internal const string _percentAttribute = "@" + Attributes._percent;
-    internal const string _priorityAttribute = "@" + Attributes._priority;
-    internal const string _rankAttribute = "@" + Attributes._rank;
-    internal const string _reverseAttribute = "@" + Attributes._reverse;
-    internal const string _rgbAttribute = "@" + Attributes._rgb;
-    internal const string _showValueAttribute = "@" + Attributes._showValue;
-    internal const string _sqrefAttribute = "@" + Attributes._sqref;
-    internal const string _stdDevAttribute = "@" + Attributes._stdDev;
-    internal const string _stopIfTrueAttribute = "@" + Attributes._stopIfTrue;
-    internal const string _textAttribute = "@" + Attributes._text;
-    internal const string _themeAttribute = "@" + Attributes._theme;
-    internal const string _timePeriodAttribute = "@" + Attributes._timePeriod;
-    internal const string _tintAttribute = "@" + Attributes._tint;
-    internal const string _typeAttribute = "@" + Attributes._type;
-    internal const string _valAttribute = "@" + Attributes._val;
-  }
-
-  internal class RuleType {
-    internal const string _aboveAverage = "aboveAverage";
-    internal const string _beginsWith = "beginsWith";
-    internal const string _cellIs = "cellIs";
-    internal const string _colorScale = "colorScale";
-    internal const string _containsBlanks = "containsBlanks";
-    internal const string _containsErrors = "containsErrors";
-    internal const string _containsText = "containsText";
-    internal const string _dataBar = "dataBar";
-    internal const string _duplicateValues = "duplicateValues";
-    internal const string _endsWith = "endsWith";
-    internal const string _expression = "expression";
-    internal const string _iconSet = "iconSet";
-    internal const string _notContainsBlanks = "notContainsBlanks";
-    internal const string _notContainsErrors = "notContainsErrors";
-    internal const string _notContainsText = "notContainsText";
-    internal const string _timePeriod = "timePeriod";
-    internal const string _top10 = "top10";
-    internal const string _uniqueValues = "uniqueValues";
-
-    // EPPlus Extended Types
-    internal const string _aboveOrEqualAverage = "aboveOrEqualAverage";
-    internal const string _aboveStdDev = "aboveStdDev";
-    internal const string _belowAverage = "belowAverage";
-    internal const string _belowOrEqualAverage = "belowOrEqualAverage";
-    internal const string _belowStdDev = "belowStdDev";
-    internal const string _between = "between";
-    internal const string _bottom = "bottom";
-    internal const string _bottomPercent = "bottomPercent";
-    internal const string _equal = "equal";
-    internal const string _greaterThan = "greaterThan";
-    internal const string _greaterThanOrEqual = "greaterThanOrEqual";
-    internal const string _iconSet3 = "iconSet3";
-    internal const string _iconSet4 = "iconSet4";
-    internal const string _iconSet5 = "iconSet5";
-    internal const string _last7Days = "last7Days";
-    internal const string _lastMonth = "lastMonth";
-    internal const string _lastWeek = "lastWeek";
-    internal const string _lessThan = "lessThan";
-    internal const string _lessThanOrEqual = "lessThanOrEqual";
-    internal const string _nextMonth = "nextMonth";
-    internal const string _nextWeek = "nextWeek";
-    internal const string _notBetween = "notBetween";
-    internal const string _notEqual = "notEqual";
-    internal const string _thisMonth = "thisMonth";
-    internal const string _thisWeek = "thisWeek";
-    internal const string _threeColorScale = "threeColorScale";
-    internal const string _today = "today";
-    internal const string _tomorrow = "tomorrow";
-    internal const string _top = "top";
-    internal const string _topPercent = "topPercent";
-    internal const string _twoColorScale = "twoColorScale";
-    internal const string _yesterday = "yesterday";
-  }
-
-  internal class CfvoType {
-    internal const string _min = "min";
-    internal const string _max = "max";
-    internal const string _num = "num";
-    internal const string _formula = "formula";
-    internal const string _percent = "percent";
-    internal const string _percentile = "percentile";
-  }
-
-  internal class Operators {
-    internal const string _beginsWith = "beginsWith";
-    internal const string _between = "between";
-    internal const string _containsText = "containsText";
-    internal const string _endsWith = "endsWith";
-    internal const string _equal = "equal";
-    internal const string _greaterThan = "greaterThan";
-    internal const string _greaterThanOrEqual = "greaterThanOrEqual";
-    internal const string _lessThan = "lessThan";
-    internal const string _lessThanOrEqual = "lessThanOrEqual";
-    internal const string _notBetween = "notBetween";
-    internal const string _notContains = "notContains";
-    internal const string _notEqual = "notEqual";
-  }
-
-  internal class TimePeriods {
-    internal const string _last7Days = "last7Days";
-    internal const string _lastMonth = "lastMonth";
-    internal const string _lastWeek = "lastWeek";
-    internal const string _nextMonth = "nextMonth";
-    internal const string _nextWeek = "nextWeek";
-    internal const string _thisMonth = "thisMonth";
-    internal const string _thisWeek = "thisWeek";
-    internal const string _today = "today";
-    internal const string _tomorrow = "tomorrow";
-    internal const string _yesterday = "yesterday";
-  }
-
-  internal class Colors {
-    internal const string _cfvoLowValue = "#FFF8696B";
-    internal const string _cfvoMiddleValue = "#FFFFEB84";
-    internal const string _cfvoHighValue = "#FF63BE7B";
-  }
-}
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingEnums.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingEnums.cs
deleted file mode 100644
index 8885f5c..0000000
--- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingEnums.cs
+++ /dev/null
@@ -1,753 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// Enum for Conditional Format Type ST_CfType §18.18.12. With some changes.
-/// </summary>
-public enum eExcelConditionalFormattingRuleType {
-  /// <summary>
-  /// This conditional formatting rule highlights cells that are above the average
-  /// for all values in the range.
-  /// </summary>
-  /// <remarks>AboveAverage Excel CF Rule Type</remarks>
-  AboveAverage,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells that are above or equal
-  /// the average for all values in the range.
-  /// </summary>
-  /// <remarks>AboveAverage Excel CF Rule Type</remarks>
-  AboveOrEqualAverage,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells that are below the average
-  /// for all values in the range.
-  /// </summary>
-  /// <remarks>AboveAverage Excel CF Rule Type</remarks>
-  BelowAverage,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells that are below or equal
-  /// the average for all values in the range.
-  /// </summary>
-  /// <remarks>AboveAverage Excel CF Rule Type</remarks>
-  BelowOrEqualAverage,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells that are above the standard
-  /// deviationa for all values in the range.
-  /// <remarks>AboveAverage Excel CF Rule Type</remarks>
-  /// </summary>
-  AboveStdDev,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells that are below the standard
-  /// deviationa for all values in the range.
-  /// </summary>
-  /// <remarks>AboveAverage Excel CF Rule Type</remarks>
-  BelowStdDev,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells whose values fall in the
-  /// bottom N bracket as specified.
-  /// </summary>
-  /// <remarks>Top10 Excel CF Rule Type</remarks>
-  Bottom,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells whose values fall in the
-  /// bottom N percent as specified.
-  /// </summary>
-  /// <remarks>Top10 Excel CF Rule Type</remarks>
-  BottomPercent,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells whose values fall in the
-  /// top N bracket as specified.
-  /// </summary>
-  /// <remarks>Top10 Excel CF Rule Type</remarks>
-  Top,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells whose values fall in the
-  /// top N percent as specified.
-  /// </summary>
-  /// <remarks>Top10 Excel CF Rule Type</remarks>
-  TopPercent,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells containing dates in the
-  /// last 7 days.
-  /// </summary>
-  /// <remarks>TimePeriod Excel CF Rule Type</remarks>
-  Last7Days,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells containing dates in the
-  /// last month.
-  /// </summary>
-  /// <remarks>TimePeriod Excel CF Rule Type</remarks>
-  LastMonth,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells containing dates in the
-  /// last week.
-  /// </summary>
-  /// <remarks>TimePeriod Excel CF Rule Type</remarks>
-  LastWeek,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells containing dates in the
-  /// next month.
-  /// </summary>
-  /// <remarks>TimePeriod Excel CF Rule Type</remarks>
-  NextMonth,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells containing dates in the
-  /// next week.
-  /// </summary>
-  /// <remarks>TimePeriod Excel CF Rule Type</remarks>
-  NextWeek,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells containing dates in this
-  /// month.
-  /// </summary>
-  /// <remarks>TimePeriod Excel CF Rule Type</remarks>
-  ThisMonth,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells containing dates in this
-  /// week.
-  /// </summary>
-  /// <remarks>TimePeriod Excel CF Rule Type</remarks>
-  ThisWeek,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells containing today dates.
-  /// </summary>
-  /// <remarks>TimePeriod Excel CF Rule Type</remarks>
-  Today,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells containing tomorrow dates.
-  /// </summary>
-  /// <remarks>TimePeriod Excel CF Rule Type</remarks>
-  Tomorrow,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells containing yesterday dates.
-  /// </summary>
-  /// <remarks>TimePeriod Excel CF Rule Type</remarks>
-  Yesterday,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells in the range that begin with
-  /// the given text.
-  /// </summary>
-  /// <remarks>
-  /// Equivalent to using the LEFT() sheet function and comparing values.
-  /// </remarks>
-  /// <remarks>BeginsWith Excel CF Rule Type</remarks>
-  BeginsWith,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells in the range between the
-  /// given two formulas.
-  /// </summary>
-  /// <remarks>CellIs Excel CF Rule Type</remarks>
-  Between,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells that are completely blank.
-  /// </summary>
-  /// <remarks>
-  /// Equivalent of using LEN(TRIM()). This means that if the cell contains only
-  /// characters that TRIM() would remove, then it is considered blank. An empty cell
-  /// is also considered blank.
-  /// </remarks>
-  /// <remarks>ContainsBlanks Excel CF Rule Type</remarks>
-  ContainsBlanks,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells with formula errors.
-  /// </summary>
-  /// <remarks>
-  /// Equivalent to using ISERROR() sheet function to determine if there is
-  /// a formula error.
-  /// </remarks>
-  /// <remarks>ContainsErrors Excel CF Rule Type</remarks>
-  ContainsErrors,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells in the range that begin with
-  /// the given text.
-  /// </summary>
-  /// <remarks>
-  /// Equivalent to using the LEFT() sheet function and comparing values.
-  /// </remarks>
-  /// <remarks>ContainsText Excel CF Rule Type</remarks>
-  ContainsText,
-
-  /// <summary>
-  /// This conditional formatting rule highlights duplicated values.
-  /// </summary>
-  /// <remarks>DuplicateValues Excel CF Rule Type</remarks>
-  DuplicateValues,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells ending with given text.
-  /// </summary>
-  /// <remarks>
-  /// Equivalent to using the RIGHT() sheet function and comparing values.
-  /// </remarks>
-  /// <remarks>EndsWith Excel CF Rule Type</remarks>
-  EndsWith,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells equals to with given formula.
-  /// </summary>
-  /// <remarks>CellIs Excel CF Rule Type</remarks>
-  Equal,
-
-  /// <summary>
-  /// This conditional formatting rule contains a formula to evaluate. When the
-  /// formula result is true, the cell is highlighted.
-  /// </summary>
-  /// <remarks>Expression Excel CF Rule Type</remarks>
-  Expression,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells greater than the given formula.
-  /// </summary>
-  /// <remarks>CellIs Excel CF Rule Type</remarks>
-  GreaterThan,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells greater than or equal the
-  /// given formula.
-  /// </summary>
-  /// <remarks>CellIs Excel CF Rule Type</remarks>
-  GreaterThanOrEqual,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells less than the given formula.
-  /// </summary>
-  /// <remarks>CellIs Excel CF Rule Type</remarks>
-  LessThan,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells less than or equal the
-  /// given formula.
-  /// </summary>
-  /// <remarks>CellIs Excel CF Rule Type</remarks>
-  LessThanOrEqual,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells outside the range in
-  /// given two formulas.
-  /// </summary>
-  /// <remarks>CellIs Excel CF Rule Type</remarks>
-  NotBetween,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells that does not contains the
-  /// given formula.
-  /// </summary>
-  /// <remarks>CellIs Excel CF Rule Type</remarks>
-  NotContains,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells that are not blank.
-  /// </summary>
-  /// <remarks>
-  /// Equivalent of using LEN(TRIM()). This means that if the cell contains only
-  /// characters that TRIM() would remove, then it is considered blank. An empty cell
-  /// is also considered blank.
-  /// </remarks>
-  /// <remarks>NotContainsBlanks Excel CF Rule Type</remarks>
-  NotContainsBlanks,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells without formula errors.
-  /// </summary>
-  /// <remarks>
-  /// Equivalent to using ISERROR() sheet function to determine if there is a
-  /// formula error.
-  /// </remarks>
-  /// <remarks>NotContainsErrors Excel CF Rule Type</remarks>
-  NotContainsErrors,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells that do not contain
-  /// the given text.
-  /// </summary>
-  /// <remarks>
-  /// Equivalent to using the SEARCH() sheet function.
-  /// </remarks>
-  /// <remarks>NotContainsText Excel CF Rule Type</remarks>
-  NotContainsText,
-
-  /// <summary>
-  /// This conditional formatting rule highlights cells not equals to with
-  /// given formula.
-  /// </summary>
-  /// <remarks>CellIs Excel CF Rule Type</remarks>
-  NotEqual,
-
-  /// <summary>
-  /// This conditional formatting rule highlights unique values in the range.
-  /// </summary>
-  /// <remarks>UniqueValues Excel CF Rule Type</remarks>
-  UniqueValues,
-
-  /// <summary>
-  /// Three Color Scale (Low, Middle and High Color Scale)
-  /// </summary>
-  /// <remarks>ColorScale Excel CF Rule Type</remarks>
-  ThreeColorScale,
-
-  /// <summary>
-  /// Two Color Scale (Low and High Color Scale)
-  /// </summary>
-  /// <remarks>ColorScale Excel CF Rule Type</remarks>
-  TwoColorScale,
-
-  /// <summary>
-  /// This conditional formatting rule applies a 3 set icons to cells according
-  /// to their values.
-  /// </summary>
-  /// <remarks>IconSet Excel CF Rule Type</remarks>
-  ThreeIconSet,
-
-  /// <summary>
-  /// This conditional formatting rule applies a 4 set icons to cells according
-  /// to their values.
-  /// </summary>
-  /// <remarks>IconSet Excel CF Rule Type</remarks>
-  FourIconSet,
-
-  /// <summary>
-  /// This conditional formatting rule applies a 5 set icons to cells according
-  /// to their values.
-  /// </summary>
-  /// <remarks>IconSet Excel CF Rule Type</remarks>
-  FiveIconSet,
-
-  /// <summary>
-  /// This conditional formatting rule displays a gradated data bar in the range of cells.
-  /// </summary>
-  /// <remarks>DataBar Excel CF Rule Type</remarks>
-  DataBar,
-}
-
-/// <summary>
-/// Enum for Conditional Format Value Object Type ST_CfvoType §18.18.13
-/// </summary>
-public enum eExcelConditionalFormattingValueObjectType {
-  /// <summary>
-  /// Formula
-  /// </summary>
-  Formula,
-
-  /// <summary>
-  /// Maximum Value
-  /// </summary>
-  Max,
-
-  /// <summary>
-  /// Minimum Value
-  /// </summary>
-  Min,
-
-  /// <summary>
-  /// Number Value
-  /// </summary>
-  Num,
-
-  /// <summary>
-  /// Percent
-  /// </summary>
-  Percent,
-
-  /// <summary>
-  /// Percentile
-  /// </summary>
-  Percentile,
-}
-
-/// <summary>
-/// Enum for Conditional Formatting Value Object Position
-/// </summary>
-public enum eExcelConditionalFormattingValueObjectPosition {
-  /// <summary>
-  /// The lower position for both TwoColorScale and ThreeColorScale
-  /// </summary>
-  Low,
-
-  /// <summary>
-  /// The middle position only for ThreeColorScale
-  /// </summary>
-  Middle,
-
-  /// <summary>
-  /// The highest position for both TwoColorScale and ThreeColorScale
-  /// </summary>
-  High,
-}
-
-/// <summary>
-/// Enum for Conditional Formatting Value Object Node Type
-/// </summary>
-public enum eExcelConditionalFormattingValueObjectNodeType {
-  /// <summary>
-  /// 'cfvo' node
-  /// </summary>
-  Cfvo,
-
-  /// <summary>
-  /// 'color' node
-  /// </summary>
-  Color,
-}
-
-/// <summary>
-/// Enum for Conditional Formatting Operartor Type ST_ConditionalFormattingOperator §18.18.15
-/// </summary>
-public enum eExcelConditionalFormattingOperatorType {
-  /// <summary>
-  /// Begins With. 'Begins with' operator
-  /// </summary>
-  BeginsWith,
-
-  /// <summary>
-  /// Between. 'Between' operator
-  /// </summary>
-  Between,
-
-  /// <summary>
-  /// Contains. 'Contains' operator
-  /// </summary>
-  ContainsText,
-
-  /// <summary>
-  /// Ends With. 'Ends with' operator
-  /// </summary>
-  EndsWith,
-
-  /// <summary>
-  /// Equal. 'Equal to' operator
-  /// </summary>
-  Equal,
-
-  /// <summary>
-  /// Greater Than. 'Greater than' operator
-  /// </summary>
-  GreaterThan,
-
-  /// <summary>
-  /// Greater Than Or Equal. 'Greater than or equal to' operator
-  /// </summary>
-  GreaterThanOrEqual,
-
-  /// <summary>
-  /// Less Than. 'Less than' operator
-  /// </summary>
-  LessThan,
-
-  /// <summary>
-  /// Less Than Or Equal. 'Less than or equal to' operator
-  /// </summary>
-  LessThanOrEqual,
-
-  /// <summary>
-  /// Not Between. 'Not between' operator
-  /// </summary>
-  NotBetween,
-
-  /// <summary>
-  /// Does Not Contain. 'Does not contain' operator
-  /// </summary>
-  NotContains,
-
-  /// <summary>
-  /// Not Equal. 'Not equal to' operator
-  /// </summary>
-  NotEqual,
-}
-
-/// <summary>
-/// Enum for Conditional Formatting Time Period Type ST_TimePeriod §18.18.82
-/// </summary>
-public enum eExcelConditionalFormattingTimePeriodType {
-  /// <summary>
-  /// Last 7 Days. A date in the last seven days.
-  /// </summary>
-  Last7Days,
-
-  /// <summary>
-  /// Last Month. A date occuring in the last calendar month.
-  /// </summary>
-  LastMonth,
-
-  /// <summary>
-  /// Last Week. A date occuring last week.
-  /// </summary>
-  LastWeek,
-
-  /// <summary>
-  /// Next Month. A date occuring in the next calendar month.
-  /// </summary>
-  NextMonth,
-
-  /// <summary>
-  /// Next Week. A date occuring next week.
-  /// </summary>
-  NextWeek,
-
-  /// <summary>
-  /// This Month. A date occuring in this calendar month.
-  /// </summary>
-  ThisMonth,
-
-  /// <summary>
-  /// This Week. A date occuring this week.
-  /// </summary>
-  ThisWeek,
-
-  /// <summary>
-  /// Today. Today's date.
-  /// </summary>
-  Today,
-
-  /// <summary>
-  /// Tomorrow. Tomorrow's date.
-  /// </summary>
-  Tomorrow,
-
-  /// <summary>
-  /// Yesterday. Yesterday's date.
-  /// </summary>
-  Yesterday,
-}
-
-/// <summary>
-/// 18.18.42 ST_IconSetType (Icon Set Type) - Only 3 icons
-/// </summary>
-public enum eExcelconditionalFormatting3IconsSetType {
-  /// <summary>
-  /// (3 Arrows) 3 arrows icon set.
-  /// </summary>
-  Arrows,
-
-  /// <summary>
-  /// (3 Arrows (Gray)) 3 gray arrows icon set.
-  /// </summary>
-  ArrowsGray,
-
-  /// <summary>
-  /// (3 Flags) 3 flags icon set.
-  /// </summary>
-  Flags,
-
-  /// <summary>
-  /// (3 Signs) 3 signs icon set.
-  /// </summary>
-  Signs,
-
-  /// <summary>
-  /// (3 Symbols Circled) 3 symbols icon set.
-  /// </summary>
-  Symbols,
-
-  /// <summary>
-  /// (3 Symbols) 3 Symbols icon set.
-  /// </summary>
-  Symbols2,
-
-  /// <summary>
-  /// (3 Traffic Lights) 3 traffic lights icon set (#1).
-  /// </summary>
-  TrafficLights1,
-
-  /// <summary>
-  /// (3 Traffic Lights Black) 3 traffic lights icon set with thick black border.
-  /// </summary>
-  TrafficLights2,
-}
-
-/// <summary>
-/// 18.18.42 ST_IconSetType (Icon Set Type) - Only 4 icons
-/// </summary>
-public enum eExcelconditionalFormatting4IconsSetType {
-  /// <summary>
-  /// (4 Arrows) 4 arrows icon set.
-  /// </summary>
-  Arrows,
-
-  /// <summary>
-  /// (4 Arrows (Gray)) 4 gray arrows icon set.
-  /// </summary>
-  ArrowsGray,
-
-  /// <summary>
-  /// (4 Ratings) 4 ratings icon set.
-  /// </summary>
-  Rating,
-
-  /// <summary>
-  /// (4 Red To Black) 4 'red to black' icon set.
-  /// </summary>
-  RedToBlack,
-
-  /// <summary>
-  /// (4 Traffic Lights) 4 traffic lights icon set.
-  /// </summary>
-  TrafficLights,
-}
-
-/// <summary>
-/// 18.18.42 ST_IconSetType (Icon Set Type) - Only 5 icons
-/// </summary>
-public enum eExcelconditionalFormatting5IconsSetType {
-  /// <summary>
-  /// (5 Arrows) 5 arrows icon set.
-  /// </summary>
-  Arrows,
-
-  /// <summary>
-  /// (5 Arrows (Gray)) 5 gray arrows icon set.
-  /// </summary>
-  ArrowsGray,
-
-  /// <summary>
-  /// (5 Quarters) 5 quarters icon set.
-  /// </summary>
-  Quarters,
-
-  /// <summary>
-  /// (5 Ratings Icon Set) 5 rating icon set.
-  /// </summary>
-  Rating,
-}
-
-/// <summary>
-/// 18.18.42 ST_IconSetType (Icon Set Type)
-/// </summary>
-public enum eExcelconditionalFormattingIconsSetType {
-  /// <summary>
-  /// (3 Arrows) 3 arrows icon set.
-  /// </summary>
-  ThreeArrows,
-
-  /// <summary>
-  /// (3 Arrows (Gray)) 3 gray arrows icon set.
-  /// </summary>
-  ThreeArrowsGray,
-
-  /// <summary>
-  /// (3 Flags) 3 flags icon set.
-  /// </summary>
-  ThreeFlags,
-
-  /// <summary>
-  /// (3 Signs) 3 signs icon set.
-  /// </summary>
-  ThreeSigns,
-
-  /// <summary>
-  /// (3 Symbols Circled) 3 symbols icon set.
-  /// </summary>
-  ThreeSymbols,
-
-  /// <summary>
-  /// (3 Symbols) 3 Symbols icon set.
-  /// </summary>
-  ThreeSymbols2,
-
-  /// <summary>
-  /// (3 Traffic Lights) 3 traffic lights icon set (#1).
-  /// </summary>
-  ThreeTrafficLights1,
-
-  /// <summary>
-  /// (3 Traffic Lights Black) 3 traffic lights icon set with thick black border.
-  /// </summary>
-  ThreeTrafficLights2,
-
-  /// <summary>
-  /// (4 Arrows) 4 arrows icon set.
-  /// </summary>
-  FourArrows,
-
-  /// <summary>
-  /// (4 Arrows (Gray)) 4 gray arrows icon set.
-  /// </summary>
-  FourArrowsGray,
-
-  /// <summary>
-  /// (4 Ratings) 4 ratings icon set.
-  /// </summary>
-  FourRating,
-
-  /// <summary>
-  /// (4 Red To Black) 4 'red to black' icon set.
-  /// </summary>
-  FourRedToBlack,
-
-  /// <summary>
-  /// (4 Traffic Lights) 4 traffic lights icon set.
-  /// </summary>
-  FourTrafficLights,
-
-  /// <summary>
-  /// (5 Arrows) 5 arrows icon set.
-  /// </summary>
-  FiveArrows,
-
-  /// <summary>
-  /// (5 Arrows (Gray)) 5 gray arrows icon set.
-  /// </summary>
-  FiveArrowsGray,
-
-  /// <summary>
-  /// (5 Quarters) 5 quarters icon set.
-  /// </summary>
-  FiveQuarters,
-
-  /// <summary>
-  /// (5 Ratings Icon Set) 5 rating icon set.
-  /// </summary>
-  FiveRating,
-}
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingHelper.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingHelper.cs
deleted file mode 100644
index ba97c3d..0000000
--- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingHelper.cs
+++ /dev/null
@@ -1,204 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System;
-using System.Globalization;
-using System.Text.RegularExpressions;
-using System.Xml;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// Conditional formatting helper
-/// </summary>
-internal static class ExcelConditionalFormattingHelper {
-  /// <summary>
-  /// Check and fix an address (string address)
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public static string CheckAndFixRangeAddress(string address) {
-    if (address.Contains(',')) {
-      throw new FormatException(
-          ExcelConditionalFormattingConstants.Errors._commaSeparatedAddresses);
-    }
-
-    address = address.ToUpper(CultureInfo.InvariantCulture);
-
-    if (Regex.IsMatch(address, "[A-Z]+:[A-Z]+")) {
-      address = AddressUtility.ParseEntireColumnSelections(address);
-    }
-
-    return address;
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="node"></param>
-  /// <param name="attribute"></param>
-  /// <returns></returns>
-  public static string GetAttributeString(XmlNode node, string attribute) {
-    try {
-      var value = node.Attributes[attribute].Value;
-      return value ?? string.Empty;
-    } catch {
-      return string.Empty;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="node"></param>
-  /// <param name="attribute"></param>
-  /// <returns></returns>
-  public static int GetAttributeInt(XmlNode node, string attribute) {
-    try {
-      var value = node.Attributes[attribute].Value;
-      return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture);
-    } catch {
-      return int.MinValue;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="node"></param>
-  /// <param name="attribute"></param>
-  /// <returns></returns>
-  public static int? GetAttributeIntNullable(XmlNode node, string attribute) {
-    try {
-      if (node.Attributes[attribute] == null) {
-        return null;
-      }
-      var value = node.Attributes[attribute].Value;
-      return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture);
-    } catch {
-      return null;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="node"></param>
-  /// <param name="attribute"></param>
-  /// <returns></returns>
-  public static bool GetAttributeBool(XmlNode node, string attribute) {
-    try {
-      var value = node.Attributes[attribute].Value;
-      return (value == "1"
-              || value == "-1"
-              || value.Equals("TRUE", StringComparison.InvariantCultureIgnoreCase));
-    } catch {
-      return false;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="node"></param>
-  /// <param name="attribute"></param>
-  /// <returns></returns>
-  public static bool? GetAttributeBoolNullable(XmlNode node, string attribute) {
-    try {
-      if (node.Attributes[attribute] == null) {
-        return null;
-      }
-      var value = node.Attributes[attribute].Value;
-      return (value == "1"
-              || value == "-1"
-              || value.Equals("TRUE", StringComparison.InvariantCultureIgnoreCase));
-    } catch {
-      return null;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="node"></param>
-  /// <param name="attribute"></param>
-  /// <returns></returns>
-  public static double GetAttributeDouble(XmlNode node, string attribute) {
-    try {
-      var value = node.Attributes[attribute].Value;
-      return double.Parse(value, NumberStyles.Number, CultureInfo.InvariantCulture);
-    } catch {
-      return double.NaN;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="node"></param>
-  /// <param name="attribute"></param>
-  /// <returns></returns>
-  public static decimal GetAttributeDecimal(XmlNode node, string attribute) {
-    try {
-      var value = node.Attributes[attribute].Value;
-      return decimal.Parse(value, NumberStyles.Any, CultureInfo.InvariantCulture);
-    } catch {
-      return decimal.MinValue;
-    }
-  }
-
-  /// <summary>
-  /// Encode to XML (special characteres: &apos; &quot; &gt; &lt; &amp;)
-  /// </summary>
-  /// <param name="s"></param>
-  /// <returns></returns>
-  public static string EncodeXml(this string s) {
-    return s.Replace("&", "&amp;")
-        .Replace("<", "&lt;")
-        .Replace(">", "&gt;")
-        .Replace("\"", "&quot;")
-        .Replace("'", "&apos;");
-  }
-
-  /// <summary>
-  /// Decode from XML (special characteres: &apos; &quot; &gt; &lt; &amp;)
-  /// </summary>
-  /// <param name="s"></param>
-  /// <returns></returns>
-  public static string DecodeXml(this string s) {
-    return s.Replace("'", "&apos;")
-        .Replace("\"", "&quot;")
-        .Replace(">", "&gt;")
-        .Replace("<", "&lt;")
-        .Replace("&", "&amp;");
-  }
-}
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingIconDatabarValue.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingIconDatabarValue.cs
deleted file mode 100644
index c38d095..0000000
--- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingIconDatabarValue.cs
+++ /dev/null
@@ -1,290 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System;
-using System.Collections.Immutable;
-using System.Drawing;
-using System.Globalization;
-using System.Xml;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// 18.3.1.11 cfvo (Conditional Format Value Object)
-/// Describes the values of the interpolation points in a gradient scale.
-/// </summary>
-public class ExcelConditionalFormattingIconDataBarValue : XmlHelper {
-  private eExcelConditionalFormattingRuleType _ruleType;
-  private readonly ExcelWorksheet _worksheet;
-
-  /// <summary>
-  /// Initialize the cfvo (§18.3.1.11) node
-  /// </summary>
-  /// <param name="type"></param>
-  /// <param name="value"></param>
-  /// <param name="formula"></param>
-  /// <param name="ruleType"></param>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode">The cfvo (§18.3.1.11) node parent. Can be any of the following:
-  /// colorScale (§18.3.1.16); dataBar (§18.3.1.28); iconSet (§18.3.1.49)</param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingIconDataBarValue(
-      eExcelConditionalFormattingValueObjectType type,
-      double value,
-      string formula,
-      eExcelConditionalFormattingRuleType ruleType,
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : this(ruleType, address, worksheet, itemElementNode, namespaceManager) {
-    Require.Argument(priority).IsInRange(1, int.MaxValue, "priority");
-
-    // Check if the parent does not exists
-    if (itemElementNode == null) {
-      // Get the parent node path by the rule type
-      string parentNodePath = ExcelConditionalFormattingValueObjectType.GetParentPathByRuleType(
-          ruleType);
-
-      // Check for en error (rule type does not have <cfvo>)
-      if (parentNodePath == string.Empty) {
-        throw new(ExcelConditionalFormattingConstants.Errors._missingCfvoParentNode);
-      }
-
-      // Point to the <cfvo> parent node
-      itemElementNode = _worksheet.WorksheetXml.SelectSingleNode(
-          string.Format(
-              "//{0}[{1}='{2}']/{3}[{4}='{5}']/{6}",
-              // {0}
-              ExcelConditionalFormattingConstants.Paths._conditionalFormatting,
-              // {1}
-              ExcelConditionalFormattingConstants.Paths._sqrefAttribute,
-              // {2}
-              address.Address,
-              // {3}
-              ExcelConditionalFormattingConstants.Paths._cfRule,
-              // {4}
-              ExcelConditionalFormattingConstants.Paths._priorityAttribute,
-              // {5}
-              priority,
-              // {6}
-              parentNodePath),
-          _worksheet.NameSpaceManager);
-
-      // Check for en error (rule type does not have <cfvo>)
-      if (itemElementNode == null) {
-        throw new(ExcelConditionalFormattingConstants.Errors._missingCfvoParentNode);
-      }
-    }
-
-    TopNode = itemElementNode;
-
-    // Save the attributes
-    RuleType = ruleType;
-    Type = type;
-    Value = value;
-    Formula = formula;
-  }
-
-  protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
-    ExcelConditionalFormattingConstants.Nodes._cfvo,
-  ];
-
-  /// <summary>
-  /// Initialize the cfvo (§18.3.1.11) node
-  /// </summary>
-  /// <param name="ruleType"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode">The cfvo (§18.3.1.11) node parent. Can be any of the following:
-  /// colorScale (§18.3.1.16); dataBar (§18.3.1.28); iconSet (§18.3.1.49)</param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingIconDataBarValue(
-      eExcelConditionalFormattingRuleType ruleType,
-      ExcelAddress address,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(namespaceManager, itemElementNode) {
-    Require.Argument(address).IsNotNull("address");
-    Require.Argument(worksheet).IsNotNull("worksheet");
-
-    // Save the worksheet for private methods to use
-    _worksheet = worksheet;
-
-    //Check if the parent does not exists
-    if (itemElementNode == null) {
-      // Get the parent node path by the rule type
-      string parentNodePath = ExcelConditionalFormattingValueObjectType.GetParentPathByRuleType(
-          ruleType);
-
-      // Check for en error (rule type does not have <cfvo>)
-      if (parentNodePath == string.Empty) {
-        throw new(ExcelConditionalFormattingConstants.Errors._missingCfvoParentNode);
-      }
-    }
-    RuleType = ruleType;
-  }
-
-  /// <summary>
-  /// Initialize the <see cref="ExcelConditionalFormattingColorScaleValue"/>
-  /// </summary>
-  /// <param name="type"></param>
-  /// <param name="value"></param>
-  /// <param name="formula"></param>
-  /// <param name="ruleType"></param>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingIconDataBarValue(
-      eExcelConditionalFormattingValueObjectType type,
-      double value,
-      string formula,
-      eExcelConditionalFormattingRuleType ruleType,
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNamespaceManager namespaceManager)
-      : this(
-          type,
-          value,
-          formula,
-          ruleType,
-          address,
-          priority,
-          worksheet,
-          null,
-          namespaceManager) {}
-
-  /// <summary>
-  /// Initialize the <see cref="ExcelConditionalFormattingColorScaleValue"/>
-  /// </summary>
-  /// <param name="type"></param>
-  /// <param name="color"></param>
-  /// <param name="ruleType"></param>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingIconDataBarValue(
-      eExcelConditionalFormattingValueObjectType type,
-      Color color,
-      eExcelConditionalFormattingRuleType ruleType,
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNamespaceManager namespaceManager)
-      : this(type, 0, null, ruleType, address, priority, worksheet, null, namespaceManager) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  internal eExcelConditionalFormattingRuleType RuleType {
-    get => _ruleType;
-    set => _ruleType = value;
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  public eExcelConditionalFormattingValueObjectType Type {
-    get {
-      var typeAttribute = GetXmlNodeString(
-          ExcelConditionalFormattingConstants.Paths._typeAttribute);
-
-      return ExcelConditionalFormattingValueObjectType.GetTypeByAttrbiute(typeAttribute);
-    }
-    set {
-      if ((_ruleType == eExcelConditionalFormattingRuleType.ThreeIconSet
-                  || _ruleType == eExcelConditionalFormattingRuleType.FourIconSet
-                  || _ruleType == eExcelConditionalFormattingRuleType.FiveIconSet)
-          && (value == eExcelConditionalFormattingValueObjectType.Min
-                  || value == eExcelConditionalFormattingValueObjectType.Max)) {
-        throw (new ArgumentException("Value type can't be Min or Max for icon sets"));
-      }
-      SetXmlNodeString(
-          ExcelConditionalFormattingConstants.Paths._typeAttribute,
-          value.ToString().ToLower(CultureInfo.InvariantCulture));
-    }
-  }
-
-  /// <summary>
-  /// Get/Set the 'cfvo' node @val attribute
-  /// </summary>
-  public Double Value {
-    get {
-      if ((Type == eExcelConditionalFormattingValueObjectType.Num)
-          || (Type == eExcelConditionalFormattingValueObjectType.Percent)
-          || (Type == eExcelConditionalFormattingValueObjectType.Percentile)) {
-        return GetXmlNodeDouble(ExcelConditionalFormattingConstants.Paths._valAttribute);
-      }
-      return 0;
-    }
-    set {
-      string valueToStore = string.Empty;
-
-      // Only some types use the @val attribute
-      if ((Type == eExcelConditionalFormattingValueObjectType.Num)
-          || (Type == eExcelConditionalFormattingValueObjectType.Percent)
-          || (Type == eExcelConditionalFormattingValueObjectType.Percentile)) {
-        valueToStore = value.ToString(CultureInfo.InvariantCulture);
-      }
-
-      SetXmlNodeString(ExcelConditionalFormattingConstants.Paths._valAttribute, valueToStore);
-    }
-  }
-
-  /// <summary>
-  /// Get/Set the Formula of the Object Value (uses the same attribute as the Value)
-  /// </summary>
-  public string Formula {
-    get {
-      // Return empty if the Object Value type is not Formula
-      if (Type != eExcelConditionalFormattingValueObjectType.Formula) {
-        return string.Empty;
-      }
-
-      // Excel stores the formula in the @val attribute
-      return GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._valAttribute);
-    }
-    set {
-      // Only store the formula if the Object Value type is Formula
-      if (Type == eExcelConditionalFormattingValueObjectType.Formula) {
-        SetXmlNodeString(ExcelConditionalFormattingConstants.Paths._valAttribute, value);
-      }
-    }
-  }
-}
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingOperatorType.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingOperatorType.cs
deleted file mode 100644
index c513d8d..0000000
--- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingOperatorType.cs
+++ /dev/null
@@ -1,131 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-17
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// Functions related to the <see cref="ExcelConditionalFormattingOperatorType"/>
-/// </summary>
-internal static class ExcelConditionalFormattingOperatorType {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="type"></param>
-  /// <returns></returns>
-  internal static string GetAttributeByType(eExcelConditionalFormattingOperatorType type) {
-    switch (type) {
-      case eExcelConditionalFormattingOperatorType.BeginsWith:
-        return ExcelConditionalFormattingConstants.Operators._beginsWith;
-
-      case eExcelConditionalFormattingOperatorType.Between:
-        return ExcelConditionalFormattingConstants.Operators._between;
-
-      case eExcelConditionalFormattingOperatorType.ContainsText:
-        return ExcelConditionalFormattingConstants.Operators._containsText;
-
-      case eExcelConditionalFormattingOperatorType.EndsWith:
-        return ExcelConditionalFormattingConstants.Operators._endsWith;
-
-      case eExcelConditionalFormattingOperatorType.Equal:
-        return ExcelConditionalFormattingConstants.Operators._equal;
-
-      case eExcelConditionalFormattingOperatorType.GreaterThan:
-        return ExcelConditionalFormattingConstants.Operators._greaterThan;
-
-      case eExcelConditionalFormattingOperatorType.GreaterThanOrEqual:
-        return ExcelConditionalFormattingConstants.Operators._greaterThanOrEqual;
-
-      case eExcelConditionalFormattingOperatorType.LessThan:
-        return ExcelConditionalFormattingConstants.Operators._lessThan;
-
-      case eExcelConditionalFormattingOperatorType.LessThanOrEqual:
-        return ExcelConditionalFormattingConstants.Operators._lessThanOrEqual;
-
-      case eExcelConditionalFormattingOperatorType.NotBetween:
-        return ExcelConditionalFormattingConstants.Operators._notBetween;
-
-      case eExcelConditionalFormattingOperatorType.NotContains:
-        return ExcelConditionalFormattingConstants.Operators._notContains;
-
-      case eExcelConditionalFormattingOperatorType.NotEqual:
-        return ExcelConditionalFormattingConstants.Operators._notEqual;
-    }
-
-    return string.Empty;
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// param name="attribute"
-  /// <returns></returns>
-  internal static eExcelConditionalFormattingOperatorType GetTypeByAttribute(string attribute) {
-    switch (attribute) {
-      case ExcelConditionalFormattingConstants.Operators._beginsWith:
-        return eExcelConditionalFormattingOperatorType.BeginsWith;
-
-      case ExcelConditionalFormattingConstants.Operators._between:
-        return eExcelConditionalFormattingOperatorType.Between;
-
-      case ExcelConditionalFormattingConstants.Operators._containsText:
-        return eExcelConditionalFormattingOperatorType.ContainsText;
-
-      case ExcelConditionalFormattingConstants.Operators._endsWith:
-        return eExcelConditionalFormattingOperatorType.EndsWith;
-
-      case ExcelConditionalFormattingConstants.Operators._equal:
-        return eExcelConditionalFormattingOperatorType.Equal;
-
-      case ExcelConditionalFormattingConstants.Operators._greaterThan:
-        return eExcelConditionalFormattingOperatorType.GreaterThan;
-
-      case ExcelConditionalFormattingConstants.Operators._greaterThanOrEqual:
-        return eExcelConditionalFormattingOperatorType.GreaterThanOrEqual;
-
-      case ExcelConditionalFormattingConstants.Operators._lessThan:
-        return eExcelConditionalFormattingOperatorType.LessThan;
-
-      case ExcelConditionalFormattingConstants.Operators._lessThanOrEqual:
-        return eExcelConditionalFormattingOperatorType.LessThanOrEqual;
-
-      case ExcelConditionalFormattingConstants.Operators._notBetween:
-        return eExcelConditionalFormattingOperatorType.NotBetween;
-
-      case ExcelConditionalFormattingConstants.Operators._notContains:
-        return eExcelConditionalFormattingOperatorType.NotContains;
-
-      case ExcelConditionalFormattingConstants.Operators._notEqual:
-        return eExcelConditionalFormattingOperatorType.NotEqual;
-    }
-
-    throw new(ExcelConditionalFormattingConstants.Errors._unexistentOperatorTypeAttribute);
-  }
-}
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingRuleFactory.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingRuleFactory.cs
deleted file mode 100644
index 6bc7563..0000000
--- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingRuleFactory.cs
+++ /dev/null
@@ -1,359 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- *  * Author							Change						      Date
- * ******************************************************************************
- * Eyal Seagull		    Conditional Formatting      2012-04-03
- *******************************************************************************/
-
-using System;
-using System.Xml;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// Factory class for ExcelConditionalFormatting.
-/// </summary>
-internal static class ExcelConditionalFormattingRuleFactory {
-  public static ExcelConditionalFormattingRule Create(
-      eExcelConditionalFormattingRuleType type,
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode) {
-    Require.Argument(type);
-    Require.Argument(address).IsNotNull("address");
-    Require.Argument(priority).IsInRange(1, int.MaxValue, "priority");
-    Require.Argument(worksheet).IsNotNull("worksheet");
-
-    // According the conditional formatting rule type
-    switch (type) {
-      case eExcelConditionalFormattingRuleType.AboveAverage:
-        return new ExcelConditionalFormattingAboveAverage(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.AboveOrEqualAverage:
-        return new ExcelConditionalFormattingAboveOrEqualAverage(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.BelowAverage:
-        return new ExcelConditionalFormattingBelowAverage(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.BelowOrEqualAverage:
-        return new ExcelConditionalFormattingBelowOrEqualAverage(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.AboveStdDev:
-        return new ExcelConditionalFormattingAboveStdDev(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.BelowStdDev:
-        return new ExcelConditionalFormattingBelowStdDev(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.Bottom:
-        return new ExcelConditionalFormattingBottom(address, priority, worksheet, itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.BottomPercent:
-        return new ExcelConditionalFormattingBottomPercent(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.Top:
-        return new ExcelConditionalFormattingTop(address, priority, worksheet, itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.TopPercent:
-        return new ExcelConditionalFormattingTopPercent(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.Last7Days:
-        return new ExcelConditionalFormattingLast7Days(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.LastMonth:
-        return new ExcelConditionalFormattingLastMonth(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.LastWeek:
-        return new ExcelConditionalFormattingLastWeek(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.NextMonth:
-        return new ExcelConditionalFormattingNextMonth(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.NextWeek:
-        return new ExcelConditionalFormattingNextWeek(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.ThisMonth:
-        return new ExcelConditionalFormattingThisMonth(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.ThisWeek:
-        return new ExcelConditionalFormattingThisWeek(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.Today:
-        return new ExcelConditionalFormattingToday(address, priority, worksheet, itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.Tomorrow:
-        return new ExcelConditionalFormattingTomorrow(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.Yesterday:
-        return new ExcelConditionalFormattingYesterday(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.BeginsWith:
-        return new ExcelConditionalFormattingBeginsWith(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.Between:
-        return new ExcelConditionalFormattingBetween(address, priority, worksheet, itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.ContainsBlanks:
-        return new ExcelConditionalFormattingContainsBlanks(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.ContainsErrors:
-        return new ExcelConditionalFormattingContainsErrors(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.ContainsText:
-        return new ExcelConditionalFormattingContainsText(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.DuplicateValues:
-        return new ExcelConditionalFormattingDuplicateValues(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.EndsWith:
-        return new ExcelConditionalFormattingEndsWith(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.Equal:
-        return new ExcelConditionalFormattingEqual(address, priority, worksheet, itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.Expression:
-        return new ExcelConditionalFormattingExpression(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.GreaterThan:
-        return new ExcelConditionalFormattingGreaterThan(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.GreaterThanOrEqual:
-        return new ExcelConditionalFormattingGreaterThanOrEqual(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.LessThan:
-        return new ExcelConditionalFormattingLessThan(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.LessThanOrEqual:
-        return new ExcelConditionalFormattingLessThanOrEqual(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.NotBetween:
-        return new ExcelConditionalFormattingNotBetween(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.NotContainsBlanks:
-        return new ExcelConditionalFormattingNotContainsBlanks(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.NotContainsErrors:
-        return new ExcelConditionalFormattingNotContainsErrors(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.NotContainsText:
-        return new ExcelConditionalFormattingNotContainsText(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.NotEqual:
-        return new ExcelConditionalFormattingNotEqual(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.UniqueValues:
-        return new ExcelConditionalFormattingUniqueValues(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.ThreeColorScale:
-        return new ExcelConditionalFormattingThreeColorScale(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-
-      case eExcelConditionalFormattingRuleType.TwoColorScale:
-        return new ExcelConditionalFormattingTwoColorScale(
-            address,
-            priority,
-            worksheet,
-            itemElementNode);
-      case eExcelConditionalFormattingRuleType.ThreeIconSet:
-        return new ExcelConditionalFormattingThreeIconSet(
-            address,
-            priority,
-            worksheet,
-            itemElementNode,
-            null);
-      case eExcelConditionalFormattingRuleType.FourIconSet:
-        return new ExcelConditionalFormattingFourIconSet(
-            address,
-            priority,
-            worksheet,
-            itemElementNode,
-            null);
-      case eExcelConditionalFormattingRuleType.FiveIconSet:
-        return new ExcelConditionalFormattingFiveIconSet(
-            address,
-            priority,
-            worksheet,
-            itemElementNode,
-            null);
-      case eExcelConditionalFormattingRuleType.DataBar:
-        return new ExcelConditionalFormattingDataBar(
-            eExcelConditionalFormattingRuleType.DataBar,
-            address,
-            priority,
-            worksheet,
-            itemElementNode,
-            null);
-
-      //TODO: Add DataBar
-    }
-
-    throw new InvalidOperationException(
-        string.Format(
-            ExcelConditionalFormattingConstants.Errors._nonSupportedRuleType,
-            type.ToString()));
-  }
-}
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingRuleType.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingRuleType.cs
deleted file mode 100644
index 8168caa..0000000
--- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingRuleType.cs
+++ /dev/null
@@ -1,494 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// Functions related to the ExcelConditionalFormattingRule
-/// </summary>
-internal static class ExcelConditionalFormattingRuleType {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="attribute"></param>
-  /// <param name="topNode"></param>
-  /// <param name="nameSpaceManager"></param>
-  /// <returns></returns>
-  internal static eExcelConditionalFormattingRuleType GetTypeByAttrbiute(
-      string attribute,
-      XmlNode topNode,
-      XmlNamespaceManager nameSpaceManager) {
-    switch (attribute) {
-      case ExcelConditionalFormattingConstants.RuleType._aboveAverage:
-        return GetAboveAverageType(topNode, nameSpaceManager);
-
-      case ExcelConditionalFormattingConstants.RuleType._top10:
-        return GetTop10Type(topNode, nameSpaceManager);
-
-      case ExcelConditionalFormattingConstants.RuleType._timePeriod:
-        return GetTimePeriodType(topNode, nameSpaceManager);
-      case ExcelConditionalFormattingConstants.RuleType._cellIs:
-        return GetCellIs((XmlElement)topNode);
-      case ExcelConditionalFormattingConstants.RuleType._beginsWith:
-        return eExcelConditionalFormattingRuleType.BeginsWith;
-
-      //case ExcelConditionalFormattingConstants.RuleType.Between:
-      //  return eExcelConditionalFormattingRuleType.Between;
-
-      case ExcelConditionalFormattingConstants.RuleType._containsBlanks:
-        return eExcelConditionalFormattingRuleType.ContainsBlanks;
-
-      case ExcelConditionalFormattingConstants.RuleType._containsErrors:
-        return eExcelConditionalFormattingRuleType.ContainsErrors;
-
-      case ExcelConditionalFormattingConstants.RuleType._containsText:
-        return eExcelConditionalFormattingRuleType.ContainsText;
-
-      case ExcelConditionalFormattingConstants.RuleType._duplicateValues:
-        return eExcelConditionalFormattingRuleType.DuplicateValues;
-
-      case ExcelConditionalFormattingConstants.RuleType._endsWith:
-        return eExcelConditionalFormattingRuleType.EndsWith;
-
-      //case ExcelConditionalFormattingConstants.RuleType.Equal:
-      //  return eExcelConditionalFormattingRuleType.Equal;
-
-      case ExcelConditionalFormattingConstants.RuleType._expression:
-        return eExcelConditionalFormattingRuleType.Expression;
-
-      //case ExcelConditionalFormattingConstants.RuleType.GreaterThan:
-      //  return eExcelConditionalFormattingRuleType.GreaterThan;
-
-      //case ExcelConditionalFormattingConstants.RuleType.GreaterThanOrEqual:
-      //  return eExcelConditionalFormattingRuleType.GreaterThanOrEqual;
-
-      //case ExcelConditionalFormattingConstants.RuleType.LessThan:
-      //  return eExcelConditionalFormattingRuleType.LessThan;
-
-      //case ExcelConditionalFormattingConstants.RuleType.LessThanOrEqual:
-      //  return eExcelConditionalFormattingRuleType.LessThanOrEqual;
-
-      //case ExcelConditionalFormattingConstants.RuleType.NotBetween:
-      //  return eExcelConditionalFormattingRuleType.NotBetween;
-
-      case ExcelConditionalFormattingConstants.RuleType._notContainsBlanks:
-        return eExcelConditionalFormattingRuleType.NotContainsBlanks;
-
-      case ExcelConditionalFormattingConstants.RuleType._notContainsErrors:
-        return eExcelConditionalFormattingRuleType.NotContainsErrors;
-
-      case ExcelConditionalFormattingConstants.RuleType._notContainsText:
-        return eExcelConditionalFormattingRuleType.NotContainsText;
-
-      //case ExcelConditionalFormattingConstants.RuleType.NotEqual:
-      //  return eExcelConditionalFormattingRuleType.NotEqual;
-
-      case ExcelConditionalFormattingConstants.RuleType._uniqueValues:
-        return eExcelConditionalFormattingRuleType.UniqueValues;
-
-      case ExcelConditionalFormattingConstants.RuleType._colorScale:
-        return GetColorScaleType(topNode, nameSpaceManager);
-      case ExcelConditionalFormattingConstants.RuleType._iconSet:
-        return GetIconSetType(topNode, nameSpaceManager);
-      case ExcelConditionalFormattingConstants.RuleType._dataBar:
-        return eExcelConditionalFormattingRuleType.DataBar;
-    }
-
-    throw new(ExcelConditionalFormattingConstants.Errors._unexpectedRuleTypeAttribute);
-  }
-
-  private static eExcelConditionalFormattingRuleType GetCellIs(XmlElement node) {
-    switch (node.GetAttribute("operator")) {
-      case ExcelConditionalFormattingConstants.Operators._beginsWith:
-        return eExcelConditionalFormattingRuleType.BeginsWith;
-      case ExcelConditionalFormattingConstants.Operators._between:
-        return eExcelConditionalFormattingRuleType.Between;
-
-      case ExcelConditionalFormattingConstants.Operators._containsText:
-        return eExcelConditionalFormattingRuleType.ContainsText;
-
-      case ExcelConditionalFormattingConstants.Operators._endsWith:
-        return eExcelConditionalFormattingRuleType.EndsWith;
-
-      case ExcelConditionalFormattingConstants.Operators._equal:
-        return eExcelConditionalFormattingRuleType.Equal;
-
-      case ExcelConditionalFormattingConstants.Operators._greaterThan:
-        return eExcelConditionalFormattingRuleType.GreaterThan;
-
-      case ExcelConditionalFormattingConstants.Operators._greaterThanOrEqual:
-        return eExcelConditionalFormattingRuleType.GreaterThanOrEqual;
-
-      case ExcelConditionalFormattingConstants.Operators._lessThan:
-        return eExcelConditionalFormattingRuleType.LessThan;
-
-      case ExcelConditionalFormattingConstants.Operators._lessThanOrEqual:
-        return eExcelConditionalFormattingRuleType.LessThanOrEqual;
-
-      case ExcelConditionalFormattingConstants.Operators._notBetween:
-        return eExcelConditionalFormattingRuleType.NotBetween;
-
-      case ExcelConditionalFormattingConstants.Operators._notContains:
-        return eExcelConditionalFormattingRuleType.NotContains;
-
-      case ExcelConditionalFormattingConstants.Operators._notEqual:
-        return eExcelConditionalFormattingRuleType.NotEqual;
-      default:
-        throw new(ExcelConditionalFormattingConstants.Errors._unexistentOperatorTypeAttribute);
-    }
-  }
-
-  private static eExcelConditionalFormattingRuleType GetIconSetType(
-      XmlNode topNode,
-      XmlNamespaceManager nameSpaceManager) {
-    var node = topNode.SelectSingleNode("d:iconSet/@iconSet", nameSpaceManager);
-    if (node == null) {
-      return eExcelConditionalFormattingRuleType.ThreeIconSet;
-    }
-    var v = node.Value;
-
-    if (v[0] == '3') {
-      return eExcelConditionalFormattingRuleType.ThreeIconSet;
-    }
-    if (v[0] == '4') {
-      return eExcelConditionalFormattingRuleType.FourIconSet;
-    }
-    return eExcelConditionalFormattingRuleType.FiveIconSet;
-  }
-
-  /// <summary>
-  /// Get the "colorScale" rule type according to the number of "cfvo" and "color" nodes.
-  /// If we have excatly 2 "cfvo" and "color" childs, then we return "twoColorScale"
-  /// </summary>
-  /// <returns>TwoColorScale or ThreeColorScale</returns>
-  internal static eExcelConditionalFormattingRuleType GetColorScaleType(
-      XmlNode topNode,
-      XmlNamespaceManager nameSpaceManager) {
-    // Get the <cfvo> nodes
-    var cfvoNodes = topNode.SelectNodes(
-        string.Format(
-            "{0}/{1}",
-            ExcelConditionalFormattingConstants.Paths._colorScale,
-            ExcelConditionalFormattingConstants.Paths._cfvo),
-        nameSpaceManager);
-
-    // Get the <color> nodes
-    var colorNodes = topNode.SelectNodes(
-        string.Format(
-            "{0}/{1}",
-            ExcelConditionalFormattingConstants.Paths._colorScale,
-            ExcelConditionalFormattingConstants.Paths._color),
-        nameSpaceManager);
-
-    // We determine if it is "TwoColorScale" or "ThreeColorScale" by the
-    // number of <cfvo> and <color> inside the <colorScale> node
-    if ((cfvoNodes == null)
-        || (cfvoNodes.Count < 2)
-        || (cfvoNodes.Count > 3)
-        || (colorNodes == null)
-        || (colorNodes.Count < 2)
-        || (colorNodes.Count > 3)
-        || (cfvoNodes.Count != colorNodes.Count)) {
-      throw new(ExcelConditionalFormattingConstants.Errors._wrongNumberCfvoColorNodes);
-    }
-
-    // Return the corresponding rule type (TwoColorScale or ThreeColorScale)
-    return (cfvoNodes.Count == 2)
-        ? eExcelConditionalFormattingRuleType.TwoColorScale
-        : eExcelConditionalFormattingRuleType.ThreeColorScale;
-  }
-
-  /// <summary>
-  /// Get the "aboveAverage" rule type according to the follwoing attributes:
-  /// "AboveAverage", "EqualAverage" and "StdDev".
-  ///
-  /// @StdDev greater than "0"                              == AboveStdDev
-  /// @StdDev less than "0"                                 == BelowStdDev
-  /// @AboveAverage = "1"/null and @EqualAverage = "0"/null == AboveAverage
-  /// @AboveAverage = "1"/null and @EqualAverage = "1"      == AboveOrEqualAverage
-  /// @AboveAverage = "0" and @EqualAverage = "0"/null      == BelowAverage
-  /// @AboveAverage = "0" and @EqualAverage = "1"           == BelowOrEqualAverage
-  /// /// </summary>
-  /// <returns>AboveAverage, AboveOrEqualAverage, BelowAverage or BelowOrEqualAverage</returns>
-  internal static eExcelConditionalFormattingRuleType GetAboveAverageType(
-      XmlNode topNode,
-      XmlNamespaceManager nameSpaceManager) {
-    // Get @StdDev attribute
-    int? stdDev = ExcelConditionalFormattingHelper.GetAttributeIntNullable(
-        topNode,
-        ExcelConditionalFormattingConstants.Attributes._stdDev);
-
-    if (stdDev > 0) {
-      // @StdDev > "0" --> AboveStdDev
-      return eExcelConditionalFormattingRuleType.AboveStdDev;
-    }
-
-    if (stdDev < 0) {
-      // @StdDev < "0" --> BelowStdDev
-      return eExcelConditionalFormattingRuleType.BelowStdDev;
-    }
-
-    // Get @AboveAverage attribute
-    bool? isAboveAverage = ExcelConditionalFormattingHelper.GetAttributeBoolNullable(
-        topNode,
-        ExcelConditionalFormattingConstants.Attributes._aboveAverage);
-
-    // Get @EqualAverage attribute
-    bool? isEqualAverage = ExcelConditionalFormattingHelper.GetAttributeBoolNullable(
-        topNode,
-        ExcelConditionalFormattingConstants.Attributes._equalAverage);
-
-    if ((isAboveAverage == null) || (isAboveAverage == true)) {
-      if (isEqualAverage == true) {
-        // @AboveAverage = "1"/null and @EqualAverage = "1" == AboveOrEqualAverage
-        return eExcelConditionalFormattingRuleType.AboveOrEqualAverage;
-      }
-
-      // @AboveAverage = "1"/null and @EqualAverage = "0"/null == AboveAverage
-      return eExcelConditionalFormattingRuleType.AboveAverage;
-    }
-
-    if (isEqualAverage == true) {
-      // @AboveAverage = "0" and @EqualAverage = "1" == BelowOrEqualAverage
-      return eExcelConditionalFormattingRuleType.BelowOrEqualAverage;
-    }
-
-    // @AboveAverage = "0" and @EqualAverage = "0"/null == BelowAverage
-    return eExcelConditionalFormattingRuleType.BelowAverage;
-  }
-
-  /// <summary>
-  /// Get the "top10" rule type according to the follwoing attributes:
-  /// "Bottom" and "Percent"
-  ///
-  /// @Bottom = "1" and @Percent = "0"/null       == Bottom
-  /// @Bottom = "1" and @Percent = "1"            == BottomPercent
-  /// @Bottom = "0"/null and @Percent = "0"/null  == Top
-  /// @Bottom = "0"/null and @Percent = "1"       == TopPercent
-  /// /// </summary>
-  /// <returns>Top, TopPercent, Bottom or BottomPercent</returns>
-  public static eExcelConditionalFormattingRuleType GetTop10Type(
-      XmlNode topNode,
-      XmlNamespaceManager nameSpaceManager) {
-    // Get @Bottom attribute
-    bool? isBottom = ExcelConditionalFormattingHelper.GetAttributeBoolNullable(
-        topNode,
-        ExcelConditionalFormattingConstants.Attributes._bottom);
-
-    // Get @Percent attribute
-    bool? isPercent = ExcelConditionalFormattingHelper.GetAttributeBoolNullable(
-        topNode,
-        ExcelConditionalFormattingConstants.Attributes._percent);
-
-    if (isBottom == true) {
-      if (isPercent == true) {
-        // @Bottom = "1" and @Percent = "1" == BottomPercent
-        return eExcelConditionalFormattingRuleType.BottomPercent;
-      }
-
-      // @Bottom = "1" and @Percent = "0"/null == Bottom
-      return eExcelConditionalFormattingRuleType.Bottom;
-    }
-
-    if (isPercent == true) {
-      // @Bottom = "0"/null and @Percent = "1" == TopPercent
-      return eExcelConditionalFormattingRuleType.TopPercent;
-    }
-
-    // @Bottom = "0"/null and @Percent = "0"/null == Top
-    return eExcelConditionalFormattingRuleType.Top;
-  }
-
-  /// <summary>
-  /// Get the "timePeriod" rule type according to "TimePeriod" attribute.
-  /// /// </summary>
-  /// <returns>Last7Days, LastMonth etc.</returns>
-  public static eExcelConditionalFormattingRuleType GetTimePeriodType(
-      XmlNode topNode,
-      XmlNamespaceManager nameSpaceManager) {
-    eExcelConditionalFormattingTimePeriodType timePeriod =
-        ExcelConditionalFormattingTimePeriodType.GetTypeByAttribute(
-            ExcelConditionalFormattingHelper.GetAttributeString(
-                topNode,
-                ExcelConditionalFormattingConstants.Attributes._timePeriod));
-
-    switch (timePeriod) {
-      case eExcelConditionalFormattingTimePeriodType.Last7Days:
-        return eExcelConditionalFormattingRuleType.Last7Days;
-
-      case eExcelConditionalFormattingTimePeriodType.LastMonth:
-        return eExcelConditionalFormattingRuleType.LastMonth;
-
-      case eExcelConditionalFormattingTimePeriodType.LastWeek:
-        return eExcelConditionalFormattingRuleType.LastWeek;
-
-      case eExcelConditionalFormattingTimePeriodType.NextMonth:
-        return eExcelConditionalFormattingRuleType.NextMonth;
-
-      case eExcelConditionalFormattingTimePeriodType.NextWeek:
-        return eExcelConditionalFormattingRuleType.NextWeek;
-
-      case eExcelConditionalFormattingTimePeriodType.ThisMonth:
-        return eExcelConditionalFormattingRuleType.ThisMonth;
-
-      case eExcelConditionalFormattingTimePeriodType.ThisWeek:
-        return eExcelConditionalFormattingRuleType.ThisWeek;
-
-      case eExcelConditionalFormattingTimePeriodType.Today:
-        return eExcelConditionalFormattingRuleType.Today;
-
-      case eExcelConditionalFormattingTimePeriodType.Tomorrow:
-        return eExcelConditionalFormattingRuleType.Tomorrow;
-
-      case eExcelConditionalFormattingTimePeriodType.Yesterday:
-        return eExcelConditionalFormattingRuleType.Yesterday;
-    }
-
-    throw new(ExcelConditionalFormattingConstants.Errors._unexistentTimePeriodTypeAttribute);
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="type"></param>
-  /// <returns></returns>
-  public static string GetAttributeByType(eExcelConditionalFormattingRuleType type) {
-    switch (type) {
-      case eExcelConditionalFormattingRuleType.AboveAverage:
-      case eExcelConditionalFormattingRuleType.AboveOrEqualAverage:
-      case eExcelConditionalFormattingRuleType.BelowAverage:
-      case eExcelConditionalFormattingRuleType.BelowOrEqualAverage:
-      case eExcelConditionalFormattingRuleType.AboveStdDev:
-      case eExcelConditionalFormattingRuleType.BelowStdDev:
-        return ExcelConditionalFormattingConstants.RuleType._aboveAverage;
-
-      case eExcelConditionalFormattingRuleType.Bottom:
-      case eExcelConditionalFormattingRuleType.BottomPercent:
-      case eExcelConditionalFormattingRuleType.Top:
-      case eExcelConditionalFormattingRuleType.TopPercent:
-        return ExcelConditionalFormattingConstants.RuleType._top10;
-
-      case eExcelConditionalFormattingRuleType.Last7Days:
-      case eExcelConditionalFormattingRuleType.LastMonth:
-      case eExcelConditionalFormattingRuleType.LastWeek:
-      case eExcelConditionalFormattingRuleType.NextMonth:
-      case eExcelConditionalFormattingRuleType.NextWeek:
-      case eExcelConditionalFormattingRuleType.ThisMonth:
-      case eExcelConditionalFormattingRuleType.ThisWeek:
-      case eExcelConditionalFormattingRuleType.Today:
-      case eExcelConditionalFormattingRuleType.Tomorrow:
-      case eExcelConditionalFormattingRuleType.Yesterday:
-        return ExcelConditionalFormattingConstants.RuleType._timePeriod;
-
-      case eExcelConditionalFormattingRuleType.Between:
-      case eExcelConditionalFormattingRuleType.Equal:
-      case eExcelConditionalFormattingRuleType.GreaterThan:
-      case eExcelConditionalFormattingRuleType.GreaterThanOrEqual:
-      case eExcelConditionalFormattingRuleType.LessThan:
-      case eExcelConditionalFormattingRuleType.LessThanOrEqual:
-      case eExcelConditionalFormattingRuleType.NotBetween:
-      case eExcelConditionalFormattingRuleType.NotEqual:
-        return ExcelConditionalFormattingConstants.RuleType._cellIs;
-
-      case eExcelConditionalFormattingRuleType.ThreeIconSet:
-      case eExcelConditionalFormattingRuleType.FourIconSet:
-      case eExcelConditionalFormattingRuleType.FiveIconSet:
-        return ExcelConditionalFormattingConstants.RuleType._iconSet;
-
-      case eExcelConditionalFormattingRuleType.ThreeColorScale:
-      case eExcelConditionalFormattingRuleType.TwoColorScale:
-        return ExcelConditionalFormattingConstants.RuleType._colorScale;
-
-      case eExcelConditionalFormattingRuleType.BeginsWith:
-        return ExcelConditionalFormattingConstants.RuleType._beginsWith;
-
-      case eExcelConditionalFormattingRuleType.ContainsBlanks:
-        return ExcelConditionalFormattingConstants.RuleType._containsBlanks;
-
-      case eExcelConditionalFormattingRuleType.ContainsErrors:
-        return ExcelConditionalFormattingConstants.RuleType._containsErrors;
-
-      case eExcelConditionalFormattingRuleType.ContainsText:
-        return ExcelConditionalFormattingConstants.RuleType._containsText;
-
-      case eExcelConditionalFormattingRuleType.DuplicateValues:
-        return ExcelConditionalFormattingConstants.RuleType._duplicateValues;
-
-      case eExcelConditionalFormattingRuleType.EndsWith:
-        return ExcelConditionalFormattingConstants.RuleType._endsWith;
-
-      case eExcelConditionalFormattingRuleType.Expression:
-        return ExcelConditionalFormattingConstants.RuleType._expression;
-
-      case eExcelConditionalFormattingRuleType.NotContainsBlanks:
-        return ExcelConditionalFormattingConstants.RuleType._notContainsBlanks;
-
-      case eExcelConditionalFormattingRuleType.NotContainsErrors:
-        return ExcelConditionalFormattingConstants.RuleType._notContainsErrors;
-
-      case eExcelConditionalFormattingRuleType.NotContainsText:
-        return ExcelConditionalFormattingConstants.RuleType._notContainsText;
-
-      case eExcelConditionalFormattingRuleType.UniqueValues:
-        return ExcelConditionalFormattingConstants.RuleType._uniqueValues;
-
-      case eExcelConditionalFormattingRuleType.DataBar:
-        return ExcelConditionalFormattingConstants.RuleType._dataBar;
-    }
-
-    throw new(ExcelConditionalFormattingConstants.Errors._missingRuleType);
-  }
-
-  /// <summary>
-  /// Return cfvo §18.3.1.11 parent according to the rule type
-  /// </summary>
-  /// <param name="type"></param>
-  /// <returns></returns>
-  public static string GetCfvoParentPathByType(eExcelConditionalFormattingRuleType type) {
-    switch (type) {
-      case eExcelConditionalFormattingRuleType.TwoColorScale:
-      case eExcelConditionalFormattingRuleType.ThreeColorScale:
-        return ExcelConditionalFormattingConstants.Paths._colorScale;
-
-      case eExcelConditionalFormattingRuleType.ThreeIconSet:
-      case eExcelConditionalFormattingRuleType.FourIconSet:
-      case eExcelConditionalFormattingRuleType.FiveIconSet:
-        return ExcelConditionalFormattingConstants.RuleType._iconSet;
-
-      case eExcelConditionalFormattingRuleType.DataBar:
-        return ExcelConditionalFormattingConstants.RuleType._dataBar;
-    }
-
-    throw new(ExcelConditionalFormattingConstants.Errors._missingRuleType);
-  }
-}
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingTimePeriodType.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingTimePeriodType.cs
deleted file mode 100644
index c93a82d..0000000
--- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingTimePeriodType.cs
+++ /dev/null
@@ -1,119 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-17
- *******************************************************************************/
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// Functions related to the <see cref="ExcelConditionalFormattingTimePeriodType"/>
-/// </summary>
-internal static class ExcelConditionalFormattingTimePeriodType {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="type"></param>
-  /// <returns></returns>
-  public static string GetAttributeByType(eExcelConditionalFormattingTimePeriodType type) {
-    switch (type) {
-      case eExcelConditionalFormattingTimePeriodType.Last7Days:
-        return ExcelConditionalFormattingConstants.TimePeriods._last7Days;
-
-      case eExcelConditionalFormattingTimePeriodType.LastMonth:
-        return ExcelConditionalFormattingConstants.TimePeriods._lastMonth;
-
-      case eExcelConditionalFormattingTimePeriodType.LastWeek:
-        return ExcelConditionalFormattingConstants.TimePeriods._lastWeek;
-
-      case eExcelConditionalFormattingTimePeriodType.NextMonth:
-        return ExcelConditionalFormattingConstants.TimePeriods._nextMonth;
-
-      case eExcelConditionalFormattingTimePeriodType.NextWeek:
-        return ExcelConditionalFormattingConstants.TimePeriods._nextWeek;
-
-      case eExcelConditionalFormattingTimePeriodType.ThisMonth:
-        return ExcelConditionalFormattingConstants.TimePeriods._thisMonth;
-
-      case eExcelConditionalFormattingTimePeriodType.ThisWeek:
-        return ExcelConditionalFormattingConstants.TimePeriods._thisWeek;
-
-      case eExcelConditionalFormattingTimePeriodType.Today:
-        return ExcelConditionalFormattingConstants.TimePeriods._today;
-
-      case eExcelConditionalFormattingTimePeriodType.Tomorrow:
-        return ExcelConditionalFormattingConstants.TimePeriods._tomorrow;
-
-      case eExcelConditionalFormattingTimePeriodType.Yesterday:
-        return ExcelConditionalFormattingConstants.TimePeriods._yesterday;
-    }
-
-    return string.Empty;
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="attribute"></param>
-  /// <returns></returns>
-  public static eExcelConditionalFormattingTimePeriodType GetTypeByAttribute(string attribute) {
-    switch (attribute) {
-      case ExcelConditionalFormattingConstants.TimePeriods._last7Days:
-        return eExcelConditionalFormattingTimePeriodType.Last7Days;
-
-      case ExcelConditionalFormattingConstants.TimePeriods._lastMonth:
-        return eExcelConditionalFormattingTimePeriodType.LastMonth;
-
-      case ExcelConditionalFormattingConstants.TimePeriods._lastWeek:
-        return eExcelConditionalFormattingTimePeriodType.LastWeek;
-
-      case ExcelConditionalFormattingConstants.TimePeriods._nextMonth:
-        return eExcelConditionalFormattingTimePeriodType.NextMonth;
-
-      case ExcelConditionalFormattingConstants.TimePeriods._nextWeek:
-        return eExcelConditionalFormattingTimePeriodType.NextWeek;
-
-      case ExcelConditionalFormattingConstants.TimePeriods._thisMonth:
-        return eExcelConditionalFormattingTimePeriodType.ThisMonth;
-
-      case ExcelConditionalFormattingConstants.TimePeriods._thisWeek:
-        return eExcelConditionalFormattingTimePeriodType.ThisWeek;
-
-      case ExcelConditionalFormattingConstants.TimePeriods._today:
-        return eExcelConditionalFormattingTimePeriodType.Today;
-
-      case ExcelConditionalFormattingConstants.TimePeriods._tomorrow:
-        return eExcelConditionalFormattingTimePeriodType.Tomorrow;
-
-      case ExcelConditionalFormattingConstants.TimePeriods._yesterday:
-        return eExcelConditionalFormattingTimePeriodType.Yesterday;
-    }
-
-    throw new(ExcelConditionalFormattingConstants.Errors._unexistentTimePeriodTypeAttribute);
-  }
-}
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingValueObjectType.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingValueObjectType.cs
deleted file mode 100644
index 22d9356..0000000
--- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingValueObjectType.cs
+++ /dev/null
@@ -1,199 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author          Change						                  Date
- * ******************************************************************************
- * Eyal Seagull    Conditional Formatting Adaption    2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// Functions related to the <see cref="ExcelConditionalFormattingColorScaleValue"/>
-/// </summary>
-internal static class ExcelConditionalFormattingValueObjectType {
-  /// <summary>
-  /// Get the sequencial order of a cfvo/color by its position.
-  /// </summary>
-  /// <param name="position"></param>
-  /// <param name="ruleType"></param>
-  /// <returns>1, 2 or 3</returns>
-  internal static int GetOrderByPosition(
-      eExcelConditionalFormattingValueObjectPosition position,
-      eExcelConditionalFormattingRuleType ruleType) {
-    switch (position) {
-      case eExcelConditionalFormattingValueObjectPosition.Low:
-        return 1;
-
-      case eExcelConditionalFormattingValueObjectPosition.Middle:
-        return 2;
-
-      case eExcelConditionalFormattingValueObjectPosition.High:
-        // Check if the rule type is TwoColorScale.
-        if (ruleType == eExcelConditionalFormattingRuleType.TwoColorScale) {
-          // There are only "Low" and "High". So "High" is the second
-          return 2;
-        }
-
-        // There are "Low", "Middle" and "High". So "High" is the third
-        return 3;
-    }
-
-    return 0;
-  }
-
-  /// <summary>
-  /// Get the CFVO type by its @type attribute
-  /// </summary>
-  /// <param name="attribute"></param>
-  /// <returns></returns>
-  public static eExcelConditionalFormattingValueObjectType GetTypeByAttrbiute(string attribute) {
-    switch (attribute) {
-      case ExcelConditionalFormattingConstants.CfvoType._min:
-        return eExcelConditionalFormattingValueObjectType.Min;
-
-      case ExcelConditionalFormattingConstants.CfvoType._max:
-        return eExcelConditionalFormattingValueObjectType.Max;
-
-      case ExcelConditionalFormattingConstants.CfvoType._num:
-        return eExcelConditionalFormattingValueObjectType.Num;
-
-      case ExcelConditionalFormattingConstants.CfvoType._formula:
-        return eExcelConditionalFormattingValueObjectType.Formula;
-
-      case ExcelConditionalFormattingConstants.CfvoType._percent:
-        return eExcelConditionalFormattingValueObjectType.Percent;
-
-      case ExcelConditionalFormattingConstants.CfvoType._percentile:
-        return eExcelConditionalFormattingValueObjectType.Percentile;
-    }
-
-    throw new(ExcelConditionalFormattingConstants.Errors._unexistentCfvoTypeAttribute);
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="position"></param>
-  ///<param name="ruleType"></param>
-  /// <param name="topNode"></param>
-  /// <param name="nameSpaceManager"></param>
-  /// <returns></returns>
-  public static XmlNode GetCfvoNodeByPosition(
-      eExcelConditionalFormattingValueObjectPosition position,
-      eExcelConditionalFormattingRuleType ruleType,
-      XmlNode topNode,
-      XmlNamespaceManager nameSpaceManager) {
-    // Get the corresponding <cfvo> node (by the position)
-    var node = topNode.SelectSingleNode(
-        string.Format(
-            "{0}[position()={1}]",
-            // {0}
-            ExcelConditionalFormattingConstants.Paths._cfvo,
-            // {1}
-            GetOrderByPosition(position, ruleType)),
-        nameSpaceManager);
-
-    if (node == null) {
-      throw new(ExcelConditionalFormattingConstants.Errors._missingCfvoNode);
-    }
-
-    return node;
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="type"></param>
-  /// <returns></returns>
-  public static string GetAttributeByType(eExcelConditionalFormattingValueObjectType type) {
-    switch (type) {
-      case eExcelConditionalFormattingValueObjectType.Min:
-        return ExcelConditionalFormattingConstants.CfvoType._min;
-
-      case eExcelConditionalFormattingValueObjectType.Max:
-        return ExcelConditionalFormattingConstants.CfvoType._max;
-
-      case eExcelConditionalFormattingValueObjectType.Num:
-        return ExcelConditionalFormattingConstants.CfvoType._num;
-
-      case eExcelConditionalFormattingValueObjectType.Formula:
-        return ExcelConditionalFormattingConstants.CfvoType._formula;
-
-      case eExcelConditionalFormattingValueObjectType.Percent:
-        return ExcelConditionalFormattingConstants.CfvoType._percent;
-
-      case eExcelConditionalFormattingValueObjectType.Percentile:
-        return ExcelConditionalFormattingConstants.CfvoType._percentile;
-    }
-
-    return string.Empty;
-  }
-
-  /// <summary>
-  /// Get the cfvo (§18.3.1.11) node parent by the rule type. Can be any of the following:
-  /// "colorScale" (§18.3.1.16); "dataBar" (§18.3.1.28); "iconSet" (§18.3.1.49)
-  /// </summary>
-  /// <param name="ruleType"></param>
-  /// <returns></returns>
-  public static string GetParentPathByRuleType(eExcelConditionalFormattingRuleType ruleType) {
-    switch (ruleType) {
-      case eExcelConditionalFormattingRuleType.TwoColorScale:
-      case eExcelConditionalFormattingRuleType.ThreeColorScale:
-        return ExcelConditionalFormattingConstants.Paths._colorScale;
-
-      case eExcelConditionalFormattingRuleType.ThreeIconSet:
-      case eExcelConditionalFormattingRuleType.FourIconSet:
-      case eExcelConditionalFormattingRuleType.FiveIconSet:
-        return ExcelConditionalFormattingConstants.Paths._iconSet;
-
-      case eExcelConditionalFormattingRuleType.DataBar:
-        return ExcelConditionalFormattingConstants.Paths._dataBar;
-    }
-
-    return string.Empty;
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="nodeType"></param>
-  /// <returns></returns>
-  public static string GetNodePathByNodeType(
-      eExcelConditionalFormattingValueObjectNodeType nodeType) {
-    switch (nodeType) {
-      case eExcelConditionalFormattingValueObjectNodeType.Cfvo:
-        return ExcelConditionalFormattingConstants.Paths._cfvo;
-
-      case eExcelConditionalFormattingValueObjectNodeType.Color:
-        return ExcelConditionalFormattingConstants.Paths._color;
-    }
-
-    return string.Empty;
-  }
-}
diff --git a/EPPlus/ConditionalFormatting/RangeConditionalFormatting.cs b/EPPlus/ConditionalFormatting/RangeConditionalFormatting.cs
deleted file mode 100644
index 6fcc305..0000000
--- a/EPPlus/ConditionalFormatting/RangeConditionalFormatting.cs
+++ /dev/null
@@ -1,380 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author             Change                    Date
- * ******************************************************************************
- * Eyal Seagull       Conditional Formatting    2012-04-03
- *******************************************************************************/
-
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-internal class RangeConditionalFormatting : IRangeConditionalFormatting {
-  public ExcelWorksheet _worksheet;
-  public ExcelAddress _address;
-
-  public RangeConditionalFormatting(ExcelWorksheet worksheet, ExcelAddress address) {
-    Require.Argument(worksheet).IsNotNull("worksheet");
-    Require.Argument(address).IsNotNull("address");
-
-    _worksheet = worksheet;
-    _address = address;
-  }
-
-  /// <summary>
-  /// Add AboveOrEqualAverage Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingAverageGroup AddAboveAverage() {
-    return _worksheet.ConditionalFormatting.AddAboveAverage(_address);
-  }
-
-  /// <summary>
-  /// Add AboveOrEqualAverage Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingAverageGroup AddAboveOrEqualAverage() {
-    return _worksheet.ConditionalFormatting.AddAboveOrEqualAverage(_address);
-  }
-
-  /// <summary>
-  /// Add BelowOrEqualAverage Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingAverageGroup AddBelowAverage() {
-    return _worksheet.ConditionalFormatting.AddBelowAverage(_address);
-  }
-
-  /// <summary>
-  /// Add BelowOrEqualAverage Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingAverageGroup AddBelowOrEqualAverage() {
-    return _worksheet.ConditionalFormatting.AddBelowOrEqualAverage(_address);
-  }
-
-  /// <summary>
-  /// Add AboveStdDev Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingStdDevGroup AddAboveStdDev() {
-    return _worksheet.ConditionalFormatting.AddAboveStdDev(_address);
-  }
-
-  /// <summary>
-  /// Add BelowStdDev Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingStdDevGroup AddBelowStdDev() {
-    return _worksheet.ConditionalFormatting.AddBelowStdDev(_address);
-  }
-
-  /// <summary>
-  /// Add Bottom Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingTopBottomGroup AddBottom() {
-    return _worksheet.ConditionalFormatting.AddBottom(_address);
-  }
-
-  /// <summary>
-  /// Add BottomPercent Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingTopBottomGroup AddBottomPercent() {
-    return _worksheet.ConditionalFormatting.AddBottomPercent(_address);
-  }
-
-  /// <summary>
-  /// Add Top Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingTopBottomGroup AddTop() {
-    return _worksheet.ConditionalFormatting.AddTop(_address);
-  }
-
-  /// <summary>
-  /// Add TopPercent Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingTopBottomGroup AddTopPercent() {
-    return _worksheet.ConditionalFormatting.AddTopPercent(_address);
-  }
-
-  /// <summary>
-  /// Add Last7Days Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingTimePeriodGroup AddLast7Days() {
-    return _worksheet.ConditionalFormatting.AddLast7Days(_address);
-  }
-
-  /// <summary>
-  /// Add LastMonth Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingTimePeriodGroup AddLastMonth() {
-    return _worksheet.ConditionalFormatting.AddLastMonth(_address);
-  }
-
-  /// <summary>
-  /// Add LastWeek Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingTimePeriodGroup AddLastWeek() {
-    return _worksheet.ConditionalFormatting.AddLastWeek(_address);
-  }
-
-  /// <summary>
-  /// Add NextMonth Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingTimePeriodGroup AddNextMonth() {
-    return _worksheet.ConditionalFormatting.AddNextMonth(_address);
-  }
-
-  /// <summary>
-  /// Add NextWeek Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingTimePeriodGroup AddNextWeek() {
-    return _worksheet.ConditionalFormatting.AddNextWeek(_address);
-  }
-
-  /// <summary>
-  /// Add ThisMonth Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingTimePeriodGroup AddThisMonth() {
-    return _worksheet.ConditionalFormatting.AddThisMonth(_address);
-  }
-
-  /// <summary>
-  /// Add ThisWeek Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingTimePeriodGroup AddThisWeek() {
-    return _worksheet.ConditionalFormatting.AddThisWeek(_address);
-  }
-
-  /// <summary>
-  /// Add Today Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingTimePeriodGroup AddToday() {
-    return _worksheet.ConditionalFormatting.AddToday(_address);
-  }
-
-  /// <summary>
-  /// Add Tomorrow Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingTimePeriodGroup AddTomorrow() {
-    return _worksheet.ConditionalFormatting.AddTomorrow(_address);
-  }
-
-  /// <summary>
-  /// Add Yesterday Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingTimePeriodGroup AddYesterday() {
-    return _worksheet.ConditionalFormatting.AddYesterday(_address);
-  }
-
-  /// <summary>
-  /// Add BeginsWith Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingBeginsWith AddBeginsWith() {
-    return _worksheet.ConditionalFormatting.AddBeginsWith(_address);
-  }
-
-  /// <summary>
-  /// Add Between Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingBetween AddBetween() {
-    return _worksheet.ConditionalFormatting.AddBetween(_address);
-  }
-
-  /// <summary>
-  /// Add ContainsBlanks Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingContainsBlanks AddContainsBlanks() {
-    return _worksheet.ConditionalFormatting.AddContainsBlanks(_address);
-  }
-
-  /// <summary>
-  /// Add ContainsErrors Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingContainsErrors AddContainsErrors() {
-    return _worksheet.ConditionalFormatting.AddContainsErrors(_address);
-  }
-
-  /// <summary>
-  /// Add ContainsText Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingContainsText AddContainsText() {
-    return _worksheet.ConditionalFormatting.AddContainsText(_address);
-  }
-
-  /// <summary>
-  /// Add DuplicateValues Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingDuplicateValues AddDuplicateValues() {
-    return _worksheet.ConditionalFormatting.AddDuplicateValues(_address);
-  }
-
-  /// <summary>
-  /// Add EndsWith Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingEndsWith AddEndsWith() {
-    return _worksheet.ConditionalFormatting.AddEndsWith(_address);
-  }
-
-  /// <summary>
-  /// Add Equal Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingEqual AddEqual() {
-    return _worksheet.ConditionalFormatting.AddEqual(_address);
-  }
-
-  /// <summary>
-  /// Add Expression Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingExpression AddExpression() {
-    return _worksheet.ConditionalFormatting.AddExpression(_address);
-  }
-
-  /// <summary>
-  /// Add GreaterThan Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingGreaterThan AddGreaterThan() {
-    return _worksheet.ConditionalFormatting.AddGreaterThan(_address);
-  }
-
-  /// <summary>
-  /// Add GreaterThanOrEqual Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingGreaterThanOrEqual AddGreaterThanOrEqual() {
-    return _worksheet.ConditionalFormatting.AddGreaterThanOrEqual(_address);
-  }
-
-  /// <summary>
-  /// Add LessThan Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingLessThan AddLessThan() {
-    return _worksheet.ConditionalFormatting.AddLessThan(_address);
-  }
-
-  /// <summary>
-  /// Add LessThanOrEqual Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingLessThanOrEqual AddLessThanOrEqual() {
-    return _worksheet.ConditionalFormatting.AddLessThanOrEqual(_address);
-  }
-
-  /// <summary>
-  /// Add NotBetween Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingNotBetween AddNotBetween() {
-    return _worksheet.ConditionalFormatting.AddNotBetween(_address);
-  }
-
-  /// <summary>
-  /// Add NotContainsBlanks Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingNotContainsBlanks AddNotContainsBlanks() {
-    return _worksheet.ConditionalFormatting.AddNotContainsBlanks(_address);
-  }
-
-  /// <summary>
-  /// Add NotContainsErrors Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingNotContainsErrors AddNotContainsErrors() {
-    return _worksheet.ConditionalFormatting.AddNotContainsErrors(_address);
-  }
-
-  /// <summary>
-  /// Add NotContainsText Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingNotContainsText AddNotContainsText() {
-    return _worksheet.ConditionalFormatting.AddNotContainsText(_address);
-  }
-
-  /// <summary>
-  /// Add NotEqual Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingNotEqual AddNotEqual() {
-    return _worksheet.ConditionalFormatting.AddNotEqual(_address);
-  }
-
-  /// <summary>
-  /// Add UniqueValues Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingUniqueValues AddUniqueValues() {
-    return _worksheet.ConditionalFormatting.AddUniqueValues(_address);
-  }
-
-  /// <summary>
-  /// Add ThreeColorScale Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingThreeColorScale AddThreeColorScale() {
-    return (IExcelConditionalFormattingThreeColorScale)(_worksheet.ConditionalFormatting.AddRule(
-        eExcelConditionalFormattingRuleType.ThreeColorScale,
-        _address));
-  }
-
-  /// <summary>
-  /// Add TwoColorScale Conditional Formatting
-  /// </summary>
-  ///  <returns></returns>
-  public IExcelConditionalFormattingTwoColorScale AddTwoColorScale() {
-    return (IExcelConditionalFormattingTwoColorScale)(_worksheet.ConditionalFormatting.AddRule(
-        eExcelConditionalFormattingRuleType.TwoColorScale,
-        _address));
-  }
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveAverage.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveAverage.cs
deleted file mode 100644
index cf90b06..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveAverage.cs
+++ /dev/null
@@ -1,94 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingAboveAverage
-/// </summary>
-public class ExcelConditionalFormattingAboveAverage : ExcelConditionalFormattingAverageGroup {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingAboveAverage(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.AboveAverage,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      AboveAverage = true;
-      EqualAverage = false;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingAboveAverage(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingAboveAverage(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveOrEqualAverage.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveOrEqualAverage.cs
deleted file mode 100644
index dcbf944..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveOrEqualAverage.cs
+++ /dev/null
@@ -1,95 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingAboveOrEqualAverage
-/// </summary>
-public class ExcelConditionalFormattingAboveOrEqualAverage
-    : ExcelConditionalFormattingAverageGroup {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingAboveOrEqualAverage(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.AboveOrEqualAverage,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      AboveAverage = true;
-      EqualAverage = true;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingAboveOrEqualAverage(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingAboveOrEqualAverage(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveStdDev.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveStdDev.cs
deleted file mode 100644
index bd905e1..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveStdDev.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingAboveStdDev
-/// </summary>
-public class ExcelConditionalFormattingAboveStdDev
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingStdDevGroup {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingAboveStdDev(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.AboveStdDev,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      AboveAverage = true;
-      StdDev = 1;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingAboveStdDev(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingAboveStdDev(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAverageGroup.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAverageGroup.cs
deleted file mode 100644
index 34076ba..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAverageGroup.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingAverageGroup
-/// </summary>
-public class ExcelConditionalFormattingAverageGroup
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingAverageGroup {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="type"></param>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingAverageGroup(
-      eExcelConditionalFormattingRuleType type,
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          type,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  ///<param name="type"></param>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingAverageGroup(
-      eExcelConditionalFormattingRuleType type,
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(type, address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  ///<param name="type"></param>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingAverageGroup(
-      eExcelConditionalFormattingRuleType type,
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(type, address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBeginsWith.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBeginsWith.cs
deleted file mode 100644
index d8cdd26..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBeginsWith.cs
+++ /dev/null
@@ -1,112 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingBeginsWith
-/// </summary>
-public class ExcelConditionalFormattingBeginsWith
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingBeginsWith {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingBeginsWith(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.BeginsWith,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      Operator = eExcelConditionalFormattingOperatorType.BeginsWith;
-      Text = string.Empty;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingBeginsWith(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingBeginsWith(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-
-  /// <summary>
-  /// The text to search in the beginning of the cell
-  /// </summary>
-  public string Text {
-    get => GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._textAttribute);
-    set {
-      SetXmlNodeString(ExcelConditionalFormattingConstants.Paths._textAttribute, value);
-
-      Formula = string.Format(
-          "LEFT({0},LEN(\"{1}\"))=\"{1}\"",
-          Address.Start.Address,
-          value.Replace("\"", "\"\""));
-    }
-  }
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowAverage.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowAverage.cs
deleted file mode 100644
index ef68fc1..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowAverage.cs
+++ /dev/null
@@ -1,94 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingBelowAverage
-/// </summary>
-public class ExcelConditionalFormattingBelowAverage : ExcelConditionalFormattingAverageGroup {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingBelowAverage(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.BelowAverage,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      AboveAverage = false;
-      EqualAverage = false;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingBelowAverage(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingBelowAverage(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowOrEqualAverage.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowOrEqualAverage.cs
deleted file mode 100644
index 4d8cd67..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowOrEqualAverage.cs
+++ /dev/null
@@ -1,95 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingBelowOrEqualAverage
-/// </summary>
-public class ExcelConditionalFormattingBelowOrEqualAverage
-    : ExcelConditionalFormattingAverageGroup {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingBelowOrEqualAverage(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.BelowOrEqualAverage,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      AboveAverage = false;
-      EqualAverage = true;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingBelowOrEqualAverage(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingBelowOrEqualAverage(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowStdDev.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowStdDev.cs
deleted file mode 100644
index 8291319..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowStdDev.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingBelowStdDev
-/// </summary>
-public class ExcelConditionalFormattingBelowStdDev
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingStdDevGroup {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingBelowStdDev(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.BelowStdDev,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      AboveAverage = false;
-      StdDev = 1;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingBelowStdDev(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingBelowStdDev(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBetween.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBetween.cs
deleted file mode 100644
index fb1bb73..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBetween.cs
+++ /dev/null
@@ -1,98 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingBetween
-/// </summary>
-public class ExcelConditionalFormattingBetween
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingBetween {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingBetween(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.Between,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      Operator = eExcelConditionalFormattingOperatorType.Between;
-      Formula = string.Empty;
-      Formula2 = string.Empty;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingBetween(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingBetween(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBottom.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBottom.cs
deleted file mode 100644
index ae9e861..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBottom.cs
+++ /dev/null
@@ -1,98 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingBottom
-/// </summary>
-public class ExcelConditionalFormattingBottom
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingTopBottomGroup {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingBottom(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.Bottom,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      Bottom = true;
-      Percent = false;
-      Rank = 10; // Last 10 values
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingBottom(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingBottom(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBottomPercent.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBottomPercent.cs
deleted file mode 100644
index 719901f..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBottomPercent.cs
+++ /dev/null
@@ -1,98 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingBottomPercent
-/// </summary>
-public class ExcelConditionalFormattingBottomPercent
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingTopBottomGroup {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingBottomPercent(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.BottomPercent,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      Bottom = true;
-      Percent = true;
-      Rank = 10; // Last 10 percent
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingBottomPercent(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingBottomPercent(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsBlanks.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsBlanks.cs
deleted file mode 100644
index d5eafe0..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsBlanks.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingContainsBlanks
-/// </summary>
-public class ExcelConditionalFormattingContainsBlanks
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingContainsBlanks {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingContainsBlanks(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.ContainsBlanks,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      Formula = string.Format("LEN(TRIM({0}))=0", Address.Start.Address);
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingContainsBlanks(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingContainsBlanks(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsErrors.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsErrors.cs
deleted file mode 100644
index f5d65f9..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsErrors.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingContainsErrors
-/// </summary>
-public class ExcelConditionalFormattingContainsErrors
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingContainsErrors {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingContainsErrors(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.ContainsErrors,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      Formula = string.Format("ISERROR({0})", Address.Start.Address);
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingContainsErrors(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingContainsErrors(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsText.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsText.cs
deleted file mode 100644
index ed433cc..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsText.cs
+++ /dev/null
@@ -1,112 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingContainsText
-/// </summary>
-public class ExcelConditionalFormattingContainsText
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingContainsText {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingContainsText(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.ContainsText,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      Operator = eExcelConditionalFormattingOperatorType.ContainsText;
-      Text = string.Empty;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingContainsText(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingContainsText(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-
-  /// <summary>
-  /// The text to search inside the cell
-  /// </summary>
-  public string Text {
-    get => GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._textAttribute);
-    set {
-      SetXmlNodeString(ExcelConditionalFormattingConstants.Paths._textAttribute, value);
-
-      Formula = string.Format(
-          "NOT(ISERROR(SEARCH(\"{1}\",{0})))",
-          Address.Start.Address,
-          value.Replace("\"", "\"\""));
-    }
-  }
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingDataBar.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingDataBar.cs
deleted file mode 100644
index 6c37773..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingDataBar.cs
+++ /dev/null
@@ -1,156 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Collections.Immutable;
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// Databar
-/// </summary>
-public class ExcelConditionalFormattingDataBar
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingDataBarGroup {
-  protected override ImmutableArray<string> SchemaNodeOrder { get; } = ["cfvo", "color"];
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="type"></param>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingDataBar(
-      eExcelConditionalFormattingRuleType type,
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          type,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    //Create the <dataBar> node inside the <cfRule> node
-    if (itemElementNode != null && itemElementNode.HasChildNodes) {
-      bool high = false;
-      foreach (XmlNode node in itemElementNode.SelectNodes("d:dataBar/d:cfvo", NameSpaceManager)) {
-        if (high == false) {
-          LowValue = new(type, address, worksheet, node, namespaceManager);
-          high = true;
-        } else {
-          HighValue = new(type, address, worksheet, node, namespaceManager);
-        }
-      }
-    } else {
-      var iconSetNode = CreateComplexNode(Node, ExcelConditionalFormattingConstants.Paths._dataBar);
-
-      var lowNode = iconSetNode.OwnerDocument.CreateElement(
-          ExcelConditionalFormattingConstants.Paths._cfvo,
-          ExcelPackage._schemaMain);
-      iconSetNode.AppendChild(lowNode);
-      LowValue = new(
-          eExcelConditionalFormattingValueObjectType.Min,
-          0,
-          "",
-          eExcelConditionalFormattingRuleType.DataBar,
-          address,
-          priority,
-          worksheet,
-          lowNode,
-          namespaceManager);
-
-      var highNode = iconSetNode.OwnerDocument.CreateElement(
-          ExcelConditionalFormattingConstants.Paths._cfvo,
-          ExcelPackage._schemaMain);
-      iconSetNode.AppendChild(highNode);
-      HighValue = new(
-          eExcelConditionalFormattingValueObjectType.Max,
-          0,
-          "",
-          eExcelConditionalFormattingRuleType.DataBar,
-          address,
-          priority,
-          worksheet,
-          highNode,
-          namespaceManager);
-    }
-    Type = type;
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="type"></param>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingDataBar(
-      eExcelConditionalFormattingRuleType type,
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(type, address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="type"></param>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingDataBar(
-      eExcelConditionalFormattingRuleType type,
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(type, address, priority, worksheet, null, null) {}
-
-  private const string _showValuePath = "d:dataBar/@showValue";
-
-  public bool ShowValue {
-    get => GetXmlNodeBool(_showValuePath, true);
-    set => SetXmlNodeBool(_showValuePath, value);
-  }
-
-  public ExcelConditionalFormattingIconDataBarValue LowValue { get; internal set; }
-
-  public ExcelConditionalFormattingIconDataBarValue HighValue { get; internal set; }
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingDuplicateValues.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingDuplicateValues.cs
deleted file mode 100644
index ecba659..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingDuplicateValues.cs
+++ /dev/null
@@ -1,90 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingDuplicateValues
-/// </summary>
-public class ExcelConditionalFormattingDuplicateValues
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingDuplicateValues {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingDuplicateValues(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.DuplicateValues,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingDuplicateValues(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingDuplicateValues(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingEndsWith.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingEndsWith.cs
deleted file mode 100644
index 39d2a2b..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingEndsWith.cs
+++ /dev/null
@@ -1,112 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingEndsWith
-/// </summary>
-public class ExcelConditionalFormattingEndsWith
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingEndsWith {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingEndsWith(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.EndsWith,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      Operator = eExcelConditionalFormattingOperatorType.EndsWith;
-      Text = string.Empty;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingEndsWith(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingEndsWith(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-
-  /// <summary>
-  /// The text to search in the end of the cell
-  /// </summary>
-  public string Text {
-    get => GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._textAttribute);
-    set {
-      SetXmlNodeString(ExcelConditionalFormattingConstants.Paths._textAttribute, value);
-
-      Formula = string.Format(
-          "RIGHT({0},LEN(\"{1}\"))=\"{1}\"",
-          Address.Start.Address,
-          value.Replace("\"", "\"\""));
-    }
-  }
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingEqual.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingEqual.cs
deleted file mode 100644
index ddade06..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingEqual.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingEqual
-/// </summary>
-public class ExcelConditionalFormattingEqual
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingEqual {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingEqual(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.Equal,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      Operator = eExcelConditionalFormattingOperatorType.Equal;
-      Formula = string.Empty;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingEqual(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingEqual(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingExpression.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingExpression.cs
deleted file mode 100644
index ce887c5..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingExpression.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingExpression
-/// </summary>
-public class ExcelConditionalFormattingExpression
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingExpression {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingExpression(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.Expression,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      Formula = string.Empty;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingExpression(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingExpression(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingFiveIconSet.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingFiveIconSet.cs
deleted file mode 100644
index e75f49a..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingFiveIconSet.cs
+++ /dev/null
@@ -1,149 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingThreeIconSet
-/// </summary>
-public class ExcelConditionalFormattingFiveIconSet
-    : ExcelConditionalFormattingIconSetBase<eExcelconditionalFormatting5IconsSetType>,
-      IExcelConditionalFormattingFiveIconSet {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingFiveIconSet(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.FiveIconSet,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode != null && itemElementNode.HasChildNodes) {
-      XmlNode iconNode4 = TopNode.SelectSingleNode(
-          "d:iconSet/d:cfvo[position()=4]",
-          NameSpaceManager);
-      Icon4 = new(
-          eExcelConditionalFormattingRuleType.FiveIconSet,
-          address,
-          worksheet,
-          iconNode4,
-          namespaceManager);
-
-      XmlNode iconNode5 = TopNode.SelectSingleNode(
-          "d:iconSet/d:cfvo[position()=5]",
-          NameSpaceManager);
-      Icon5 = new(
-          eExcelConditionalFormattingRuleType.FiveIconSet,
-          address,
-          worksheet,
-          iconNode5,
-          namespaceManager);
-    } else {
-      XmlNode iconSetNode = TopNode.SelectSingleNode("d:iconSet", NameSpaceManager);
-      var iconNode4 = iconSetNode.OwnerDocument.CreateElement(
-          ExcelConditionalFormattingConstants.Paths._cfvo,
-          ExcelPackage._schemaMain);
-      iconSetNode.AppendChild(iconNode4);
-
-      Icon4 = new(
-          eExcelConditionalFormattingValueObjectType.Percent,
-          60,
-          "",
-          eExcelConditionalFormattingRuleType.ThreeIconSet,
-          address,
-          priority,
-          worksheet,
-          iconNode4,
-          namespaceManager);
-
-      var iconNode5 = iconSetNode.OwnerDocument.CreateElement(
-          ExcelConditionalFormattingConstants.Paths._cfvo,
-          ExcelPackage._schemaMain);
-      iconSetNode.AppendChild(iconNode5);
-
-      Icon5 = new(
-          eExcelConditionalFormattingValueObjectType.Percent,
-          80,
-          "",
-          eExcelConditionalFormattingRuleType.ThreeIconSet,
-          address,
-          priority,
-          worksheet,
-          iconNode5,
-          namespaceManager);
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingFiveIconSet(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingFiveIconSet(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-
-  public ExcelConditionalFormattingIconDataBarValue Icon5 { get; internal set; }
-
-  public ExcelConditionalFormattingIconDataBarValue Icon4 { get; internal set; }
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingFourIconSet.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingFourIconSet.cs
deleted file mode 100644
index 10bd1b3..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingFourIconSet.cs
+++ /dev/null
@@ -1,121 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingThreeIconSet
-/// </summary>
-public class ExcelConditionalFormattingFourIconSet
-    : ExcelConditionalFormattingIconSetBase<eExcelconditionalFormatting4IconsSetType>,
-      IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting4IconsSetType> {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingFourIconSet(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.FourIconSet,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode != null && itemElementNode.HasChildNodes) {
-      XmlNode iconNode4 = TopNode.SelectSingleNode(
-          "d:iconSet/d:cfvo[position()=4]",
-          NameSpaceManager);
-      Icon4 = new(
-          eExcelConditionalFormattingRuleType.FourIconSet,
-          address,
-          worksheet,
-          iconNode4,
-          namespaceManager);
-    } else {
-      XmlNode iconSetNode = TopNode.SelectSingleNode("d:iconSet", NameSpaceManager);
-      var iconNode4 = iconSetNode.OwnerDocument.CreateElement(
-          ExcelConditionalFormattingConstants.Paths._cfvo,
-          ExcelPackage._schemaMain);
-      iconSetNode.AppendChild(iconNode4);
-
-      Icon4 = new(
-          eExcelConditionalFormattingValueObjectType.Percent,
-          75,
-          "",
-          eExcelConditionalFormattingRuleType.ThreeIconSet,
-          address,
-          priority,
-          worksheet,
-          iconNode4,
-          namespaceManager);
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingFourIconSet(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingFourIconSet(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-
-  public ExcelConditionalFormattingIconDataBarValue Icon4 { get; internal set; }
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThan.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThan.cs
deleted file mode 100644
index 9e57c1e..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThan.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingGreaterThan
-/// </summary>
-public class ExcelConditionalFormattingGreaterThan
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingGreaterThan {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingGreaterThan(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.GreaterThan,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      Operator = eExcelConditionalFormattingOperatorType.GreaterThan;
-      Formula = string.Empty;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingGreaterThan(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingGreaterThan(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThanOrEqual.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThanOrEqual.cs
deleted file mode 100644
index 1a83939..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThanOrEqual.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingGreaterThanOrEqual
-/// </summary>
-public class ExcelConditionalFormattingGreaterThanOrEqual
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingGreaterThanOrEqual {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingGreaterThanOrEqual(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.GreaterThanOrEqual,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      Operator = eExcelConditionalFormattingOperatorType.GreaterThanOrEqual;
-      Formula = string.Empty;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingGreaterThanOrEqual(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingGreaterThanOrEqual(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLast7Days.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLast7Days.cs
deleted file mode 100644
index 100f6da..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLast7Days.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingLast7Days
-/// </summary>
-public class ExcelConditionalFormattingLast7Days : ExcelConditionalFormattingTimePeriodGroup {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingLast7Days(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.Last7Days,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      TimePeriod = eExcelConditionalFormattingTimePeriodType.Last7Days;
-      Formula = string.Format(
-          "AND(TODAY()-FLOOR({0},1)<=6,FLOOR({0},1)<=TODAY())",
-          Address.Start.Address);
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingLast7Days(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingLast7Days(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLastMonth.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLastMonth.cs
deleted file mode 100644
index 3888e32..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLastMonth.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingLastMonth
-/// </summary>
-public class ExcelConditionalFormattingLastMonth : ExcelConditionalFormattingTimePeriodGroup {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingLastMonth(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.LastMonth,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      TimePeriod = eExcelConditionalFormattingTimePeriodType.LastMonth;
-      Formula = string.Format(
-          "AND(MONTH({0})=MONTH(EDATE(TODAY(),0-1)),YEAR({0})=YEAR(EDATE(TODAY(),0-1)))",
-          Address.Start.Address);
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingLastMonth(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingLastMonth(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLastWeek.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLastWeek.cs
deleted file mode 100644
index 9edbe40..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLastWeek.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingLastWeek
-/// </summary>
-public class ExcelConditionalFormattingLastWeek : ExcelConditionalFormattingTimePeriodGroup {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingLastWeek(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.LastWeek,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      TimePeriod = eExcelConditionalFormattingTimePeriodType.LastWeek;
-      Formula = string.Format(
-          "AND(TODAY()-ROUNDDOWN({0},0)>=(WEEKDAY(TODAY())),TODAY()-ROUNDDOWN({0},0)<(WEEKDAY(TODAY())+7))",
-          Address.Start.Address);
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingLastWeek(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingLastWeek(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThan.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThan.cs
deleted file mode 100644
index 5695da9..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThan.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingLessThan
-/// </summary>
-public class ExcelConditionalFormattingLessThan
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingLessThan {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingLessThan(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.LessThan,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      Operator = eExcelConditionalFormattingOperatorType.LessThan;
-      Formula = string.Empty;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingLessThan(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingLessThan(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThanOrEqual.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThanOrEqual.cs
deleted file mode 100644
index 3e54630..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThanOrEqual.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingLessThanOrEqual
-/// </summary>
-public class ExcelConditionalFormattingLessThanOrEqual
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingLessThanOrEqual {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingLessThanOrEqual(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.LessThanOrEqual,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      Operator = eExcelConditionalFormattingOperatorType.LessThanOrEqual;
-      Formula = string.Empty;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingLessThanOrEqual(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingLessThanOrEqual(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNextMonth.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNextMonth.cs
deleted file mode 100644
index a7a23e6..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNextMonth.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingNextMonth
-/// </summary>
-public class ExcelConditionalFormattingNextMonth : ExcelConditionalFormattingTimePeriodGroup {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingNextMonth(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.NextMonth,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      TimePeriod = eExcelConditionalFormattingTimePeriodType.NextMonth;
-      Formula = string.Format(
-          "AND(MONTH({0})=MONTH(EDATE(TODAY(),0+1)), YEAR({0})=YEAR(EDATE(TODAY(),0+1)))",
-          Address.Start.Address);
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingNextMonth(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingNextMonth(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNextWeek.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNextWeek.cs
deleted file mode 100644
index 1c01b87..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNextWeek.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingNextWeek
-/// </summary>
-public class ExcelConditionalFormattingNextWeek : ExcelConditionalFormattingTimePeriodGroup {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingNextWeek(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.NextWeek,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      TimePeriod = eExcelConditionalFormattingTimePeriodType.NextWeek;
-      Formula = string.Format(
-          "AND(ROUNDDOWN({0},0)-TODAY()>(7-WEEKDAY(TODAY())),ROUNDDOWN({0},0)-TODAY()<(15-WEEKDAY(TODAY())))",
-          Address.Start.Address);
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingNextWeek(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingNextWeek(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotBetween.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotBetween.cs
deleted file mode 100644
index afa0de5..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotBetween.cs
+++ /dev/null
@@ -1,98 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingNotBetween
-/// </summary>
-public class ExcelConditionalFormattingNotBetween
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingNotBetween {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingNotBetween(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.NotBetween,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      Operator = eExcelConditionalFormattingOperatorType.NotBetween;
-      Formula = string.Empty;
-      Formula2 = string.Empty;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingNotBetween(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingNotBetween(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsBlanks.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsBlanks.cs
deleted file mode 100644
index babf13b..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsBlanks.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingNotContainsBlanks
-/// </summary>
-public class ExcelConditionalFormattingNotContainsBlanks
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingNotContainsBlanks {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingNotContainsBlanks(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.NotContainsBlanks,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      Formula = string.Format("LEN(TRIM({0}))>0", Address.Start.Address);
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingNotContainsBlanks(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingNotContainsBlanks(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsErrors.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsErrors.cs
deleted file mode 100644
index e6fa828..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsErrors.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingNotContainsErrors
-/// </summary>
-public class ExcelConditionalFormattingNotContainsErrors
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingNotContainsErrors {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingNotContainsErrors(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.NotContainsErrors,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      Formula = string.Format("NOT(ISERROR({0}))", Address.Start.Address);
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingNotContainsErrors(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingNotContainsErrors(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsText.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsText.cs
deleted file mode 100644
index 1b86511..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsText.cs
+++ /dev/null
@@ -1,112 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingNotContainsText
-/// </summary>
-public class ExcelConditionalFormattingNotContainsText
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingNotContainsText {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingNotContainsText(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.NotContainsText,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      Operator = eExcelConditionalFormattingOperatorType.NotContains;
-      Text = string.Empty;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingNotContainsText(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingNotContainsText(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-
-  /// <summary>
-  /// The text to search inside the cell
-  /// </summary>
-  public string Text {
-    get => GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._textAttribute);
-    set {
-      SetXmlNodeString(ExcelConditionalFormattingConstants.Paths._textAttribute, value);
-
-      Formula = string.Format(
-          "ISERROR(SEARCH(\"{1}\",{0}))",
-          Address.Start.Address,
-          value.Replace("\"", "\"\""));
-    }
-  }
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotEqual.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotEqual.cs
deleted file mode 100644
index 8782151..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotEqual.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingNotEqual
-/// </summary>
-public class ExcelConditionalFormattingNotEqual
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingNotEqual {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingNotEqual(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.NotEqual,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      Operator = eExcelConditionalFormattingOperatorType.NotEqual;
-      Formula = string.Empty;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingNotEqual(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingNotEqual(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingRule.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingRule.cs
deleted file mode 100644
index 082da63..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingRule.cs
+++ /dev/null
@@ -1,492 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System;
-using System.Collections.Immutable;
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-using OfficeOpenXml.Style.Dxf;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-///
-/// </summary>
-public abstract class ExcelConditionalFormattingRule : XmlHelper, IExcelConditionalFormattingRule {
-  private eExcelConditionalFormattingRuleType? _type;
-  private readonly ExcelWorksheet _worksheet;
-
-  /// <summary>
-  /// Sinalize that we are in a Cnaging Priorities opeartion so that we won't enter
-  /// a recursive loop.
-  /// </summary>
-  private static bool _changingPriority;
-
-  protected override ImmutableArray<string> SchemaNodeOrder =>
-    ExcelWorksheet.WorksheetSchemaNodeOrder;
-
-  /// <summary>
-  /// Initialize the <see cref="ExcelConditionalFormattingRule"/>
-  /// </summary>
-  /// <param name="type"></param>
-  /// <param name="address"></param>
-  /// <param name="priority">Used also as the cfRule unique key</param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingRule(
-      eExcelConditionalFormattingRuleType type,
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(namespaceManager, itemElementNode) {
-    Require.Argument(address).IsNotNull("address");
-    Require.Argument(priority).IsInRange(1, int.MaxValue, "priority");
-    Require.Argument(worksheet).IsNotNull("worksheet");
-
-    _type = type;
-    _worksheet = worksheet;
-
-    if (itemElementNode == null) {
-      // Create/Get the <cfRule> inside <conditionalFormatting>
-      itemElementNode = CreateComplexNode(
-          _worksheet.WorksheetXml.DocumentElement,
-          string.Format(
-              "{0}[{1}='{2}']/{1}='{2}'/{3}[{4}='{5}']/{4}='{5}'",
-              //{0}
-              ExcelConditionalFormattingConstants.Paths._conditionalFormatting,
-              // {1}
-              ExcelConditionalFormattingConstants.Paths._sqrefAttribute,
-              // {2}
-              address.AddressSpaceSeparated, //CF node don't what to have comma between multi addresses, use space instead.
-              // {3}
-              ExcelConditionalFormattingConstants.Paths._cfRule,
-              //{4}
-              ExcelConditionalFormattingConstants.Paths._priorityAttribute,
-              //{5}
-              priority));
-    }
-
-    // Point to <cfRule>
-    TopNode = itemElementNode;
-
-    Address = address;
-    Priority = priority;
-    Type = type;
-    if (DxfId >= 0) {
-      worksheet.Workbook.Styles.Dxfs[DxfId].AllowChange = true; //This Id is referenced by CF, so we can use it when we save.
-      _style = worksheet.Workbook.Styles.Dxfs[DxfId].Clone(); //Clone, so it can be altered without effecting other dxf styles
-    }
-  }
-
-  /// <summary>
-  /// Initialize the <see cref="ExcelConditionalFormattingRule"/>
-  /// </summary>
-  /// <param name="type"></param>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingRule(
-      eExcelConditionalFormattingRuleType type,
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNamespaceManager namespaceManager)
-      : this(type, address, priority, worksheet, null, namespaceManager) {}
-
-  /// <summary>
-  /// Get the &lt;cfRule&gt; node
-  /// </summary>
-  public XmlNode Node => TopNode;
-
-  /// <summary>
-  /// Address of the conditional formatting rule
-  /// </summary>
-  /// <remarks>
-  /// The address is stores in a parent node called &lt;conditionalFormatting&gt; in the
-  /// @sqref attribute. Excel groups rules that have the same address inside one node.
-  /// </remarks>
-  public ExcelAddress Address {
-    get =>
-      new(Node.ParentNode.Attributes[ExcelConditionalFormattingConstants.Attributes._sqref].Value);
-    set {
-      // Check if the address is to be changed
-      if (Address.Address != value.Address) {
-        // Save the old parente node
-        XmlNode oldNode = Node;
-        XmlNode oldParentNode = Node.ParentNode;
-
-        // Create/Get the new <conditionalFormatting> parent node
-        XmlNode newParentNode = CreateComplexNode(
-            _worksheet.WorksheetXml.DocumentElement,
-            string.Format(
-                "{0}[{1}='{2}']/{1}='{2}'",
-                //{0}
-                ExcelConditionalFormattingConstants.Paths._conditionalFormatting,
-                // {1}
-                ExcelConditionalFormattingConstants.Paths._sqrefAttribute,
-                // {2}
-                value.AddressSpaceSeparated));
-
-        // Move the <cfRule> node to the new <conditionalFormatting> parent node
-        TopNode = newParentNode.AppendChild(Node);
-
-        // Check if the old <conditionalFormatting> parent node has <cfRule> node inside it
-        if (!oldParentNode.HasChildNodes) {
-          // Remove the old parent node
-          oldParentNode.ParentNode.RemoveChild(oldParentNode);
-        }
-      }
-    }
-  }
-
-  /// <summary>
-  /// Type of conditional formatting rule. ST_CfType §18.18.12.
-  /// </summary>
-  public eExcelConditionalFormattingRuleType Type {
-    get {
-      // Transform the @type attribute to EPPlus Rule Type (slighty diferente)
-      if (_type == null) {
-        _type = ExcelConditionalFormattingRuleType.GetTypeByAttrbiute(
-            GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._typeAttribute),
-            TopNode,
-            _worksheet.NameSpaceManager);
-      }
-      return (eExcelConditionalFormattingRuleType)_type;
-    }
-    internal set {
-      _type = value;
-      // Transform the EPPlus Rule Type to @type attribute (slighty diferente)
-      SetXmlNodeString(
-          ExcelConditionalFormattingConstants.Paths._typeAttribute,
-          ExcelConditionalFormattingRuleType.GetAttributeByType(value),
-          true);
-    }
-  }
-
-  /// <summary>
-  /// The priority of this conditional formatting rule. This value is used to determine
-  /// which format should be evaluated and rendered. Lower numeric values are higher
-  /// priority than higher numeric values, where 1 is the highest priority.
-  /// </summary>
-  public int Priority {
-    get => GetXmlNodeInt(ExcelConditionalFormattingConstants.Paths._priorityAttribute);
-    set {
-      // Save the current CF rule priority
-      int priority = Priority;
-
-      // Check if the @priority is to be changed
-      if (priority != value) {
-        // Check if we are not already inside a "Change Priority" operation
-        if (!_changingPriority) {
-          if (value < 1) {
-            throw new IndexOutOfRangeException(
-                ExcelConditionalFormattingConstants.Errors._invalidPriority);
-          }
-
-          // Sinalize that we are already changing cfRules priorities
-          _changingPriority = true;
-
-          // Check if we lowered the priority
-          if (priority > value) {
-            for (int i = priority - 1; i >= value; i--) {
-              var cfRule = _worksheet.ConditionalFormatting.RulesByPriority(i);
-
-              if (cfRule != null) {
-                cfRule.Priority++;
-              }
-            }
-          } else {
-            for (int i = priority + 1; i <= value; i++) {
-              var cfRule = _worksheet.ConditionalFormatting.RulesByPriority(i);
-
-              if (cfRule != null) {
-                cfRule.Priority--;
-              }
-            }
-          }
-
-          // Sinalize that we are no longer changing cfRules priorities
-          _changingPriority = false;
-        }
-
-        // Change the priority in the XML
-        SetXmlNodeString(
-            ExcelConditionalFormattingConstants.Paths._priorityAttribute,
-            value.ToString(),
-            true);
-      }
-    }
-  }
-
-  /// <summary>
-  /// If this flag is true, no rules with lower priority shall be applied over this rule,
-  /// when this rule evaluates to true.
-  /// </summary>
-  public bool StopIfTrue {
-    get => GetXmlNodeBool(ExcelConditionalFormattingConstants.Paths._stopIfTrueAttribute);
-    set =>
-      SetXmlNodeString(
-          ExcelConditionalFormattingConstants.Paths._stopIfTrueAttribute,
-          value ? "1" : string.Empty,
-          true);
-  }
-
-  /// <summary>
-  /// DxfId Style Attribute
-  /// </summary>
-  internal int DxfId {
-    get => GetXmlNodeInt(ExcelConditionalFormattingConstants.Paths._dxfIdAttribute);
-    set =>
-      SetXmlNodeString(
-          ExcelConditionalFormattingConstants.Paths._dxfIdAttribute,
-          (value == int.MinValue) ? string.Empty : value.ToString(),
-          true);
-  }
-
-  internal ExcelDxfStyleConditionalFormatting _style;
-
-  public ExcelDxfStyleConditionalFormatting Style {
-    get {
-      if (_style == null) {
-        _style = new(NameSpaceManager, null, _worksheet.Workbook.Styles);
-      }
-      return _style;
-    }
-  }
-
-  /// <summary>
-  /// StdDev (zero is not allowed and will be converted to 1)
-  /// </summary>
-  public UInt16 StdDev {
-    get =>
-      Convert.ToUInt16(GetXmlNodeInt(ExcelConditionalFormattingConstants.Paths._stdDevAttribute));
-    set =>
-      SetXmlNodeString(
-          ExcelConditionalFormattingConstants.Paths._stdDevAttribute,
-          (value == 0) ? "1" : value.ToString(),
-          true);
-  }
-
-  /// <summary>
-  /// Rank (zero is not allowed and will be converted to 1)
-  /// </summary>
-  public UInt16 Rank {
-    get =>
-      Convert.ToUInt16(GetXmlNodeInt(ExcelConditionalFormattingConstants.Paths._rankAttribute));
-    set =>
-      SetXmlNodeString(
-          ExcelConditionalFormattingConstants.Paths._rankAttribute,
-          (value == 0) ? "1" : value.ToString(),
-          true);
-  }
-
-  /// <summary>
-  /// AboveAverage
-  /// </summary>
-  internal protected bool? AboveAverage {
-    get {
-      bool? aboveAverage = GetXmlNodeBoolNullable(
-          ExcelConditionalFormattingConstants.Paths._aboveAverageAttribute);
-
-      // Above Avarege if TRUE or if attribute does not exists
-      return (aboveAverage == true) || (aboveAverage == null);
-    }
-    set {
-      string aboveAverageValue = string.Empty;
-
-      // Only the types that needs the @AboveAverage
-      if ((_type == eExcelConditionalFormattingRuleType.BelowAverage)
-          || (_type == eExcelConditionalFormattingRuleType.BelowOrEqualAverage)
-          || (_type == eExcelConditionalFormattingRuleType.BelowStdDev)) {
-        aboveAverageValue = "0";
-      }
-
-      SetXmlNodeString(
-          ExcelConditionalFormattingConstants.Paths._aboveAverageAttribute,
-          aboveAverageValue,
-          true);
-    }
-  }
-
-  /// <summary>
-  /// EqualAverage
-  /// </summary>
-  internal protected bool? EqualAverage {
-    get {
-      bool? equalAverage = GetXmlNodeBoolNullable(
-          ExcelConditionalFormattingConstants.Paths._equalAverageAttribute);
-
-      // Equal Avarege only if TRUE
-      return (equalAverage == true);
-    }
-    set {
-      string equalAverageValue = string.Empty;
-
-      // Only the types that needs the @EqualAverage
-      if ((_type == eExcelConditionalFormattingRuleType.AboveOrEqualAverage)
-          || (_type == eExcelConditionalFormattingRuleType.BelowOrEqualAverage)) {
-        equalAverageValue = "1";
-      }
-
-      SetXmlNodeString(
-          ExcelConditionalFormattingConstants.Paths._equalAverageAttribute,
-          equalAverageValue,
-          true);
-    }
-  }
-
-  /// <summary>
-  /// Bottom attribute
-  /// </summary>
-  internal protected bool? Bottom {
-    get {
-      bool? bottom = GetXmlNodeBoolNullable(
-          ExcelConditionalFormattingConstants.Paths._bottomAttribute);
-
-      // Bottom if TRUE
-      return (bottom == true);
-    }
-    set {
-      string bottomValue = string.Empty;
-
-      // Only the types that needs the @Bottom
-      if ((_type == eExcelConditionalFormattingRuleType.Bottom)
-          || (_type == eExcelConditionalFormattingRuleType.BottomPercent)) {
-        bottomValue = "1";
-      }
-
-      SetXmlNodeString(
-          ExcelConditionalFormattingConstants.Paths._bottomAttribute,
-          bottomValue,
-          true);
-    }
-  }
-
-  /// <summary>
-  /// Percent attribute
-  /// </summary>
-  internal protected bool? Percent {
-    get {
-      bool? percent = GetXmlNodeBoolNullable(
-          ExcelConditionalFormattingConstants.Paths._percentAttribute);
-
-      // Bottom if TRUE
-      return (percent == true);
-    }
-    set {
-      string percentValue = string.Empty;
-
-      // Only the types that needs the @Bottom
-      if ((_type == eExcelConditionalFormattingRuleType.BottomPercent)
-          || (_type == eExcelConditionalFormattingRuleType.TopPercent)) {
-        percentValue = "1";
-      }
-
-      SetXmlNodeString(
-          ExcelConditionalFormattingConstants.Paths._percentAttribute,
-          percentValue,
-          true);
-    }
-  }
-
-  /// <summary>
-  /// TimePeriod
-  /// </summary>
-  internal protected eExcelConditionalFormattingTimePeriodType TimePeriod {
-    get =>
-      ExcelConditionalFormattingTimePeriodType.GetTypeByAttribute(
-          GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._timePeriodAttribute));
-    set =>
-      SetXmlNodeString(
-          ExcelConditionalFormattingConstants.Paths._timePeriodAttribute,
-          ExcelConditionalFormattingTimePeriodType.GetAttributeByType(value),
-          true);
-  }
-
-  /// <summary>
-  /// Operator
-  /// </summary>
-  internal protected eExcelConditionalFormattingOperatorType Operator {
-    get =>
-      ExcelConditionalFormattingOperatorType.GetTypeByAttribute(
-          GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._operatorAttribute));
-    set =>
-      SetXmlNodeString(
-          ExcelConditionalFormattingConstants.Paths._operatorAttribute,
-          ExcelConditionalFormattingOperatorType.GetAttributeByType(value),
-          true);
-  }
-
-  /// <summary>
-  /// Formula
-  /// </summary>
-  public string Formula {
-    get => GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._formula);
-    set => SetXmlNodeString(ExcelConditionalFormattingConstants.Paths._formula, value);
-  }
-
-  /// <summary>
-  /// Formula2
-  /// </summary>
-  public string Formula2 {
-    get =>
-      GetXmlNodeString(
-          string.Format(
-              "{0}[position()=2]",
-              // {0}
-              ExcelConditionalFormattingConstants.Paths._formula));
-    set {
-      // Create/Get the first <formula> node (ensure that it exists)
-      var firstNode = CreateComplexNode(
-          TopNode,
-          string.Format(
-              "{0}[position()=1]",
-              // {0}
-              ExcelConditionalFormattingConstants.Paths._formula));
-
-      // Create/Get the seconde <formula> node (ensure that it exists)
-      var secondNode = CreateComplexNode(
-          TopNode,
-          string.Format(
-              "{0}[position()=2]",
-              // {0}
-              ExcelConditionalFormattingConstants.Paths._formula));
-
-      // Save the formula in the second <formula> node
-      secondNode.InnerText = value;
-    }
-  }
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThisMonth.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThisMonth.cs
deleted file mode 100644
index db86666..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThisMonth.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingThisMonth
-/// </summary>
-public class ExcelConditionalFormattingThisMonth : ExcelConditionalFormattingTimePeriodGroup {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingThisMonth(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.ThisMonth,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      TimePeriod = eExcelConditionalFormattingTimePeriodType.ThisMonth;
-      Formula = string.Format(
-          "AND(MONTH({0})=MONTH(TODAY()), YEAR({0})=YEAR(TODAY()))",
-          Address.Start.Address);
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingThisMonth(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingThisMonth(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThisWeek.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThisWeek.cs
deleted file mode 100644
index 1635e36..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThisWeek.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingThisWeek
-/// </summary>
-public class ExcelConditionalFormattingThisWeek : ExcelConditionalFormattingTimePeriodGroup {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingThisWeek(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.ThisWeek,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      TimePeriod = eExcelConditionalFormattingTimePeriodType.ThisWeek;
-      Formula = string.Format(
-          "AND(TODAY()-ROUNDDOWN({0},0)<=WEEKDAY(TODAY())-1,ROUNDDOWN({0},0)-TODAY()<=7-WEEKDAY(TODAY()))",
-          Address.Start.Address);
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingThisWeek(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingThisWeek(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeColorScale.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeColorScale.cs
deleted file mode 100644
index 23c8d02..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeColorScale.cs
+++ /dev/null
@@ -1,142 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingThreeColorScale
-/// </summary>
-public class ExcelConditionalFormattingThreeColorScale
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingThreeColorScale {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingThreeColorScale(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.ThreeColorScale,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    // Create the <colorScale> node inside the <cfRule> node
-    var colorScaleNode = CreateComplexNode(
-        Node,
-        ExcelConditionalFormattingConstants.Paths._colorScale);
-
-    // LowValue default
-    LowValue = new(
-        eExcelConditionalFormattingValueObjectPosition.Low,
-        eExcelConditionalFormattingValueObjectType.Min,
-        eExcelConditionalFormattingRuleType.ThreeColorScale,
-        address,
-        priority,
-        worksheet,
-        NameSpaceManager);
-
-    // MiddleValue default
-    MiddleValue = new(
-        eExcelConditionalFormattingValueObjectPosition.Middle,
-        eExcelConditionalFormattingValueObjectType.Percent,
-        50,
-        string.Empty,
-        eExcelConditionalFormattingRuleType.ThreeColorScale,
-        address,
-        priority,
-        worksheet,
-        NameSpaceManager);
-
-    // HighValue default
-    HighValue = new(
-        eExcelConditionalFormattingValueObjectPosition.High,
-        eExcelConditionalFormattingValueObjectType.Max,
-        eExcelConditionalFormattingRuleType.ThreeColorScale,
-        address,
-        priority,
-        worksheet,
-        NameSpaceManager);
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingThreeColorScale(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingThreeColorScale(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-
-  /// <summary>
-  /// Low Value for Three Color Scale Object Value
-  /// </summary>
-  public ExcelConditionalFormattingColorScaleValue LowValue { get; set; }
-
-  /// <summary>
-  /// Middle Value for Three Color Scale Object Value
-  /// </summary>
-  public ExcelConditionalFormattingColorScaleValue MiddleValue { get; set; }
-
-  /// <summary>
-  /// High Value for Three Color Scale Object Value
-  /// </summary>
-  public ExcelConditionalFormattingColorScaleValue HighValue { get; set; }
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeIconSet.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeIconSet.cs
deleted file mode 100644
index bcf19e1..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeIconSet.cs
+++ /dev/null
@@ -1,278 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System;
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-public class ExcelConditionalFormattingThreeIconSet
-    : ExcelConditionalFormattingIconSetBase<eExcelconditionalFormatting3IconsSetType> {
-  internal ExcelConditionalFormattingThreeIconSet(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.ThreeIconSet,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {}
-}
-
-/// <summary>
-/// ExcelConditionalFormattingThreeIconSet
-/// </summary>
-public class ExcelConditionalFormattingIconSetBase<T>
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingThreeIconSet<T> {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="type"></param>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingIconSetBase(
-      eExcelConditionalFormattingRuleType type,
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          type,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode != null && itemElementNode.HasChildNodes) {
-      int pos = 1;
-      foreach (XmlNode node in itemElementNode.SelectNodes("d:iconSet/d:cfvo", NameSpaceManager)) {
-        if (pos == 1) {
-          Icon1 = new(type, address, worksheet, node, namespaceManager);
-        } else if (pos == 2) {
-          Icon2 = new(type, address, worksheet, node, namespaceManager);
-        } else if (pos == 3) {
-          Icon3 = new(type, address, worksheet, node, namespaceManager);
-        } else {
-          break;
-        }
-        pos++;
-      }
-    } else {
-      var iconSetNode = CreateComplexNode(Node, ExcelConditionalFormattingConstants.Paths._iconSet);
-
-      //Create the <iconSet> node inside the <cfRule> node
-      double spann;
-      if (type == eExcelConditionalFormattingRuleType.ThreeIconSet) {
-        spann = 3;
-      } else if (type == eExcelConditionalFormattingRuleType.FourIconSet) {
-        spann = 4;
-      } else {
-        spann = 5;
-      }
-
-      var iconNode1 = iconSetNode.OwnerDocument.CreateElement(
-          ExcelConditionalFormattingConstants.Paths._cfvo,
-          ExcelPackage._schemaMain);
-      iconSetNode.AppendChild(iconNode1);
-      Icon1 = new(
-          eExcelConditionalFormattingValueObjectType.Percent,
-          0,
-          "",
-          eExcelConditionalFormattingRuleType.ThreeIconSet,
-          address,
-          priority,
-          worksheet,
-          iconNode1,
-          namespaceManager);
-
-      var iconNode2 = iconSetNode.OwnerDocument.CreateElement(
-          ExcelConditionalFormattingConstants.Paths._cfvo,
-          ExcelPackage._schemaMain);
-      iconSetNode.AppendChild(iconNode2);
-      Icon2 = new(
-          eExcelConditionalFormattingValueObjectType.Percent,
-          Math.Round(100D / spann, 0),
-          "",
-          eExcelConditionalFormattingRuleType.ThreeIconSet,
-          address,
-          priority,
-          worksheet,
-          iconNode2,
-          namespaceManager);
-
-      var iconNode3 = iconSetNode.OwnerDocument.CreateElement(
-          ExcelConditionalFormattingConstants.Paths._cfvo,
-          ExcelPackage._schemaMain);
-      iconSetNode.AppendChild(iconNode3);
-      Icon3 = new(
-          eExcelConditionalFormattingValueObjectType.Percent,
-          Math.Round(100D * (2D / spann), 0),
-          "",
-          eExcelConditionalFormattingRuleType.ThreeIconSet,
-          address,
-          priority,
-          worksheet,
-          iconNode3,
-          namespaceManager);
-      Type = type;
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  ///<param name="type"></param>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingIconSetBase(
-      eExcelConditionalFormattingRuleType type,
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(type, address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  ///<param name="type"></param>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingIconSetBase(
-      eExcelConditionalFormattingRuleType type,
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(type, address, priority, worksheet, null, null) {}
-
-  /// <summary>
-  /// Settings for icon 1 in the iconset
-  /// </summary>
-  public ExcelConditionalFormattingIconDataBarValue Icon1 { get; internal set; }
-
-  /// <summary>
-  /// Settings for icon 2 in the iconset
-  /// </summary>
-  public ExcelConditionalFormattingIconDataBarValue Icon2 { get; internal set; }
-
-  /// <summary>
-  /// Settings for icon 2 in the iconset
-  /// </summary>
-  public ExcelConditionalFormattingIconDataBarValue Icon3 { get; internal set; }
-
-  private const string _reversePath = "d:iconSet/@reverse";
-
-  /// <summary>
-  /// Reverse the order of the icons
-  /// </summary>
-  public bool Reverse {
-    get => GetXmlNodeBool(_reversePath, false);
-    set => SetXmlNodeBool(_reversePath, value);
-  }
-
-  private const string _showValuePath = "d:iconSet/@showValue";
-
-  /// <summary>
-  /// If the cell values are visible
-  /// </summary>
-  public bool ShowValue {
-    get => GetXmlNodeBool(_showValuePath, true);
-    set => SetXmlNodeBool(_showValuePath, value);
-  }
-
-  private const string _iconSetPath = "d:iconSet/@iconSet";
-
-  private string GetIconSetString(T value) {
-    if (Type == eExcelConditionalFormattingRuleType.FourIconSet) {
-      switch (value.ToString()) {
-        case "Arrows":
-          return "4Arrows";
-        case "ArrowsGray":
-          return "4ArrowsGray";
-        case "Rating":
-          return "4Rating";
-        case "RedToBlack":
-          return "4RedToBlack";
-        case "TrafficLights":
-          return "4TrafficLights";
-        default:
-          throw (new ArgumentException("Invalid type"));
-      }
-    }
-    if (Type == eExcelConditionalFormattingRuleType.FiveIconSet) {
-      switch (value.ToString()) {
-        case "Arrows":
-          return "5Arrows";
-        case "ArrowsGray":
-          return "5ArrowsGray";
-        case "Quarters":
-          return "5Quarters";
-        case "Rating":
-          return "5Rating";
-        default:
-          throw (new ArgumentException("Invalid type"));
-      }
-    }
-    switch (value.ToString()) {
-      case "Arrows":
-        return "3Arrows";
-      case "ArrowsGray":
-        return "3ArrowsGray";
-      case "Flags":
-        return "3Flags";
-      case "Signs":
-        return "3Signs";
-      case "Symbols":
-        return "3Symbols";
-      case "Symbols2":
-        return "3Symbols2";
-      case "TrafficLights1":
-        return "3TrafficLights1";
-      case "TrafficLights2":
-        return "3TrafficLights2";
-      default:
-        throw (new ArgumentException("Invalid type"));
-    }
-  }
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTimePeriodGroup.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTimePeriodGroup.cs
deleted file mode 100644
index 52fe1ab..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTimePeriodGroup.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingTimePeriodGroup
-/// </summary>
-public class ExcelConditionalFormattingTimePeriodGroup
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingTimePeriodGroup {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="type"></param>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingTimePeriodGroup(
-      eExcelConditionalFormattingRuleType type,
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          type,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="type"></param>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingTimePeriodGroup(
-      eExcelConditionalFormattingRuleType type,
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(type, address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="type"></param>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingTimePeriodGroup(
-      eExcelConditionalFormattingRuleType type,
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(type, address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingToday.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingToday.cs
deleted file mode 100644
index b2d1755..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingToday.cs
+++ /dev/null
@@ -1,94 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingToday
-/// </summary>
-public class ExcelConditionalFormattingToday : ExcelConditionalFormattingTimePeriodGroup {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingToday(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.Today,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      TimePeriod = eExcelConditionalFormattingTimePeriodType.Today;
-      Formula = string.Format("FLOOR({0},1)=TODAY()", Address.Start.Address);
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingToday(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingToday(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTomorrow.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTomorrow.cs
deleted file mode 100644
index fcfab71..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTomorrow.cs
+++ /dev/null
@@ -1,94 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingTomorrow
-/// </summary>
-public class ExcelConditionalFormattingTomorrow : ExcelConditionalFormattingTimePeriodGroup {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingTomorrow(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.Tomorrow,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      TimePeriod = eExcelConditionalFormattingTimePeriodType.Tomorrow;
-      Formula = string.Format("FLOOR({0},1)=TODAY()+1", Address.Start.Address);
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingTomorrow(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingTomorrow(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTop.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTop.cs
deleted file mode 100644
index 5672d2d..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTop.cs
+++ /dev/null
@@ -1,98 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingTop
-/// </summary>
-public class ExcelConditionalFormattingTop
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingTopBottomGroup {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingTop(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.Top,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      Bottom = false;
-      Percent = false;
-      Rank = 10; // First 10 values
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingTop(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingTop(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTopPercent.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTopPercent.cs
deleted file mode 100644
index 0d4a06c..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTopPercent.cs
+++ /dev/null
@@ -1,98 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingTopPercent
-/// </summary>
-public class ExcelConditionalFormattingTopPercent
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingTopBottomGroup {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingTopPercent(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.TopPercent,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      Bottom = false;
-      Percent = true;
-      Rank = 10; // First 10 percent
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingTopPercent(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingTopPercent(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTwoColorScale.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTwoColorScale.cs
deleted file mode 100644
index 691f0dd..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTwoColorScale.cs
+++ /dev/null
@@ -1,141 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingTwoColorScale
-/// </summary>
-public class ExcelConditionalFormattingTwoColorScale
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingTwoColorScale {
-  /// <summary>
-  /// Private Low Value
-  /// </summary>
-  private ExcelConditionalFormattingColorScaleValue _lowValue;
-
-  /// <summary>
-  /// Private High Value
-  /// </summary>
-  private ExcelConditionalFormattingColorScaleValue _highValue;
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingTwoColorScale(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.TwoColorScale,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    // Create the <colorScale> node inside the <cfRule> node
-    var colorScaleNode = CreateComplexNode(
-        Node,
-        ExcelConditionalFormattingConstants.Paths._colorScale);
-
-    // LowValue default
-    LowValue = new(
-        eExcelConditionalFormattingValueObjectPosition.Low,
-        eExcelConditionalFormattingValueObjectType.Min,
-        eExcelConditionalFormattingRuleType.TwoColorScale,
-        address,
-        priority,
-        worksheet,
-        NameSpaceManager);
-
-    // HighValue default
-    HighValue = new(
-        eExcelConditionalFormattingValueObjectPosition.High,
-        eExcelConditionalFormattingValueObjectType.Max,
-        eExcelConditionalFormattingRuleType.TwoColorScale,
-        address,
-        priority,
-        worksheet,
-        NameSpaceManager);
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingTwoColorScale(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingTwoColorScale(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-
-  /// <summary>
-  /// Low Value for Two Color Scale Object Value
-  /// </summary>
-  public ExcelConditionalFormattingColorScaleValue LowValue {
-    get => _lowValue;
-    set => _lowValue = value;
-  }
-
-  /// <summary>
-  /// High Value for Two Color Scale Object Value
-  /// </summary>
-  public ExcelConditionalFormattingColorScaleValue HighValue {
-    get => _highValue;
-    set => _highValue = value;
-  }
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingUniqueValues.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingUniqueValues.cs
deleted file mode 100644
index ff0ba0d..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingUniqueValues.cs
+++ /dev/null
@@ -1,90 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting.Contracts;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingUniqueValues
-/// </summary>
-public class ExcelConditionalFormattingUniqueValues
-    : ExcelConditionalFormattingRule,
-      IExcelConditionalFormattingUniqueValues {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="priority"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingUniqueValues(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.UniqueValues,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingUniqueValues(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingUniqueValues(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingYesterday.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingYesterday.cs
deleted file mode 100644
index a5701ec..0000000
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingYesterday.cs
+++ /dev/null
@@ -1,94 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Eyal Seagull        Added       		  2012-04-03
- *******************************************************************************/
-
-using System.Xml;
-
-namespace OfficeOpenXml.ConditionalFormatting;
-
-/// <summary>
-/// ExcelConditionalFormattingYesterday
-/// </summary>
-public class ExcelConditionalFormattingYesterday : ExcelConditionalFormattingTimePeriodGroup {
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelConditionalFormattingYesterday(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(
-          eExcelConditionalFormattingRuleType.Yesterday,
-          address,
-          priority,
-          worksheet,
-          itemElementNode,
-          namespaceManager ?? worksheet.NameSpaceManager) {
-    if (itemElementNode
-        == null) //Set default values and create attributes if needed
-    {
-      TimePeriod = eExcelConditionalFormattingTimePeriodType.Yesterday;
-      Formula = string.Format("FLOOR({0},1)=TODAY()-1", Address.Start.Address);
-    }
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelConditionalFormattingYesterday(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet,
-      XmlNode itemElementNode)
-      : this(address, priority, worksheet, itemElementNode, null) {}
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="priority"></param>
-  /// <param name="address"></param>
-  /// <param name="worksheet"></param>
-  internal ExcelConditionalFormattingYesterday(
-      ExcelAddress address,
-      int priority,
-      ExcelWorksheet worksheet)
-      : this(address, priority, worksheet, null, null) {}
-}
diff --git a/EPPlus/DataValidation/Contracts/IExcelDataValidation.cs b/EPPlus/DataValidation/Contracts/IExcelDataValidation.cs
deleted file mode 100644
index 7917008..0000000
--- a/EPPlus/DataValidation/Contracts/IExcelDataValidation.cs
+++ /dev/null
@@ -1,98 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-namespace OfficeOpenXml.DataValidation.Contracts;
-
-/// <summary>
-/// Interface for data validation
-/// </summary>
-public interface IExcelDataValidation {
-  /// <summary>
-  /// Address of data validation
-  /// </summary>
-  ExcelAddress Address { get; }
-
-  /// <summary>
-  /// Validation type
-  /// </summary>
-  ExcelDataValidationType ValidationType { get; }
-
-  /// <summary>
-  /// Controls how Excel will handle invalid values.
-  /// </summary>
-  ExcelDataValidationWarningStyle ErrorStyle { get; }
-
-  /// <summary>
-  /// True if input message should be shown
-  /// </summary>
-  bool? AllowBlank { get; set; }
-
-  /// <summary>
-  /// True if input message should be shown
-  /// </summary>
-  bool? ShowInputMessage { get; set; }
-
-  /// <summary>
-  /// True if error message should be shown.
-  /// </summary>
-  bool? ShowErrorMessage { get; set; }
-
-  /// <summary>
-  /// Title of error message box (see property ShowErrorMessage)
-  /// </summary>
-  string ErrorTitle { get; set; }
-
-  /// <summary>
-  /// Error message box text (see property ShowErrorMessage)
-  /// </summary>
-  string Error { get; set; }
-
-  /// <summary>
-  /// Title of info box if input message should be shown (see property ShowInputMessage)
-  /// </summary>
-  string PromptTitle { get; set; }
-
-  /// <summary>
-  /// Info message text (see property ShowErrorMessage)
-  /// </summary>
-  string Prompt { get; set; }
-
-  /// <summary>
-  /// True if the current validation type allows operator.
-  /// </summary>
-  bool AllowsOperator { get; }
-
-  /// <summary>
-  /// Validates the state of the validation.
-  /// </summary>
-  void Validate();
-}
diff --git a/EPPlus/DataValidation/Contracts/IExcelDataValidationAny.cs b/EPPlus/DataValidation/Contracts/IExcelDataValidationAny.cs
deleted file mode 100644
index c3b6bfd..0000000
--- a/EPPlus/DataValidation/Contracts/IExcelDataValidationAny.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Raziq York   		            Added       		        2014-08-08
- *******************************************************************************/
-
-namespace OfficeOpenXml.DataValidation.Contracts;
-
-/// <summary>
-/// Data validation interface for Any value validation.
-/// </summary>
-public interface IExcelDataValidationAny : IExcelDataValidation {}
diff --git a/EPPlus/DataValidation/Contracts/IExcelDataValidationCustom.cs b/EPPlus/DataValidation/Contracts/IExcelDataValidationCustom.cs
deleted file mode 100644
index f567ce4..0000000
--- a/EPPlus/DataValidation/Contracts/IExcelDataValidationCustom.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-namespace OfficeOpenXml.DataValidation.Contracts;
-
-/// <summary>
-/// Data validation interface for custom validation.
-/// </summary>
-public interface IExcelDataValidationCustom
-    : IExcelDataValidationWithFormula<IExcelDataValidationFormula>,
-      IExcelDataValidationWithOperator {}
diff --git a/EPPlus/DataValidation/Contracts/IExcelDataValidationDateTime.cs b/EPPlus/DataValidation/Contracts/IExcelDataValidationDateTime.cs
deleted file mode 100644
index 6ab40d0..0000000
--- a/EPPlus/DataValidation/Contracts/IExcelDataValidationDateTime.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-namespace OfficeOpenXml.DataValidation.Contracts;
-
-/// <summary>
-/// Validation interface for datetime validations
-/// </summary>
-public interface IExcelDataValidationDateTime
-    : IExcelDataValidationWithFormula2<IExcelDataValidationFormulaDateTime>,
-      IExcelDataValidationWithOperator {}
diff --git a/EPPlus/DataValidation/Contracts/IExcelDataValidationDecimal.cs b/EPPlus/DataValidation/Contracts/IExcelDataValidationDecimal.cs
deleted file mode 100644
index 48983ed..0000000
--- a/EPPlus/DataValidation/Contracts/IExcelDataValidationDecimal.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-namespace OfficeOpenXml.DataValidation.Contracts;
-
-/// <summary>
-/// Data validation interface for decimal values
-/// </summary>
-public interface IExcelDataValidationDecimal
-    : IExcelDataValidationWithFormula2<IExcelDataValidationFormulaDecimal>,
-      IExcelDataValidationWithOperator {}
diff --git a/EPPlus/DataValidation/Contracts/IExcelDataValidationInt.cs b/EPPlus/DataValidation/Contracts/IExcelDataValidationInt.cs
deleted file mode 100644
index 9d984e2..0000000
--- a/EPPlus/DataValidation/Contracts/IExcelDataValidationInt.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-namespace OfficeOpenXml.DataValidation.Contracts;
-
-public interface IExcelDataValidationInt
-    : IExcelDataValidationWithFormula2<IExcelDataValidationFormulaInt>,
-      IExcelDataValidationWithOperator {}
diff --git a/EPPlus/DataValidation/Contracts/IExcelDataValidationList.cs b/EPPlus/DataValidation/Contracts/IExcelDataValidationList.cs
deleted file mode 100644
index 13bb5a9..0000000
--- a/EPPlus/DataValidation/Contracts/IExcelDataValidationList.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-namespace OfficeOpenXml.DataValidation.Contracts;
-
-public interface IExcelDataValidationList
-    : IExcelDataValidationWithFormula<IExcelDataValidationFormulaList> {}
diff --git a/EPPlus/DataValidation/Contracts/IExcelDataValidationTime.cs b/EPPlus/DataValidation/Contracts/IExcelDataValidationTime.cs
deleted file mode 100644
index 4c57587..0000000
--- a/EPPlus/DataValidation/Contracts/IExcelDataValidationTime.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-namespace OfficeOpenXml.DataValidation.Contracts;
-
-/// <summary>
-/// Data validation interface for time validation.
-/// </summary>
-public interface IExcelDataValidationTime
-    : IExcelDataValidationWithFormula2<IExcelDataValidationFormulaTime>,
-      IExcelDataValidationWithOperator {}
diff --git a/EPPlus/DataValidation/Contracts/IExcelDataValidationWithFormula.cs b/EPPlus/DataValidation/Contracts/IExcelDataValidationWithFormula.cs
deleted file mode 100644
index b93dd30..0000000
--- a/EPPlus/DataValidation/Contracts/IExcelDataValidationWithFormula.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-namespace OfficeOpenXml.DataValidation.Contracts;
-
-public interface IExcelDataValidationWithFormula<T> : IExcelDataValidation
-    where T : IExcelDataValidationFormula {
-  T Formula { get; }
-}
diff --git a/EPPlus/DataValidation/Contracts/IExcelDataValidationWithFormula2.cs b/EPPlus/DataValidation/Contracts/IExcelDataValidationWithFormula2.cs
deleted file mode 100644
index 2f6692b..0000000
--- a/EPPlus/DataValidation/Contracts/IExcelDataValidationWithFormula2.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-namespace OfficeOpenXml.DataValidation.Contracts;
-
-/// <summary>
-/// Interface for a data validation with two formulas
-/// </summary>
-/// <typeparam name="T"></typeparam>
-public interface IExcelDataValidationWithFormula2<T> : IExcelDataValidationWithFormula<T>
-    where T : IExcelDataValidationFormula {
-  /// <summary>
-  /// Formula 2
-  /// </summary>
-  T Formula2 { get; }
-}
diff --git a/EPPlus/DataValidation/Contracts/IExcelDataValidationWithOperator.cs b/EPPlus/DataValidation/Contracts/IExcelDataValidationWithOperator.cs
deleted file mode 100644
index 2604079..0000000
--- a/EPPlus/DataValidation/Contracts/IExcelDataValidationWithOperator.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-namespace OfficeOpenXml.DataValidation.Contracts;
-
-/// <summary>
-/// Represents a validation with an operator
-/// </summary>
-public interface IExcelDataValidationWithOperator {
-  /// <summary>
-  /// Operator type
-  /// </summary>
-  ExcelDataValidationOperator Operator { get; }
-}
diff --git a/EPPlus/DataValidation/ExcelDataValidation.cs b/EPPlus/DataValidation/ExcelDataValidation.cs
deleted file mode 100644
index 1e5f445..0000000
--- a/EPPlus/DataValidation/ExcelDataValidation.cs
+++ /dev/null
@@ -1,285 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-01
- * Jan Källman		                License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using System;
-using System.Collections.Immutable;
-using System.Globalization;
-using System.Text.RegularExpressions;
-using System.Xml;
-using OfficeOpenXml.DataValidation.Contracts;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.DataValidation;
-
-/// <summary>
-/// Excel datavalidation
-/// </summary>
-public abstract class ExcelDataValidation : XmlHelper, IExcelDataValidation {
-  private const string _itemElementNodeName = "d:dataValidation";
-
-  private readonly string _errorStylePath = "@errorStyle";
-  private readonly string _errorTitlePath = "@errorTitle";
-  private readonly string _errorPath = "@error";
-  private readonly string _promptTitlePath = "@promptTitle";
-  private readonly string _promptPath = "@prompt";
-  private readonly string _operatorPath = "@operator";
-  private readonly string _showErrorMessagePath = "@showErrorMessage";
-  private readonly string _showInputMessagePath = "@showInputMessage";
-  private readonly string _typeMessagePath = "@type";
-  private readonly string _sqrefPath = "@sqref";
-  private readonly string _allowBlankPath = "@allowBlank";
-  protected readonly string _formula1Path = "d:formula1";
-  protected readonly string _formula2Path = "d:formula2";
-
-  protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
-    "type",
-    "errorStyle",
-    "operator",
-    "allowBlank",
-    "showInputMessage",
-    "showErrorMessage",
-    "errorTitle",
-    "error",
-    "promptTitle",
-    "prompt",
-    "sqref",
-    "formula1",
-    "formula2",
-  ];
-
-  internal ExcelDataValidation(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType)
-      : this(worksheet, address, validationType, null) {}
-
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet">worksheet that owns the validation</param>
-  /// <param name="itemElementNode">Xml top node (dataValidations)</param>
-  /// <param name="validationType">Data validation type</param>
-  /// <param name="address">address for data validation</param>
-  internal ExcelDataValidation(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType,
-      XmlNode itemElementNode)
-      : this(worksheet, address, validationType, itemElementNode, null) {}
-
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet">worksheet that owns the validation</param>
-  /// <param name="itemElementNode">Xml top node (dataValidations) when importing xml</param>
-  /// <param name="validationType">Data validation type</param>
-  /// <param name="address">address for data validation</param>
-  /// <param name="namespaceManager">Xml Namespace manager</param>
-  internal ExcelDataValidation(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(namespaceManager ?? worksheet.NameSpaceManager) {
-    Require.Argument(address).IsNotNullOrEmpty("address");
-    address = CheckAndFixRangeAddress(address);
-    if (itemElementNode == null) {
-      //var xmlDoc = worksheet.WorksheetXml;
-      TopNode = worksheet.WorksheetXml.SelectSingleNode(
-          "//d:dataValidations",
-          worksheet.NameSpaceManager);
-      // did not succeed using the XmlHelper methods here... so I'm creating the new node using XmlDocument...
-      var nsUri = NameSpaceManager.LookupNamespace("d");
-      //itemElementNode = TopNode.OwnerDocument.CreateElement(_itemElementNodeName, nsUri);
-      itemElementNode = TopNode.OwnerDocument.CreateElement(
-          _itemElementNodeName.Split(':')[1],
-          nsUri);
-      TopNode.AppendChild(itemElementNode);
-    }
-    TopNode = itemElementNode;
-    ValidationType = validationType;
-    Address = new(address);
-  }
-
-  private string CheckAndFixRangeAddress(string address) {
-    if (address.Contains(',')) {
-      throw new FormatException("Multiple addresses may not be commaseparated, use space instead");
-    }
-    address = address.ToUpper(CultureInfo.InvariantCulture);
-    if (Regex.IsMatch(address, "[A-Z]+:[A-Z]+")) {
-      address = AddressUtility.ParseEntireColumnSelections(address);
-    }
-    return address;
-  }
-
-  private void SetNullableBoolValue(string path, bool? val) {
-    if (val.HasValue) {
-      SetXmlNodeBool(path, val.Value);
-    } else {
-      DeleteNode(path);
-    }
-  }
-
-  /// <summary>
-  /// This method will validate the state of the validation
-  /// </summary>
-  /// <exception cref="InvalidOperationException">If the state breaks the rules of the validation</exception>
-  public virtual void Validate() {
-    var address = Address.Address;
-    // validate Formula1
-    if (string.IsNullOrEmpty(Formula1Internal)) {
-      throw new InvalidOperationException(
-          "Validation of " + address + " failed: Formula1 cannot be empty");
-    }
-  }
-
-  /// <summary>
-  /// True if the validation type allows operator to be set.
-  /// </summary>
-  public bool AllowsOperator => ValidationType.AllowOperator;
-
-  /// <summary>
-  /// Address of data validation
-  /// </summary>
-  public ExcelAddress Address {
-    get => new(GetXmlNodeString(_sqrefPath));
-    private set {
-      var address = AddressUtility.ParseEntireColumnSelections(value.Address);
-      SetXmlNodeString(_sqrefPath, address);
-    }
-  }
-
-  /// <summary>
-  /// Validation type
-  /// </summary>
-  public ExcelDataValidationType ValidationType {
-    get {
-      var typeString = GetXmlNodeString(_typeMessagePath);
-      return ExcelDataValidationType.GetBySchemaName(typeString);
-    }
-    private set => SetXmlNodeString(_typeMessagePath, value.SchemaName, true);
-  }
-
-  /// <summary>
-  /// Operator for comparison between the entered value and Formula/Formulas.
-  /// </summary>
-  public ExcelDataValidationOperator Operator {
-    get {
-      var operatorString = GetXmlNodeString(_operatorPath);
-      return Enum.TryParse<ExcelDataValidationOperator>(operatorString, true, out var op)
-          ? op
-          : ExcelDataValidationOperator.Any;
-    }
-  }
-
-  /// <summary>
-  /// Warning style
-  /// </summary>
-  public ExcelDataValidationWarningStyle ErrorStyle {
-    get {
-      var errorStyleString = GetXmlNodeString(_errorStylePath);
-      return Enum.TryParse<ExcelDataValidationWarningStyle>(errorStyleString, true, out var style)
-          ? style
-          : ExcelDataValidationWarningStyle.Undefined;
-    }
-  }
-
-  /// <summary>
-  /// True if blanks should be allowed
-  /// </summary>
-  public bool? AllowBlank {
-    get => GetXmlNodeBoolNullable(_allowBlankPath);
-    set => SetNullableBoolValue(_allowBlankPath, value);
-  }
-
-  /// <summary>
-  /// True if input message should be shown
-  /// </summary>
-  public bool? ShowInputMessage {
-    get => GetXmlNodeBoolNullable(_showInputMessagePath);
-    set => SetNullableBoolValue(_showInputMessagePath, value);
-  }
-
-  /// <summary>
-  /// True if error message should be shown
-  /// </summary>
-  public bool? ShowErrorMessage {
-    get => GetXmlNodeBoolNullable(_showErrorMessagePath);
-    set => SetNullableBoolValue(_showErrorMessagePath, value);
-  }
-
-  /// <summary>
-  /// Title of error message box
-  /// </summary>
-  public string ErrorTitle {
-    get => GetXmlNodeString(_errorTitlePath);
-    set => SetXmlNodeString(_errorTitlePath, value);
-  }
-
-  /// <summary>
-  /// Error message box text
-  /// </summary>
-  public string Error {
-    get => GetXmlNodeString(_errorPath);
-    set => SetXmlNodeString(_errorPath, value);
-  }
-
-  public string PromptTitle {
-    get => GetXmlNodeString(_promptTitlePath);
-    set => SetXmlNodeString(_promptTitlePath, value);
-  }
-
-  public string Prompt {
-    get => GetXmlNodeString(_promptPath);
-    set => SetXmlNodeString(_promptPath, value);
-  }
-
-  /// <summary>
-  /// Formula 1
-  /// </summary>
-  protected string Formula1Internal => GetXmlNodeString(_formula1Path);
-
-  /// <summary>
-  /// Formula 2
-  /// </summary>
-  protected string Formula2Internal => GetXmlNodeString(_formula2Path);
-
-  protected void SetValue<T>(T? val, string path)
-      where T : struct {
-    if (!val.HasValue) {
-      DeleteNode(path);
-    }
-    var stringValue = val.Value.ToString().Replace(',', '.');
-    SetXmlNodeString(path, stringValue);
-  }
-}
diff --git a/EPPlus/DataValidation/ExcelDataValidationAny.cs b/EPPlus/DataValidation/ExcelDataValidationAny.cs
deleted file mode 100644
index 8d00268..0000000
--- a/EPPlus/DataValidation/ExcelDataValidationAny.cs
+++ /dev/null
@@ -1,87 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Raziq York   		            Added       		        2014-08-08
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.DataValidation.Contracts;
-
-namespace OfficeOpenXml.DataValidation;
-
-/// <summary>
-/// Any value validation.
-/// </summary>
-public class ExcelDataValidationAny : ExcelDataValidation, IExcelDataValidationAny {
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet"></param>
-  /// <param name="address"></param>
-  /// <param name="validationType"></param>
-  internal ExcelDataValidationAny(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType)
-      : base(worksheet, address, validationType) {}
-
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet"></param>
-  /// <param name="address"></param>
-  /// <param name="validationType"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelDataValidationAny(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType,
-      XmlNode itemElementNode)
-      : base(worksheet, address, validationType, itemElementNode) {}
-
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet"></param>
-  /// <param name="address"></param>
-  /// <param name="validationType"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelDataValidationAny(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(worksheet, address, validationType, itemElementNode, namespaceManager) {}
-
-  /// <summary>
-  /// This method will validate the state of the validation
-  /// </summary>
-  public override void Validate() {}
-}
diff --git a/EPPlus/DataValidation/ExcelDataValidationCollection.cs b/EPPlus/DataValidation/ExcelDataValidationCollection.cs
deleted file mode 100644
index 3c186a5..0000000
--- a/EPPlus/DataValidation/ExcelDataValidationCollection.cs
+++ /dev/null
@@ -1,361 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-01
- * Mats Alm                         Applying patch submitted    2011-11-14
- *                                  by Ted Heatherington
- * Jan Källman		                License changed GPL-->LGPL  2011-12-27
- * Raziq York		                Added support for Any type  2014-08-08
-*******************************************************************************/
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Xml;
-using OfficeOpenXml.DataValidation.Contracts;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.DataValidation;
-
-/// <summary>
-/// <para>
-/// Collection of <see cref="ExcelDataValidation"/>. This class is providing the API for EPPlus data validation.
-/// </para>
-/// <para>
-/// The public methods of this class (Add[...]Validation) will create a datavalidation entry in the worksheet. When this
-/// validation has been created changes to the properties will affect the workbook immediately.
-/// </para>
-/// <para>
-/// Each type of validation has either a formula or a typed value/values, except for custom validation which has a formula only.
-/// </para>
-/// <code>
-/// // Add a date time validation
-/// var validation = worksheet.DataValidation.AddDateTimeValidation("A1");
-/// // set validation properties
-/// validation.ShowErrorMessage = true;
-/// validation.ErrorTitle = "An invalid date was entered";
-/// validation.Error = "The date must be between 2011-01-31 and 2011-12-31";
-/// validation.Prompt = "Enter date here";
-/// validation.Formula.Value = DateTime.Parse("2011-01-01");
-/// validation.Formula2.Value = DateTime.Parse("2011-12-31");
-/// validation.Operator = ExcelDataValidationOperator.between;
-/// </code>
-/// </summary>
-public class ExcelDataValidationCollection : XmlHelper, IEnumerable<IExcelDataValidation> {
-  private readonly List<IExcelDataValidation> _validations = new();
-  private readonly ExcelWorksheet _worksheet;
-
-  private const string _dataValidationPath = "//d:dataValidations";
-  private readonly string DataValidationItemsPath = string.Format(
-      "{0}/d:dataValidation",
-      _dataValidationPath);
-
-  protected override ImmutableArray<string> SchemaNodeOrder =>
-    ExcelWorksheet.WorksheetSchemaNodeOrder;
-
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet"></param>
-  internal ExcelDataValidationCollection(ExcelWorksheet worksheet)
-      : base(worksheet.NameSpaceManager, worksheet.WorksheetXml.DocumentElement) {
-    Require.Argument(worksheet).IsNotNull("worksheet");
-    _worksheet = worksheet;
-
-    // check existing nodes and load them
-    var dataValidationNodes = worksheet.WorksheetXml.SelectNodes(
-        DataValidationItemsPath,
-        worksheet.NameSpaceManager);
-    if (dataValidationNodes != null && dataValidationNodes.Count > 0) {
-      foreach (XmlNode node in dataValidationNodes) {
-        if (node.Attributes["sqref"] == null) {
-          continue;
-        }
-
-        var addr = node.Attributes["sqref"].Value;
-
-        var typeSchema = node.Attributes["type"] != null ? node.Attributes["type"].Value : "";
-
-        var type = ExcelDataValidationType.GetBySchemaName(typeSchema);
-        _validations.Add(ExcelDataValidationFactory.Create(type, worksheet, addr, node));
-      }
-    }
-  }
-
-  private void EnsureRootElementExists() {
-    var node = _worksheet.WorksheetXml.SelectSingleNode(
-        _dataValidationPath,
-        _worksheet.NameSpaceManager);
-    if (node == null) {
-      CreateNode(_dataValidationPath.TrimStart('/'));
-    }
-  }
-
-  /// <summary>
-  /// Validates address - not empty, collisions
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="validatingValidation"></param>
-  private void ValidateAddress(string address, IExcelDataValidation validatingValidation) {
-    Require.Argument(address).IsNotNullOrEmpty("address");
-
-    // ensure that the new address does not collide with an existing validation.
-    var newAddress = new ExcelAddress(address);
-    if (_validations.Count > 0) {
-      foreach (var validation in _validations) {
-        if (validatingValidation != null && validatingValidation == validation) {
-          continue;
-        }
-        var result = validation.Address.Collide(newAddress);
-        if (result != ExcelAddressBase.eAddressCollition.No) {
-          throw new InvalidOperationException(
-              string.Format(
-                  "The address ({0}) collides with an existing validation ({1})",
-                  address,
-                  validation.Address.Address));
-        }
-      }
-    }
-  }
-
-  private void ValidateAddress(string address) {
-    ValidateAddress(address, null);
-  }
-
-  /// <summary>
-  /// Validates all data validations.
-  /// </summary>
-  internal void ValidateAll() {
-    foreach (var validation in _validations) {
-      validation.Validate();
-
-      ValidateAddress(validation.Address.Address, validation);
-    }
-  }
-
-  /// <summary>
-  /// Adds a <see cref="ExcelDataValidationAny"/> to the worksheet.
-  /// </summary>
-  /// <param name="address">The range/address to validate</param>
-  /// <returns></returns>
-  public IExcelDataValidationAny AddAnyValidation(string address) {
-    ValidateAddress(address);
-    EnsureRootElementExists();
-    var item = new ExcelDataValidationAny(_worksheet, address, ExcelDataValidationType.Any);
-    _validations.Add(item);
-    return item;
-  }
-
-  /// <summary>
-  /// Adds an <see cref="IExcelDataValidationInt"/> to the worksheet. Whole means that the only accepted values
-  /// are integer values.
-  /// </summary>
-  /// <param name="address">the range/address to validate</param>
-  public IExcelDataValidationInt AddIntegerValidation(string address) {
-    ValidateAddress(address);
-    EnsureRootElementExists();
-    var item = new ExcelDataValidationInt(_worksheet, address, ExcelDataValidationType.Whole);
-    _validations.Add(item);
-    return item;
-  }
-
-  /// <summary>
-  /// Addes an <see cref="IExcelDataValidationDecimal"/> to the worksheet. The only accepted values are
-  /// decimal values.
-  /// </summary>
-  /// <param name="address">The range/address to validate</param>
-  /// <returns></returns>
-  public IExcelDataValidationDecimal AddDecimalValidation(string address) {
-    ValidateAddress(address);
-    EnsureRootElementExists();
-    var item = new ExcelDataValidationDecimal(_worksheet, address, ExcelDataValidationType.Decimal);
-    _validations.Add(item);
-    return item;
-  }
-
-  /// <summary>
-  /// Adds an <see cref="IExcelDataValidationList"/> to the worksheet. The accepted values are defined
-  /// in a list.
-  /// </summary>
-  /// <param name="address">The range/address to validate</param>
-  /// <returns></returns>
-  public IExcelDataValidationList AddListValidation(string address) {
-    ValidateAddress(address);
-    EnsureRootElementExists();
-    var item = new ExcelDataValidationList(_worksheet, address, ExcelDataValidationType.List);
-    _validations.Add(item);
-    return item;
-  }
-
-  /// <summary>
-  /// Adds an <see cref="IExcelDataValidationInt"/> regarding text length to the worksheet.
-  /// </summary>
-  /// <param name="address">The range/address to validate</param>
-  /// <returns></returns>
-  public IExcelDataValidationInt AddTextLengthValidation(string address) {
-    ValidateAddress(address);
-    EnsureRootElementExists();
-    var item = new ExcelDataValidationInt(_worksheet, address, ExcelDataValidationType.TextLength);
-    _validations.Add(item);
-    return item;
-  }
-
-  /// <summary>
-  /// Adds an <see cref="IExcelDataValidationDateTime"/> to the worksheet.
-  /// </summary>
-  /// <param name="address">The range/address to validate</param>
-  /// <returns></returns>
-  public IExcelDataValidationDateTime AddDateTimeValidation(string address) {
-    ValidateAddress(address);
-    EnsureRootElementExists();
-    var item = new ExcelDataValidationDateTime(
-        _worksheet,
-        address,
-        ExcelDataValidationType.DateTime);
-    _validations.Add(item);
-    return item;
-  }
-
-  public IExcelDataValidationTime AddTimeValidation(string address) {
-    ValidateAddress(address);
-    EnsureRootElementExists();
-    var item = new ExcelDataValidationTime(_worksheet, address, ExcelDataValidationType.Time);
-    _validations.Add(item);
-    return item;
-  }
-
-  /// <summary>
-  /// Adds a <see cref="ExcelDataValidationCustom"/> to the worksheet.
-  /// </summary>
-  /// <param name="address">The range/address to validate</param>
-  /// <returns></returns>
-  public IExcelDataValidationCustom AddCustomValidation(string address) {
-    ValidateAddress(address);
-    EnsureRootElementExists();
-    var item = new ExcelDataValidationCustom(_worksheet, address, ExcelDataValidationType.Custom);
-    _validations.Add(item);
-    return item;
-  }
-
-  /// <summary>
-  /// Removes an <see cref="ExcelDataValidation"/> from the collection.
-  /// </summary>
-  /// <param name="item">The item to remove</param>
-  /// <returns>True if remove succeeds, otherwise false</returns>
-  /// <exception cref="ArgumentNullException">if <paramref name="item"/> is null</exception>
-  public bool Remove(IExcelDataValidation item) {
-    if (!(item is ExcelDataValidation validation)) {
-      throw new InvalidCastException(
-          "The supplied item must inherit OfficeOpenXml.DataValidation.ExcelDataValidation");
-    }
-    Require.Argument(item).IsNotNull("item");
-    TopNode.RemoveChild(validation.TopNode);
-    return _validations.Remove(validation);
-  }
-
-  /// <summary>
-  /// Number of validations
-  /// </summary>
-  public int Count => _validations.Count;
-
-  /// <summary>
-  /// Index operator, returns by 0-based index
-  /// </summary>
-  /// <param name="index"></param>
-  /// <returns></returns>
-  public IExcelDataValidation this[int index] {
-    get => _validations[index];
-    set => _validations[index] = value;
-  }
-
-  /// <summary>
-  /// Index operator, returns a data validation which address partly or exactly matches the searched address.
-  /// </summary>
-  /// <param name="address">A cell address or range</param>
-  /// <returns>A <see cref="ExcelDataValidation"/> or null if no match</returns>
-  public IExcelDataValidation this[string address] {
-    get {
-      var searchedAddress = new ExcelAddress(address);
-      return _validations.Find(x =>
-          x.Address.Collide(searchedAddress) != ExcelAddressBase.eAddressCollition.No);
-    }
-  }
-
-  /// <summary>
-  /// Returns all validations that matches the supplied predicate <paramref name="match"/>.
-  /// </summary>
-  /// <param name="match">predicate to filter out matching validations</param>
-  /// <returns></returns>
-  public IEnumerable<IExcelDataValidation> FindAll(Predicate<IExcelDataValidation> match) {
-    return _validations.FindAll(match);
-  }
-
-  /// <summary>
-  /// Returns the first matching validation.
-  /// </summary>
-  /// <param name="match"></param>
-  /// <returns></returns>
-  public IExcelDataValidation Find(Predicate<IExcelDataValidation> match) {
-    return _validations.Find(match);
-  }
-
-  /// <summary>
-  /// Removes all validations from the collection.
-  /// </summary>
-  public void Clear() {
-    DeleteAllNode(DataValidationItemsPath.TrimStart('/'));
-    _validations.Clear();
-  }
-
-  /// <summary>
-  /// Removes the validations that matches the predicate
-  /// </summary>
-  /// <param name="match"></param>
-  public void RemoveAll(Predicate<IExcelDataValidation> match) {
-    var matches = _validations.FindAll(match);
-    foreach (var m in matches) {
-      if (!(m is ExcelDataValidation validation)) {
-        throw new InvalidCastException(
-            "The supplied item must inherit OfficeOpenXml.DataValidation.ExcelDataValidation");
-      }
-      TopNode
-          .SelectSingleNode(_dataValidationPath.TrimStart('/'), NameSpaceManager)
-          .RemoveChild(validation.TopNode);
-    }
-    _validations.RemoveAll(match);
-  }
-
-  IEnumerator<IExcelDataValidation> IEnumerable<IExcelDataValidation>.GetEnumerator() {
-    return _validations.GetEnumerator();
-  }
-
-  IEnumerator IEnumerable.GetEnumerator() {
-    return _validations.GetEnumerator();
-  }
-}
diff --git a/EPPlus/DataValidation/ExcelDataValidationCustom.cs b/EPPlus/DataValidation/ExcelDataValidationCustom.cs
deleted file mode 100644
index f98b2f6..0000000
--- a/EPPlus/DataValidation/ExcelDataValidationCustom.cs
+++ /dev/null
@@ -1,93 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-01
- * Jan Källman		                License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.DataValidation.Contracts;
-using OfficeOpenXml.DataValidation.Formulas;
-using OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-namespace OfficeOpenXml.DataValidation;
-
-/// <summary>
-/// Custom validation, i.e. a formula.
-/// </summary>
-public class ExcelDataValidationCustom
-    : ExcelDataValidationWithFormula<IExcelDataValidationFormula>,
-      IExcelDataValidationCustom {
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet"></param>
-  /// <param name="address"></param>
-  /// <param name="validationType"></param>
-  internal ExcelDataValidationCustom(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType)
-      : base(worksheet, address, validationType) {
-    Formula = new ExcelDataValidationFormulaCustom(NameSpaceManager, TopNode, _formula1Path);
-  }
-
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet"></param>
-  /// <param name="address"></param>
-  /// <param name="validationType"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelDataValidationCustom(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType,
-      XmlNode itemElementNode)
-      : base(worksheet, address, validationType, itemElementNode) {
-    Formula = new ExcelDataValidationFormulaCustom(NameSpaceManager, TopNode, _formula1Path);
-  }
-
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet"></param>
-  /// <param name="address"></param>
-  /// <param name="validationType"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelDataValidationCustom(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(worksheet, address, validationType, itemElementNode, namespaceManager) {
-    Formula = new ExcelDataValidationFormulaCustom(NameSpaceManager, TopNode, _formula1Path);
-  }
-}
diff --git a/EPPlus/DataValidation/ExcelDataValidationDateTime.cs b/EPPlus/DataValidation/ExcelDataValidationDateTime.cs
deleted file mode 100644
index c72a83d..0000000
--- a/EPPlus/DataValidation/ExcelDataValidationDateTime.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-01
- * Jan Källman		                License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using System;
-using System.Xml;
-using OfficeOpenXml.DataValidation.Contracts;
-using OfficeOpenXml.DataValidation.Formulas;
-using OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-namespace OfficeOpenXml.DataValidation;
-
-/// <summary>
-/// Validation for <see cref="DateTime"/>.
-/// </summary>
-public class ExcelDataValidationDateTime
-    : ExcelDataValidationWithFormula2<IExcelDataValidationFormulaDateTime>,
-      IExcelDataValidationDateTime {
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet"></param>
-  /// <param name="address"></param>
-  /// <param name="validationType"></param>
-  internal ExcelDataValidationDateTime(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType)
-      : base(worksheet, address, validationType) {
-    Formula = new ExcelDataValidationFormulaDateTime(NameSpaceManager, TopNode, _formula1Path);
-    Formula2 = new ExcelDataValidationFormulaDateTime(NameSpaceManager, TopNode, _formula2Path);
-  }
-
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet"></param>
-  /// <param name="address"></param>
-  /// <param name="validationType"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelDataValidationDateTime(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType,
-      XmlNode itemElementNode)
-      : base(worksheet, address, validationType, itemElementNode) {
-    Formula = new ExcelDataValidationFormulaDateTime(NameSpaceManager, TopNode, _formula1Path);
-    Formula2 = new ExcelDataValidationFormulaDateTime(NameSpaceManager, TopNode, _formula2Path);
-  }
-
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet"></param>
-  /// <param name="address"></param>
-  /// <param name="validationType"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelDataValidationDateTime(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(worksheet, address, validationType, itemElementNode, namespaceManager) {
-    Formula = new ExcelDataValidationFormulaDateTime(NameSpaceManager, TopNode, _formula1Path);
-    Formula2 = new ExcelDataValidationFormulaDateTime(NameSpaceManager, TopNode, _formula2Path);
-  }
-}
diff --git a/EPPlus/DataValidation/ExcelDataValidationDecimal.cs b/EPPlus/DataValidation/ExcelDataValidationDecimal.cs
deleted file mode 100644
index 1e8e8af..0000000
--- a/EPPlus/DataValidation/ExcelDataValidationDecimal.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-01
- * Jan Källman		                License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.DataValidation.Contracts;
-using OfficeOpenXml.DataValidation.Formulas;
-using OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-namespace OfficeOpenXml.DataValidation;
-
-/// <summary>
-/// Data validation for decimal values
-/// </summary>
-public class ExcelDataValidationDecimal
-    : ExcelDataValidationWithFormula2<IExcelDataValidationFormulaDecimal>,
-      IExcelDataValidationDecimal {
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet"></param>
-  /// <param name="address"></param>
-  /// <param name="validationType"></param>
-  internal ExcelDataValidationDecimal(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType)
-      : base(worksheet, address, validationType) {
-    Formula = new ExcelDataValidationFormulaDecimal(NameSpaceManager, TopNode, _formula1Path);
-    Formula2 = new ExcelDataValidationFormulaDecimal(NameSpaceManager, TopNode, _formula2Path);
-  }
-
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet"></param>
-  /// <param name="address"></param>
-  /// <param name="validationType"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelDataValidationDecimal(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType,
-      XmlNode itemElementNode)
-      : base(worksheet, address, validationType, itemElementNode) {
-    Formula = new ExcelDataValidationFormulaDecimal(NameSpaceManager, TopNode, _formula1Path);
-    Formula2 = new ExcelDataValidationFormulaDecimal(NameSpaceManager, TopNode, _formula2Path);
-  }
-
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet"></param>
-  /// <param name="address"></param>
-  /// <param name="validationType"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager">For test purposes</param>
-  internal ExcelDataValidationDecimal(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(worksheet, address, validationType, itemElementNode, namespaceManager) {
-    Formula = new ExcelDataValidationFormulaDecimal(NameSpaceManager, TopNode, _formula1Path);
-    Formula2 = new ExcelDataValidationFormulaDecimal(NameSpaceManager, TopNode, _formula2Path);
-  }
-}
diff --git a/EPPlus/DataValidation/ExcelDataValidationFactory.cs b/EPPlus/DataValidation/ExcelDataValidationFactory.cs
deleted file mode 100644
index 86dcba6..0000000
--- a/EPPlus/DataValidation/ExcelDataValidationFactory.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-01
- * Jan Källman		                License changed GPL-->LGPL  2011-12-27
- * Raziq York 		                Added support for Any type  2014-08-08
- *******************************************************************************/
-
-using System;
-using System.Xml;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.DataValidation;
-
-/// <summary>
-/// Factory class for ExcelDataValidation.
-/// </summary>
-internal static class ExcelDataValidationFactory {
-  /// <summary>
-  /// Creates an instance of <see cref="ExcelDataValidation"/> out of the given parameters.
-  /// </summary>
-  /// <param name="type"></param>
-  /// <param name="worksheet"></param>
-  /// <param name="address"></param>
-  /// <param name="itemElementNode"></param>
-  /// <returns></returns>
-  public static ExcelDataValidation Create(
-      ExcelDataValidationType type,
-      ExcelWorksheet worksheet,
-      string address,
-      XmlNode itemElementNode) {
-    Require.Argument(type).IsNotNull("validationType");
-    switch (type.Type) {
-      case eDataValidationType.Any:
-        return new ExcelDataValidationAny(worksheet, address, type, itemElementNode);
-      case eDataValidationType.TextLength:
-      case eDataValidationType.Whole:
-        return new ExcelDataValidationInt(worksheet, address, type, itemElementNode);
-      case eDataValidationType.Decimal:
-        return new ExcelDataValidationDecimal(worksheet, address, type, itemElementNode);
-      case eDataValidationType.List:
-        return new ExcelDataValidationList(worksheet, address, type, itemElementNode);
-      case eDataValidationType.DateTime:
-        return new ExcelDataValidationDateTime(worksheet, address, type, itemElementNode);
-      case eDataValidationType.Time:
-        return new ExcelDataValidationTime(worksheet, address, type, itemElementNode);
-      case eDataValidationType.Custom:
-        return new ExcelDataValidationCustom(worksheet, address, type, itemElementNode);
-      default:
-        throw new InvalidOperationException("Non supported validationtype: " + type.Type);
-    }
-  }
-}
diff --git a/EPPlus/DataValidation/ExcelDataValidationInt.cs b/EPPlus/DataValidation/ExcelDataValidationInt.cs
deleted file mode 100644
index 12cdb94..0000000
--- a/EPPlus/DataValidation/ExcelDataValidationInt.cs
+++ /dev/null
@@ -1,102 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		                License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.DataValidation.Contracts;
-using OfficeOpenXml.DataValidation.Formulas;
-using OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-namespace OfficeOpenXml.DataValidation;
-
-/// <summary>
-/// Data validation for integer values.
-/// </summary>
-public class ExcelDataValidationInt
-    : ExcelDataValidationWithFormula2<IExcelDataValidationFormulaInt>,
-      IExcelDataValidationInt {
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet"></param>
-  /// <param name="address"></param>
-  /// <param name="validationType"></param>
-  internal ExcelDataValidationInt(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType)
-      : base(worksheet, address, validationType) {
-    Formula = new ExcelDataValidationFormulaInt(worksheet.NameSpaceManager, TopNode, _formula1Path);
-    Formula2 = new ExcelDataValidationFormulaInt(
-        worksheet.NameSpaceManager,
-        TopNode,
-        _formula2Path);
-  }
-
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet"></param>
-  /// <param name="address"></param>
-  /// <param name="validationType"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelDataValidationInt(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType,
-      XmlNode itemElementNode)
-      : base(worksheet, address, validationType, itemElementNode) {
-    Formula = new ExcelDataValidationFormulaInt(worksheet.NameSpaceManager, TopNode, _formula1Path);
-    Formula2 = new ExcelDataValidationFormulaInt(
-        worksheet.NameSpaceManager,
-        TopNode,
-        _formula2Path);
-  }
-
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet"></param>
-  /// <param name="address"></param>
-  /// <param name="validationType"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager">For test purposes</param>
-  internal ExcelDataValidationInt(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(worksheet, address, validationType, itemElementNode, namespaceManager) {
-    Formula = new ExcelDataValidationFormulaInt(NameSpaceManager, TopNode, _formula1Path);
-    Formula2 = new ExcelDataValidationFormulaInt(NameSpaceManager, TopNode, _formula2Path);
-  }
-}
diff --git a/EPPlus/DataValidation/ExcelDataValidationList.cs b/EPPlus/DataValidation/ExcelDataValidationList.cs
deleted file mode 100644
index e9dbdf1..0000000
--- a/EPPlus/DataValidation/ExcelDataValidationList.cs
+++ /dev/null
@@ -1,93 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		                License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.DataValidation.Contracts;
-using OfficeOpenXml.DataValidation.Formulas;
-using OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-namespace OfficeOpenXml.DataValidation;
-
-/// <summary>
-/// This class represents an List data validation.
-/// </summary>
-public class ExcelDataValidationList
-    : ExcelDataValidationWithFormula<IExcelDataValidationFormulaList>,
-      IExcelDataValidationList {
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet"></param>
-  /// <param name="address"></param>
-  /// <param name="validationType"></param>
-  internal ExcelDataValidationList(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType)
-      : base(worksheet, address, validationType) {
-    Formula = new ExcelDataValidationFormulaList(NameSpaceManager, TopNode, _formula1Path);
-  }
-
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet"></param>
-  /// <param name="address"></param>
-  /// <param name="validationType"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelDataValidationList(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType,
-      XmlNode itemElementNode)
-      : base(worksheet, address, validationType, itemElementNode) {
-    Formula = new ExcelDataValidationFormulaList(NameSpaceManager, TopNode, _formula1Path);
-  }
-
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet"></param>
-  /// <param name="address"></param>
-  /// <param name="validationType"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager">Namespace manager, for test purposes</param>
-  internal ExcelDataValidationList(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(worksheet, address, validationType, itemElementNode, namespaceManager) {
-    Formula = new ExcelDataValidationFormulaList(NameSpaceManager, TopNode, _formula1Path);
-  }
-}
diff --git a/EPPlus/DataValidation/ExcelDataValidationOperator.cs b/EPPlus/DataValidation/ExcelDataValidationOperator.cs
deleted file mode 100644
index a6f3fe2..0000000
--- a/EPPlus/DataValidation/ExcelDataValidationOperator.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-01
- * Jan Källman		                License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-namespace OfficeOpenXml.DataValidation;
-
-/// <summary>
-/// Operator for comparison between Formula and Formula2 in a validation.
-/// </summary>
-public enum ExcelDataValidationOperator {
-  Any,
-  Equal,
-  NotEqual,
-  LessThan,
-  LessThanOrEqual,
-  GreaterThan,
-  GreaterThanOrEqual,
-  Between,
-  NotBetween,
-}
diff --git a/EPPlus/DataValidation/ExcelDataValidationTime.cs b/EPPlus/DataValidation/ExcelDataValidationTime.cs
deleted file mode 100644
index 3c37d13..0000000
--- a/EPPlus/DataValidation/ExcelDataValidationTime.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		                License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.DataValidation.Contracts;
-using OfficeOpenXml.DataValidation.Formulas;
-using OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-namespace OfficeOpenXml.DataValidation;
-
-/// <summary>
-/// Validation for times (<see cref="OfficeOpenXml.DataValidation.ExcelTime"/>).
-/// </summary>
-public class ExcelDataValidationTime
-    : ExcelDataValidationWithFormula2<IExcelDataValidationFormulaTime>,
-      IExcelDataValidationTime {
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet"></param>
-  /// <param name="address"></param>
-  /// <param name="validationType"></param>
-  internal ExcelDataValidationTime(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType)
-      : base(worksheet, address, validationType) {
-    Formula = new ExcelDataValidationFormulaTime(NameSpaceManager, TopNode, _formula1Path);
-    Formula2 = new ExcelDataValidationFormulaTime(NameSpaceManager, TopNode, _formula2Path);
-  }
-
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet"></param>
-  /// <param name="address"></param>
-  /// <param name="validationType"></param>
-  /// <param name="itemElementNode"></param>
-  internal ExcelDataValidationTime(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType,
-      XmlNode itemElementNode)
-      : base(worksheet, address, validationType, itemElementNode) {
-    Formula = new ExcelDataValidationFormulaTime(NameSpaceManager, TopNode, _formula1Path);
-    Formula2 = new ExcelDataValidationFormulaTime(NameSpaceManager, TopNode, _formula2Path);
-  }
-
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet"></param>
-  /// <param name="address"></param>
-  /// <param name="validationType"></param>
-  /// <param name="itemElementNode"></param>
-  /// <param name="namespaceManager"></param>
-  internal ExcelDataValidationTime(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(worksheet, address, validationType, itemElementNode, namespaceManager) {
-    Formula = new ExcelDataValidationFormulaTime(NameSpaceManager, TopNode, _formula1Path);
-    Formula2 = new ExcelDataValidationFormulaTime(NameSpaceManager, TopNode, _formula2Path);
-  }
-}
diff --git a/EPPlus/DataValidation/ExcelDataValidationType.cs b/EPPlus/DataValidation/ExcelDataValidationType.cs
deleted file mode 100644
index cdcc99c..0000000
--- a/EPPlus/DataValidation/ExcelDataValidationType.cs
+++ /dev/null
@@ -1,261 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-01
- * Jan Källman		                License changed GPL-->LGPL  2011-12-27
- * Raziq York 		                Added support for Any type  2014-08-08
- *******************************************************************************/
-
-using System;
-
-namespace OfficeOpenXml.DataValidation;
-
-/// <summary>
-/// Enum for available data validation types
-/// </summary>
-public enum eDataValidationType {
-  /// <summary>
-  /// Any value
-  /// </summary>
-  Any,
-
-  /// <summary>
-  /// Integer value
-  /// </summary>
-  Whole,
-
-  /// <summary>
-  /// Decimal values
-  /// </summary>
-  Decimal,
-
-  /// <summary>
-  /// List of values
-  /// </summary>
-  List,
-
-  /// <summary>
-  /// Text length validation
-  /// </summary>
-  TextLength,
-
-  /// <summary>
-  /// DateTime validation
-  /// </summary>
-  DateTime,
-
-  /// <summary>
-  /// Time validation
-  /// </summary>
-  Time,
-
-  /// <summary>
-  /// Custom validation
-  /// </summary>
-  Custom,
-}
-
-internal static class DataValidationSchemaNames {
-  public const string Any = "";
-  public const string Whole = "whole";
-  public const string Decimal = "decimal";
-  public const string List = "list";
-  public const string TextLength = "textLength";
-  public const string Date = "date";
-  public const string Time = "time";
-  public const string Custom = "custom";
-}
-
-/// <summary>
-/// Types of datavalidation
-/// </summary>
-public class ExcelDataValidationType {
-  private ExcelDataValidationType(
-      eDataValidationType validationType,
-      bool allowOperator,
-      string schemaName) {
-    Type = validationType;
-    AllowOperator = allowOperator;
-    SchemaName = schemaName;
-  }
-
-  /// <summary>
-  /// Validation type
-  /// </summary>
-  public eDataValidationType Type { get; private set; }
-
-  internal string SchemaName { get; private set; }
-
-  /// <summary>
-  /// This type allows operator to be set
-  /// </summary>
-  internal bool AllowOperator { get; private set; }
-
-  internal static ExcelDataValidationType GetBySchemaName(string schemaName) {
-    switch (schemaName) {
-      case DataValidationSchemaNames.Any:
-        return Any;
-      case DataValidationSchemaNames.Whole:
-        return Whole;
-      case DataValidationSchemaNames.Decimal:
-        return Decimal;
-      case DataValidationSchemaNames.List:
-        return List;
-      case DataValidationSchemaNames.TextLength:
-        return TextLength;
-      case DataValidationSchemaNames.Date:
-        return DateTime;
-      case DataValidationSchemaNames.Time:
-        return Time;
-      case DataValidationSchemaNames.Custom:
-        return Custom;
-      default:
-        throw new ArgumentException("Invalid schemaname: " + schemaName);
-    }
-  }
-
-  /// <summary>
-  /// Overridden Equals, compares on internal validation type
-  /// </summary>
-  /// <param name="obj"></param>
-  /// <returns></returns>
-  public override bool Equals(object obj) {
-    if (!(obj is ExcelDataValidationType type)) {
-      return false;
-    }
-    return type.Type == Type;
-  }
-
-  /// <summary>
-  /// Overrides GetHashCode()
-  /// </summary>
-  /// <returns></returns>
-  public override int GetHashCode() {
-    return base.GetHashCode();
-  }
-
-  /// <summary>
-  /// Integer values
-  /// </summary>
-  private static ExcelDataValidationType _any;
-
-  public static ExcelDataValidationType Any {
-    get {
-      if (_any == null) {
-        _any = new(eDataValidationType.Any, false, DataValidationSchemaNames.Any);
-      }
-      return _any;
-    }
-  }
-
-  /// <summary>
-  /// Integer values
-  /// </summary>
-  private static ExcelDataValidationType _whole;
-
-  public static ExcelDataValidationType Whole {
-    get {
-      if (_whole == null) {
-        _whole = new(eDataValidationType.Whole, true, DataValidationSchemaNames.Whole);
-      }
-      return _whole;
-    }
-  }
-
-  /// <summary>
-  /// List of allowed values
-  /// </summary>
-  private static ExcelDataValidationType _list;
-
-  public static ExcelDataValidationType List {
-    get {
-      if (_list == null) {
-        _list = new(eDataValidationType.List, false, DataValidationSchemaNames.List);
-      }
-      return _list;
-    }
-  }
-
-  private static ExcelDataValidationType _decimal;
-
-  public static ExcelDataValidationType Decimal {
-    get {
-      if (_decimal == null) {
-        _decimal = new(eDataValidationType.Decimal, true, DataValidationSchemaNames.Decimal);
-      }
-      return _decimal;
-    }
-  }
-
-  private static ExcelDataValidationType _textLength;
-
-  public static ExcelDataValidationType TextLength {
-    get {
-      if (_textLength == null) {
-        _textLength = new(
-            eDataValidationType.TextLength,
-            true,
-            DataValidationSchemaNames.TextLength);
-      }
-      return _textLength;
-    }
-  }
-
-  private static ExcelDataValidationType _dateTime;
-
-  public static ExcelDataValidationType DateTime {
-    get {
-      if (_dateTime == null) {
-        _dateTime = new(eDataValidationType.DateTime, true, DataValidationSchemaNames.Date);
-      }
-      return _dateTime;
-    }
-  }
-
-  private static ExcelDataValidationType _time;
-
-  public static ExcelDataValidationType Time {
-    get {
-      if (_time == null) {
-        _time = new(eDataValidationType.Time, true, DataValidationSchemaNames.Time);
-      }
-      return _time;
-    }
-  }
-
-  private static ExcelDataValidationType _custom;
-
-  public static ExcelDataValidationType Custom {
-    get {
-      if (_custom == null) {
-        _custom = new(eDataValidationType.Custom, true, DataValidationSchemaNames.Custom);
-      }
-      return _custom;
-    }
-  }
-}
diff --git a/EPPlus/DataValidation/ExcelDataValidationWarningStyle.cs b/EPPlus/DataValidation/ExcelDataValidationWarningStyle.cs
deleted file mode 100644
index ae808bb..0000000
--- a/EPPlus/DataValidation/ExcelDataValidationWarningStyle.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-01
- * Jan Källman		                License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-namespace OfficeOpenXml.DataValidation;
-
-/// <summary>
-/// warning style, controls how Excel will handle invalid changes.
-/// </summary>
-public enum ExcelDataValidationWarningStyle {
-  /// <summary>
-  /// warning style will be excluded
-  /// </summary>
-  Undefined,
-
-  /// <summary>
-  /// stop warning style, invalid changes will not be accepted
-  /// </summary>
-  Stop,
-
-  /// <summary>
-  /// warning will be presented when an attempt to an invalid change is done, but the change will be accepted.
-  /// </summary>
-  Warning,
-
-  /// <summary>
-  /// information warning style.
-  /// </summary>
-  Information,
-}
diff --git a/EPPlus/DataValidation/ExcelDataValidationWithFormula.cs b/EPPlus/DataValidation/ExcelDataValidationWithFormula.cs
deleted file mode 100644
index 7c20825..0000000
--- a/EPPlus/DataValidation/ExcelDataValidationWithFormula.cs
+++ /dev/null
@@ -1,104 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-01
- * Jan Källman		                License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using System;
-using System.Xml;
-using OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-namespace OfficeOpenXml.DataValidation;
-
-/// <summary>
-/// A validation containing a formula
-/// </summary>
-/// <typeparam name="T"></typeparam>
-public class ExcelDataValidationWithFormula<T> : ExcelDataValidation
-    where T : IExcelDataValidationFormula {
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet"></param>
-  /// <param name="address"></param>
-  /// <param name="validationType"></param>
-  internal ExcelDataValidationWithFormula(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType)
-      : this(worksheet, address, validationType, null) {}
-
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet">Worksheet that owns the validation</param>
-  /// <param name="itemElementNode">Xml top node (dataValidations)</param>
-  /// <param name="validationType">Data validation type</param>
-  /// <param name="address">address for data validation</param>
-  internal ExcelDataValidationWithFormula(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType,
-      XmlNode itemElementNode)
-      : base(worksheet, address, validationType, itemElementNode) {}
-
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet">Worksheet that owns the validation</param>
-  /// <param name="itemElementNode">Xml top node (dataValidations)</param>
-  /// <param name="validationType">Data validation type</param>
-  /// <param name="address">address for data validation</param>
-  /// <param name="namespaceManager">for test purposes</param>
-  internal ExcelDataValidationWithFormula(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(worksheet, address, validationType, itemElementNode, namespaceManager) {}
-
-  /// <summary>
-  /// Formula - Either a {T} value (except for custom validation) or a spreadsheet formula
-  /// </summary>
-  public T Formula { get; protected set; }
-
-  public override void Validate() {
-    base.Validate();
-    if (Operator == ExcelDataValidationOperator.Between
-        || Operator == ExcelDataValidationOperator.NotBetween) {
-      if (string.IsNullOrEmpty(Formula2Internal)) {
-        throw new InvalidOperationException(
-            "Validation of "
-                + Address.Address
-                + " failed: Formula2 must be set if operator is 'between' or 'notBetween'");
-      }
-    }
-  }
-}
diff --git a/EPPlus/DataValidation/ExcelDataValidationWithFormula2.cs b/EPPlus/DataValidation/ExcelDataValidationWithFormula2.cs
deleted file mode 100644
index 3b9b7c0..0000000
--- a/EPPlus/DataValidation/ExcelDataValidationWithFormula2.cs
+++ /dev/null
@@ -1,86 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-01
- * Jan Källman		                License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-namespace OfficeOpenXml.DataValidation;
-
-public class ExcelDataValidationWithFormula2<T> : ExcelDataValidationWithFormula<T>
-    where T : IExcelDataValidationFormula {
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet"></param>
-  /// <param name="address"></param>
-  /// <param name="validationType"></param>
-  internal ExcelDataValidationWithFormula2(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType)
-      : this(worksheet, address, validationType, null) {}
-
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet">Worksheet that owns the validation</param>
-  /// <param name="itemElementNode">Xml top node (dataValidations)</param>
-  /// <param name="validationType">Data validation type</param>
-  /// <param name="address">address for data validation</param>
-  internal ExcelDataValidationWithFormula2(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType,
-      XmlNode itemElementNode)
-      : base(worksheet, address, validationType, itemElementNode) {}
-
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="worksheet">Worksheet that owns the validation</param>
-  /// <param name="itemElementNode">Xml top node (dataValidations)</param>
-  /// <param name="validationType">Data validation type</param>
-  /// <param name="address">address for data validation</param>
-  /// <param name="namespaceManager">for test purposes</param>
-  internal ExcelDataValidationWithFormula2(
-      ExcelWorksheet worksheet,
-      string address,
-      ExcelDataValidationType validationType,
-      XmlNode itemElementNode,
-      XmlNamespaceManager namespaceManager)
-      : base(worksheet, address, validationType, itemElementNode, namespaceManager) {}
-
-  /// <summary>
-  /// Formula - Either a {T} value or a spreadsheet formula
-  /// </summary>
-  public T Formula2 { get; protected set; }
-}
diff --git a/EPPlus/DataValidation/ExcelTime.cs b/EPPlus/DataValidation/ExcelTime.cs
deleted file mode 100644
index 783eb17..0000000
--- a/EPPlus/DataValidation/ExcelTime.cs
+++ /dev/null
@@ -1,224 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-01
- * Jan Källman		                License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using System;
-using System.Globalization;
-
-namespace OfficeOpenXml.DataValidation;
-
-/// <summary>
-/// Represents a time between 00:00:00 and 23:59:59
-/// </summary>
-public class ExcelTime {
-  private event EventHandler TimeChangedEvent;
-
-  private readonly decimal SecondsPerDay = 3600 * 24;
-  private readonly decimal SecondsPerHour = 3600;
-  private readonly decimal SecondsPerMinute = 60;
-
-  /// <summary>
-  /// Max number of decimals when rounding.
-  /// </summary>
-  public const int NumberOfDecimals = 15;
-
-  /// <summary>
-  /// Default constructor
-  /// </summary>
-  public ExcelTime() {}
-
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="value">An existing time for initialization</param>
-  public ExcelTime(decimal value) {
-    if (value < 0M) {
-      throw new ArgumentException("Value cannot be less than 0");
-    }
-    if (value >= 1M) {
-      throw new ArgumentException("Value cannot be greater or equal to 1");
-    }
-    Init(value);
-  }
-
-  private void Init(decimal value) {
-    // handle hour
-    decimal totalSeconds = value * SecondsPerDay;
-    decimal hour = Math.Floor(totalSeconds / SecondsPerHour);
-    Hour = (int)hour;
-
-    // handle minute
-    decimal remainingSeconds = totalSeconds - (hour * SecondsPerHour);
-    decimal minute = Math.Floor(remainingSeconds / SecondsPerMinute);
-    Minute = (int)minute;
-
-    // handle second
-    remainingSeconds = totalSeconds - (hour * SecondsPerHour) - (minute * SecondsPerMinute);
-    decimal second = Math.Round(remainingSeconds, MidpointRounding.AwayFromZero);
-    // Second might be rounded to 60... the SetSecond method handles that.
-    SetSecond((int)second);
-  }
-
-  /// <summary>
-  /// If we are unlucky second might be rounded up to 60. This will have the minute to be raised and might affect the hour.
-  /// </summary>
-  /// <param name="value"></param>
-  private void SetSecond(int value) {
-    if (value == 60) {
-      Second = 0;
-      var minute = Minute + 1;
-      SetMinute(minute);
-    } else {
-      Second = value;
-    }
-  }
-
-  private void SetMinute(int value) {
-    if (value == 60) {
-      Minute = 0;
-      var hour = Hour + 1;
-      SetHour(hour);
-    } else {
-      Minute = value;
-    }
-  }
-
-  private void SetHour(int value) {
-    if (value == 24) {
-      Hour = 0;
-    }
-  }
-
-  internal event EventHandler TimeChanged {
-    add => TimeChangedEvent += value;
-    remove => TimeChangedEvent -= value;
-  }
-
-  private void OnTimeChanged() {
-    if (TimeChangedEvent != null) {
-      TimeChangedEvent(this, EventArgs.Empty);
-    }
-  }
-
-  private int _hour;
-
-  /// <summary>
-  /// Hour between 0 and 23
-  /// </summary>
-  public int Hour {
-    get => _hour;
-    set {
-      if (value < 0) {
-        throw new InvalidOperationException("Value for hour cannot be negative");
-      }
-      if (value > 23) {
-        throw new InvalidOperationException("Value for hour cannot be greater than 23");
-      }
-      _hour = value;
-      OnTimeChanged();
-    }
-  }
-
-  private int _minute;
-
-  /// <summary>
-  /// Minute between 0 and 59
-  /// </summary>
-  public int Minute {
-    get => _minute;
-    set {
-      if (value < 0) {
-        throw new InvalidOperationException("Value for minute cannot be negative");
-      }
-      if (value > 59) {
-        throw new InvalidOperationException("Value for minute cannot be greater than 59");
-      }
-      _minute = value;
-      OnTimeChanged();
-    }
-  }
-
-  private int? _second;
-
-  /// <summary>
-  /// Second between 0 and 59
-  /// </summary>
-  public int? Second {
-    get => _second;
-    set {
-      if (value < 0) {
-        throw new InvalidOperationException("Value for second cannot be negative");
-      }
-      if (value > 59) {
-        throw new InvalidOperationException("Value for second cannot be greater than 59");
-      }
-      _second = value;
-      OnTimeChanged();
-    }
-  }
-
-  private decimal Round(decimal value) {
-    return Math.Round(value, NumberOfDecimals);
-  }
-
-  private decimal ToSeconds() {
-    var result = Hour * SecondsPerHour;
-    result += Minute * SecondsPerMinute;
-    result += Second ?? 0;
-    return result;
-  }
-
-  /// <summary>
-  /// Returns the excel decimal representation of a time.
-  /// </summary>
-  /// <returns></returns>
-  public decimal ToExcelTime() {
-    var seconds = ToSeconds();
-    return Round(seconds / SecondsPerDay);
-  }
-
-  /// <summary>
-  /// Returns the excel decimal representation of a time as a string.
-  /// </summary>
-  /// <returns></returns>
-  public string ToExcelString() {
-    return ToExcelTime().ToString(CultureInfo.InvariantCulture);
-  }
-
-  public override string ToString() {
-    var second = Second ?? 0;
-    return string.Format(
-        "{0}:{1}:{2}",
-        Hour < 10 ? "0" + Hour : Hour.ToString(),
-        Minute < 10 ? "0" + Minute : Minute.ToString(),
-        second < 10 ? "0" + second : second.ToString());
-  }
-}
diff --git a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormula.cs b/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormula.cs
deleted file mode 100644
index fee785c..0000000
--- a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormula.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-namespace OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-/// <summary>
-/// Interface for a data validation formula
-/// </summary>
-public interface IExcelDataValidationFormula {
-  /// <summary>
-  /// An excel formula
-  /// </summary>
-  string ExcelFormula { get; set; }
-}
diff --git a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaDateTime.cs b/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaDateTime.cs
deleted file mode 100644
index 2cc6df2..0000000
--- a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaDateTime.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using System;
-
-namespace OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-/// <summary>
-/// Validation formula interface for <see cref="DateTime"/>
-/// </summary>
-public interface IExcelDataValidationFormulaDateTime
-    : IExcelDataValidationFormulaWithValue<DateTime?> {}
diff --git a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaDecimal.cs b/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaDecimal.cs
deleted file mode 100644
index 0a87a75..0000000
--- a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaDecimal.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-namespace OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-/// <summary>
-/// Interface for a data validation formula of <see cref="System.Single">float</see> value
-/// </summary>
-public interface IExcelDataValidationFormulaDecimal
-    : IExcelDataValidationFormulaWithValue<double?> {}
diff --git a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaInt.cs b/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaInt.cs
deleted file mode 100644
index 47ecfaa..0000000
--- a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaInt.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-namespace OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-/// <summary>
-/// Interface for a data validation formula of <see cref="System.Int32"/> value
-/// </summary>
-public interface IExcelDataValidationFormulaInt : IExcelDataValidationFormulaWithValue<int?> {}
diff --git a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaList.cs b/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaList.cs
deleted file mode 100644
index 6a799b4..0000000
--- a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaList.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-/// <summary>
-/// Interface for a data validation of list type
-/// </summary>
-public interface IExcelDataValidationFormulaList : IExcelDataValidationFormula {
-  /// <summary>
-  /// A list of value strings.
-  /// </summary>
-  IList<string> Values { get; }
-}
diff --git a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaTime.cs b/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaTime.cs
deleted file mode 100644
index a9f1f5d..0000000
--- a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaTime.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-namespace OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-public interface IExcelDataValidationFormulaTime
-    : IExcelDataValidationFormulaWithValue<ExcelTime> {}
diff --git a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaWithValue.cs b/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaWithValue.cs
deleted file mode 100644
index 21b937b..0000000
--- a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaWithValue.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-namespace OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-/// <summary>
-/// Interface for a formula with a value
-/// </summary>
-/// <typeparam name="T"></typeparam>
-public interface IExcelDataValidationFormulaWithValue<T> : IExcelDataValidationFormula {
-  /// <summary>
-  /// The value.
-  /// </summary>
-  T Value { get; set; }
-}
diff --git a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormula.cs b/EPPlus/DataValidation/Formulas/ExcelDataValidationFormula.cs
deleted file mode 100644
index bbc9819..0000000
--- a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormula.cs
+++ /dev/null
@@ -1,119 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using System;
-using System.Xml;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.DataValidation.Formulas;
-
-/// <summary>
-/// Enumeration representing the state of an <see cref="ExcelDataValidationFormulaValue{T}"/>
-/// </summary>
-internal enum FormulaState {
-  /// <summary>
-  /// Value is set
-  /// </summary>
-  Value,
-
-  /// <summary>
-  /// Formula is set
-  /// </summary>
-  Formula,
-}
-
-/// <summary>
-/// Base class for a formula
-/// </summary>
-internal abstract class ExcelDataValidationFormula : XmlHelper {
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="namespaceManager">Namespacemanger of the worksheet</param>
-  /// <param name="topNode">validation top node</param>
-  /// <param name="formulaPath">xml path of the current formula</param>
-  public ExcelDataValidationFormula(
-      XmlNamespaceManager namespaceManager,
-      XmlNode topNode,
-      string formulaPath)
-      : base(namespaceManager, topNode) {
-    Require.Argument(formulaPath).IsNotNullOrEmpty("formulaPath");
-    FormulaPath = formulaPath;
-  }
-
-  private string _formula;
-
-  protected string FormulaPath { get; private set; }
-
-  /// <summary>
-  /// State of the validationformula, i.e. tells if value or formula is set
-  /// </summary>
-  protected FormulaState State { get; set; }
-
-  /// <summary>
-  /// A formula which output must match the current validation type
-  /// </summary>
-  public string ExcelFormula {
-    get => _formula;
-    set {
-      if (!string.IsNullOrEmpty(value)) {
-        ResetValue();
-        State = FormulaState.Formula;
-      }
-      if (value != null && value.Length > 255) {
-        throw new InvalidOperationException(
-            "The length of a DataValidation formula cannot exceed 255 characters");
-      }
-      //var val = SqRefUtility.ToSqRefAddress(value);
-      _formula = value;
-      SetXmlNodeString(FormulaPath, value);
-    }
-  }
-
-  internal abstract void ResetValue();
-
-  /// <summary>
-  /// This value will be stored in the xml. Can be overridden by subclasses
-  /// </summary>
-  internal virtual string GetXmlValue() {
-    if (State == FormulaState.Formula) {
-      return ExcelFormula;
-    }
-    return GetValueAsString();
-  }
-
-  /// <summary>
-  /// Returns the value as a string. Must be implemented by subclasses
-  /// </summary>
-  /// <returns></returns>
-  protected abstract string GetValueAsString();
-}
diff --git a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaCustom.cs b/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaCustom.cs
deleted file mode 100644
index 1072535..0000000
--- a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaCustom.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-namespace OfficeOpenXml.DataValidation.Formulas;
-
-/// <summary>
-///
-/// </summary>
-internal class ExcelDataValidationFormulaCustom
-    : ExcelDataValidationFormula,
-      IExcelDataValidationFormula {
-  public ExcelDataValidationFormulaCustom(
-      XmlNamespaceManager namespaceManager,
-      XmlNode topNode,
-      string formulaPath)
-      : base(namespaceManager, topNode, formulaPath) {
-    var value = GetXmlNodeString(formulaPath);
-    if (!string.IsNullOrEmpty(value)) {
-      ExcelFormula = value;
-    }
-    State = FormulaState.Formula;
-  }
-
-  internal override string GetXmlValue() {
-    return ExcelFormula;
-  }
-
-  protected override string GetValueAsString() {
-    return ExcelFormula;
-  }
-
-  internal override void ResetValue() {
-    ExcelFormula = null;
-  }
-}
diff --git a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaDateTime.cs b/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaDateTime.cs
deleted file mode 100644
index 3dbc85d..0000000
--- a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaDateTime.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using System;
-using System.Globalization;
-using System.Xml;
-using OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-namespace OfficeOpenXml.DataValidation.Formulas;
-
-internal class ExcelDataValidationFormulaDateTime
-    : ExcelDataValidationFormulaValue<DateTime?>,
-      IExcelDataValidationFormulaDateTime {
-  public ExcelDataValidationFormulaDateTime(
-      XmlNamespaceManager namespaceManager,
-      XmlNode topNode,
-      string formulaPath)
-      : base(namespaceManager, topNode, formulaPath) {
-    var value = GetXmlNodeString(formulaPath);
-    if (!string.IsNullOrEmpty(value)) {
-      if (double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var oADate)) {
-        Value = DateTime.FromOADate(oADate);
-      } else {
-        ExcelFormula = value;
-      }
-    }
-  }
-
-  protected override string GetValueAsString() {
-    return Value.HasValue
-        ? Value.Value.ToOADate().ToString(CultureInfo.InvariantCulture)
-        : string.Empty;
-  }
-}
diff --git a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaDecimal.cs b/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaDecimal.cs
deleted file mode 100644
index 995c459..0000000
--- a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaDecimal.cs
+++ /dev/null
@@ -1,65 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using System.Globalization;
-using System.Xml;
-using OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-namespace OfficeOpenXml.DataValidation.Formulas;
-
-/// <summary>
-///
-/// </summary>
-internal class ExcelDataValidationFormulaDecimal
-    : ExcelDataValidationFormulaValue<double?>,
-      IExcelDataValidationFormulaDecimal {
-  public ExcelDataValidationFormulaDecimal(
-      XmlNamespaceManager namespaceManager,
-      XmlNode topNode,
-      string formulaPath)
-      : base(namespaceManager, topNode, formulaPath) {
-    var value = GetXmlNodeString(formulaPath);
-    if (!string.IsNullOrEmpty(value)) {
-      if (double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var dValue)) {
-        Value = dValue;
-      } else {
-        ExcelFormula = value;
-      }
-    }
-  }
-
-  protected override string GetValueAsString() {
-    return Value.HasValue
-        ? Value.Value.ToString("R15", CultureInfo.InvariantCulture)
-        : string.Empty;
-  }
-}
diff --git a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaInt.cs b/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaInt.cs
deleted file mode 100644
index 6bd31d2..0000000
--- a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaInt.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-namespace OfficeOpenXml.DataValidation.Formulas;
-
-internal class ExcelDataValidationFormulaInt
-    : ExcelDataValidationFormulaValue<int?>,
-      IExcelDataValidationFormulaInt {
-  public ExcelDataValidationFormulaInt(
-      XmlNamespaceManager namespaceManager,
-      XmlNode topNode,
-      string formulaPath)
-      : base(namespaceManager, topNode, formulaPath) {
-    var value = GetXmlNodeString(formulaPath);
-    if (!string.IsNullOrEmpty(value)) {
-      if (int.TryParse(value, out var intValue)) {
-        Value = intValue;
-      } else {
-        ExcelFormula = value;
-      }
-    }
-  }
-
-  protected override string GetValueAsString() {
-    return Value.HasValue ? Value.Value.ToString() : string.Empty;
-  }
-}
diff --git a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaList.cs b/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaList.cs
deleted file mode 100644
index 55e554b..0000000
--- a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaList.cs
+++ /dev/null
@@ -1,192 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Text;
-using System.Xml;
-using OfficeOpenXml.DataValidation.Formulas.Contracts;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.DataValidation.Formulas;
-
-internal class ExcelDataValidationFormulaList
-    : ExcelDataValidationFormula,
-      IExcelDataValidationFormulaList {
-  private class DataValidationList : IList<string>, ICollection {
-    private readonly IList<string> _items = new List<string>();
-    private EventHandler<EventArgs> _listChanged;
-
-    public event EventHandler<EventArgs> ListChanged {
-      add => _listChanged += value;
-      remove => _listChanged -= value;
-    }
-
-    private void OnListChanged() {
-      if (_listChanged != null) {
-        _listChanged(this, EventArgs.Empty);
-      }
-    }
-
-    int IList<string>.IndexOf(string item) {
-      return _items.IndexOf(item);
-    }
-
-    void IList<string>.Insert(int index, string item) {
-      _items.Insert(index, item);
-      OnListChanged();
-    }
-
-    void IList<string>.RemoveAt(int index) {
-      _items.RemoveAt(index);
-      OnListChanged();
-    }
-
-    string IList<string>.this[int index] {
-      get => _items[index];
-      set {
-        _items[index] = value;
-        OnListChanged();
-      }
-    }
-
-    void ICollection<string>.Add(string item) {
-      _items.Add(item);
-      OnListChanged();
-    }
-
-    void ICollection<string>.Clear() {
-      _items.Clear();
-      OnListChanged();
-    }
-
-    bool ICollection<string>.Contains(string item) {
-      return _items.Contains(item);
-    }
-
-    void ICollection<string>.CopyTo(string[] array, int arrayIndex) {
-      _items.CopyTo(array, arrayIndex);
-    }
-
-    int ICollection<string>.Count => _items.Count;
-
-    bool ICollection<string>.IsReadOnly => false;
-
-    bool ICollection<string>.Remove(string item) {
-      var retVal = _items.Remove(item);
-      OnListChanged();
-      return retVal;
-    }
-
-    IEnumerator<string> IEnumerable<string>.GetEnumerator() {
-      return _items.GetEnumerator();
-    }
-
-    IEnumerator IEnumerable.GetEnumerator() {
-      return _items.GetEnumerator();
-    }
-
-    public void CopyTo(Array array, int index) {
-      _items.CopyTo((string[])array, index);
-    }
-
-    int ICollection.Count => _items.Count;
-
-    public bool IsSynchronized => ((ICollection)_items).IsSynchronized;
-
-    public object SyncRoot => ((ICollection)_items).SyncRoot;
-  }
-
-  public ExcelDataValidationFormulaList(
-      XmlNamespaceManager namespaceManager,
-      XmlNode itemNode,
-      string formulaPath)
-      : base(namespaceManager, itemNode, formulaPath) {
-    Require.Argument(formulaPath).IsNotNullOrEmpty("formulaPath");
-    _formulaPath = formulaPath;
-    var values = new DataValidationList();
-    values.ListChanged += values_ListChanged;
-    Values = values;
-    SetInitialValues();
-  }
-
-  private readonly string _formulaPath;
-
-  private void SetInitialValues() {
-    var value = GetXmlNodeString(_formulaPath);
-    if (!string.IsNullOrEmpty(value)) {
-      if (value.StartsWith("\"") && value.EndsWith("\"")) {
-        value = value.TrimStart('"').TrimEnd('"');
-        var items = value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
-        foreach (var item in items) {
-          Values.Add(item);
-        }
-      } else {
-        ExcelFormula = value;
-      }
-    }
-  }
-
-  private void values_ListChanged(object sender, EventArgs e) {
-    if (Values.Count > 0) {
-      State = FormulaState.Value;
-    }
-    var valuesAsString = GetValueAsString();
-    // Excel supports max 255 characters in this field.
-    if (valuesAsString.Length > 255) {
-      throw new InvalidOperationException(
-          "The total length of a DataValidation list cannot exceed 255 characters");
-    }
-    SetXmlNodeString(_formulaPath, valuesAsString);
-  }
-
-  public IList<string> Values { get; private set; }
-
-  protected override string GetValueAsString() {
-    var sb = new StringBuilder();
-    foreach (var val in Values) {
-      if (sb.Length == 0) {
-        sb.Append("\"");
-        sb.Append(val);
-      } else {
-        sb.AppendFormat(",{0}", val);
-      }
-    }
-    sb.Append("\"");
-    return sb.ToString();
-  }
-
-  internal override void ResetValue() {
-    Values.Clear();
-  }
-}
diff --git a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaTime.cs b/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaTime.cs
deleted file mode 100644
index 54d9844..0000000
--- a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaTime.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		                License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using System;
-using System.Globalization;
-using System.Xml;
-using OfficeOpenXml.DataValidation.Formulas.Contracts;
-
-namespace OfficeOpenXml.DataValidation.Formulas;
-
-internal class ExcelDataValidationFormulaTime
-    : ExcelDataValidationFormulaValue<ExcelTime>,
-      IExcelDataValidationFormulaTime {
-  public ExcelDataValidationFormulaTime(
-      XmlNamespaceManager namespaceManager,
-      XmlNode topNode,
-      string formulaPath)
-      : base(namespaceManager, topNode, formulaPath) {
-    var value = GetXmlNodeString(formulaPath);
-    if (!string.IsNullOrEmpty(value)) {
-      if (decimal.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var time)) {
-        Value = new(time);
-      } else {
-        Value = new();
-        ExcelFormula = value;
-      }
-    } else {
-      Value = new();
-    }
-    Value.TimeChanged += Value_TimeChanged;
-  }
-
-  private void Value_TimeChanged(object sender, EventArgs e) {
-    SetXmlNodeString(FormulaPath, Value.ToExcelString());
-  }
-
-  protected override string GetValueAsString() {
-    if (State == FormulaState.Value) {
-      return Value.ToExcelString();
-    }
-    return string.Empty;
-  }
-
-  internal override void ResetValue() {
-    Value = new();
-  }
-}
diff --git a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaValue.cs b/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaValue.cs
deleted file mode 100644
index 8490c7a..0000000
--- a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaValue.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-08
- * Jan Källman		                License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using System.Xml;
-
-namespace OfficeOpenXml.DataValidation.Formulas;
-
-/// <summary>
-/// This class represents a validation formula. Its value can be specified as a value of the specified datatype or as a formula.
-/// </summary>
-/// <typeparam name="T"></typeparam>
-internal abstract class ExcelDataValidationFormulaValue<T> : ExcelDataValidationFormula {
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="namespaceManager">Namespacemanger of the worksheet</param>
-  /// <param name="topNode">validation top node</param>
-  /// <param name="formulaPath">xml path of the current formula</param>
-  public ExcelDataValidationFormulaValue(
-      XmlNamespaceManager namespaceManager,
-      XmlNode topNode,
-      string formulaPath)
-      : base(namespaceManager, topNode, formulaPath) {}
-
-  private T _value;
-
-  /// <summary>
-  /// Typed value
-  /// </summary>
-  public T Value {
-    get => _value;
-    set {
-      State = FormulaState.Value;
-      _value = value;
-      SetXmlNodeString(FormulaPath, GetValueAsString());
-    }
-  }
-
-  internal override void ResetValue() {
-    Value = default(T);
-  }
-}
diff --git a/EPPlus/DataValidation/IRangeDataValidation.cs b/EPPlus/DataValidation/IRangeDataValidation.cs
deleted file mode 100644
index 0002560..0000000
--- a/EPPlus/DataValidation/IRangeDataValidation.cs
+++ /dev/null
@@ -1,89 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-03-23
- * Jan Källman		                License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using OfficeOpenXml.DataValidation.Contracts;
-
-namespace OfficeOpenXml.DataValidation;
-
-/// <summary>
-/// Provides functionality for adding datavalidation to a range (<see cref="ExcelRangeBase"/>). Each method will
-/// return a configurable validation.
-/// </summary>
-public interface IRangeDataValidation {
-  /// <summary>
-  /// Adds a <see cref="IExcelDataValidationAny"/> to the range.
-  /// </summary>
-  /// <returns>A <see cref="ExcelDataValidationAny"/> that can be configured for any validation</returns>
-  IExcelDataValidationAny AddAnyDataValidation();
-
-  /// <summary>
-  /// Adds a <see cref="IExcelDataValidationInt"/> to the range
-  /// </summary>
-  /// <returns>A <see cref="ExcelDataValidationInt"/> that can be configured for integer data validation</returns>
-  IExcelDataValidationInt AddIntegerDataValidation();
-
-  /// <summary>
-  /// Adds a <see cref="ExcelDataValidationDecimal"/> to the range
-  /// </summary>
-  /// <returns>A <see cref="ExcelDataValidationDecimal"/> that can be configured for decimal data validation</returns>
-  IExcelDataValidationDecimal AddDecimalDataValidation();
-
-  /// <summary>
-  /// Adds a <see cref="ExcelDataValidationDateTime"/> to the range
-  /// </summary>
-  /// <returns>A <see cref="ExcelDataValidationDecimal"/> that can be configured for datetime data validation</returns>
-  IExcelDataValidationDateTime AddDateTimeDataValidation();
-
-  /// <summary>
-  /// Adds a <see cref="IExcelDataValidationList"/> to the range
-  /// </summary>
-  /// <returns>A <see cref="ExcelDataValidationList"/> that can be configured for datetime data validation</returns>
-  IExcelDataValidationList AddListDataValidation();
-
-  /// <summary>
-  /// Adds a <see cref="IExcelDataValidationInt"/> regarding text length validation to the range.
-  /// </summary>
-  /// <returns></returns>
-  IExcelDataValidationInt AddTextLengthDataValidation();
-
-  /// <summary>
-  /// Adds a <see cref="IExcelDataValidationTime"/> to the range.
-  /// </summary>
-  /// <returns>A <see cref="IExcelDataValidationTime"/> that can be configured for time data validation</returns>
-  IExcelDataValidationTime AddTimeDataValidation();
-
-  /// <summary>
-  /// Adds a <see cref="IExcelDataValidationCustom"/> to the range.
-  /// </summary>
-  /// <returns>A <see cref="IExcelDataValidationCustom"/> that can be configured for custom validation</returns>
-  IExcelDataValidationCustom AddCustomDataValidation();
-}
diff --git a/EPPlus/DataValidation/RangeDataValidation.cs b/EPPlus/DataValidation/RangeDataValidation.cs
deleted file mode 100644
index b09d219..0000000
--- a/EPPlus/DataValidation/RangeDataValidation.cs
+++ /dev/null
@@ -1,80 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-03-23
- * Jan Källman		                License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using OfficeOpenXml.DataValidation.Contracts;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.DataValidation;
-
-internal class RangeDataValidation : IRangeDataValidation {
-  public RangeDataValidation(ExcelWorksheet worksheet, string address) {
-    Require.Argument(worksheet).IsNotNull("worksheet");
-    Require.Argument(address).IsNotNullOrEmpty("address");
-    _worksheet = worksheet;
-    _address = address;
-  }
-
-  private readonly ExcelWorksheet _worksheet;
-  private readonly string _address;
-
-  public IExcelDataValidationAny AddAnyDataValidation() {
-    return _worksheet.DataValidations.AddAnyValidation(_address);
-  }
-
-  public IExcelDataValidationInt AddIntegerDataValidation() {
-    return _worksheet.DataValidations.AddIntegerValidation(_address);
-  }
-
-  public IExcelDataValidationDecimal AddDecimalDataValidation() {
-    return _worksheet.DataValidations.AddDecimalValidation(_address);
-  }
-
-  public IExcelDataValidationDateTime AddDateTimeDataValidation() {
-    return _worksheet.DataValidations.AddDateTimeValidation(_address);
-  }
-
-  public IExcelDataValidationList AddListDataValidation() {
-    return _worksheet.DataValidations.AddListValidation(_address);
-  }
-
-  public IExcelDataValidationInt AddTextLengthDataValidation() {
-    return _worksheet.DataValidations.AddTextLengthValidation(_address);
-  }
-
-  public IExcelDataValidationTime AddTimeDataValidation() {
-    return _worksheet.DataValidations.AddTimeValidation(_address);
-  }
-
-  public IExcelDataValidationCustom AddCustomDataValidation() {
-    return _worksheet.DataValidations.AddCustomValidation(_address);
-  }
-}
diff --git a/EPPlus/Drawing/Vml/ExcelVmlDrawingBase.cs b/EPPlus/Drawing/Vml/ExcelVmlDrawingBase.cs
deleted file mode 100644
index ade7974..0000000
--- a/EPPlus/Drawing/Vml/ExcelVmlDrawingBase.cs
+++ /dev/null
@@ -1,153 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		Initial Release		        2010-06-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System.Collections.Immutable;
-using System.Xml;
-
-namespace OfficeOpenXml.Drawing.Vml;
-
-/// <summary>
-/// Horizontal Alingment
-/// </summary>
-public enum eTextAlignHorizontalVml {
-  Left,
-  Center,
-  Right,
-}
-
-/// <summary>
-/// Vertical Alingment
-/// </summary>
-public enum eTextAlignVerticalVml {
-  Top,
-  Center,
-  Bottom,
-}
-
-/// <summary>
-/// Linestyle
-/// </summary>
-public enum eLineStyleVml {
-  Solid,
-  Round,
-  Square,
-  Dash,
-  DashDot,
-  LongDash,
-  LongDashDot,
-  LongDashDotDot,
-}
-
-/// <summary>
-/// Drawing object used for comments
-/// </summary>
-public class ExcelVmlDrawingBase : XmlHelper {
-  protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
-    "fill",
-    "stroke",
-    "shadow",
-    "path",
-    "textbox",
-    "ClientData",
-    "MoveWithCells",
-    "SizeWithCells",
-    "Anchor",
-    "Locked",
-    "AutoFill",
-    "LockText",
-    "TextHAlign",
-    "TextVAlign",
-    "Row",
-    "Column",
-    "Visible",
-  ];
-
-  internal ExcelVmlDrawingBase(XmlNode topNode, XmlNamespaceManager ns)
-      : base(ns, topNode) {}
-
-  public string Id {
-    get => GetXmlNodeString("@id");
-    set => SetXmlNodeString("@id", value);
-  }
-
-  /// <summary>
-  /// Alternative text to be displayed instead of a graphic.
-  /// </summary>
-  public string AlternativeText {
-    get => GetXmlNodeString("@alt");
-    set => SetXmlNodeString("@alt", value);
-  }
-
-  protected bool GetStyle(string style, string key, out string value) {
-    string[] styles = style.Split(';');
-    foreach (string s in styles) {
-      if (s.IndexOf(':') > 0) {
-        string[] split = s.Split(':');
-        if (split[0] == key) {
-          value = split[1];
-          return true;
-        }
-      } else if (s == key) {
-        value = "";
-        return true;
-      }
-    }
-    value = "";
-    return false;
-  }
-
-  protected string SetStyle(string style, string key, string value) {
-    string[] styles = style.Split(';');
-    string newStyle = "";
-    bool changed = false;
-    foreach (string s in styles) {
-      string[] split = s.Split(':');
-      if (split[0].Trim() == key) {
-        if (value.Trim()
-            != "") //If blank remove the item
-        {
-          newStyle += key + ':' + value;
-        }
-        changed = true;
-      } else {
-        newStyle += s;
-      }
-      newStyle += ';';
-    }
-    if (!changed) {
-      newStyle += key + ':' + value;
-    } else {
-      newStyle = style.Substring(0, style.Length - 1);
-    }
-    return newStyle;
-  }
-}
diff --git a/EPPlus/Drawing/Vml/ExcelVmlDrawingBaseCollection.cs b/EPPlus/Drawing/Vml/ExcelVmlDrawingBaseCollection.cs
deleted file mode 100644
index a0bd7e1..0000000
--- a/EPPlus/Drawing/Vml/ExcelVmlDrawingBaseCollection.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		Initial Release		        2010-06-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System;
-using System.Xml;
-using OfficeOpenXml.Packaging;
-
-namespace OfficeOpenXml.Drawing.Vml;
-
-public class ExcelVmlDrawingBaseCollection {
-  internal ExcelVmlDrawingBaseCollection(ExcelPackage pck, ExcelWorksheet ws, Uri uri) {
-    VmlDrawingXml.PreserveWhitespace = false;
-
-    NameTable nt = new NameTable();
-    NameSpaceManager = new(nt);
-    NameSpaceManager.AddNamespace("v", ExcelPackage._schemaMicrosoftVml);
-    NameSpaceManager.AddNamespace("o", ExcelPackage._schemaMicrosoftOffice);
-    NameSpaceManager.AddNamespace("x", ExcelPackage._schemaMicrosoftExcel);
-    Uri = uri;
-    if (uri == null) {
-      Part = null;
-    } else {
-      Part = pck.Package.GetPart(uri);
-      XmlHelper.LoadXmlSafe(VmlDrawingXml, Part.GetStream());
-    }
-  }
-
-  internal XmlDocument VmlDrawingXml { get; set; } = new();
-
-  internal Uri Uri { get; set; }
-  internal string RelId { get; set; }
-  internal ZipPackagePart Part { get; set; }
-  internal XmlNamespaceManager NameSpaceManager { get; set; }
-}
diff --git a/EPPlus/Drawing/Vml/ExcelVmlDrawingComment.cs b/EPPlus/Drawing/Vml/ExcelVmlDrawingComment.cs
deleted file mode 100644
index 7eecb26..0000000
--- a/EPPlus/Drawing/Vml/ExcelVmlDrawingComment.cs
+++ /dev/null
@@ -1,232 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		Initial Release		        2010-06-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System.Collections.Immutable;
-using System.Xml;
-
-namespace OfficeOpenXml.Drawing.Vml;
-
-/// <summary>
-/// Drawing object used for comments
-/// </summary>
-public class ExcelVmlDrawingComment : ExcelVmlDrawingBase, IRangeId {
-  protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
-    "fill",
-    "stroke",
-    "shadow",
-    "path",
-    "textbox",
-    "ClientData",
-    "MoveWithCells",
-    "SizeWithCells",
-    "Anchor",
-    "Locked",
-    "AutoFill",
-    "LockText",
-    "TextHAlign",
-    "TextVAlign",
-    "Row",
-    "Column",
-    "Visible",
-  ];
-
-  internal ExcelVmlDrawingComment(XmlNode topNode, ExcelRangeBase range, XmlNamespaceManager ns)
-      : base(topNode, ns) {
-    Range = range;
-  }
-
-  internal ExcelRangeBase Range { get; set; }
-
-  /// <summary>
-  /// Address in the worksheet
-  /// </summary>
-  public string Address => Range.Address;
-
-  private const string _verticalAlignmentPath = "x:ClientData/x:TextVAlign";
-
-  /// <summary>
-  /// Vertical alignment for text
-  /// </summary>
-  public eTextAlignVerticalVml VerticalAlignment {
-    get {
-      switch (GetXmlNodeString(_verticalAlignmentPath)) {
-        case "Center":
-          return eTextAlignVerticalVml.Center;
-        case "Bottom":
-          return eTextAlignVerticalVml.Bottom;
-        default:
-          return eTextAlignVerticalVml.Top;
-      }
-    }
-    set {
-      switch (value) {
-        case eTextAlignVerticalVml.Center:
-          SetXmlNodeString(_verticalAlignmentPath, "Center");
-          break;
-        case eTextAlignVerticalVml.Bottom:
-          SetXmlNodeString(_verticalAlignmentPath, "Bottom");
-          break;
-        default:
-          DeleteNode(_verticalAlignmentPath);
-          break;
-      }
-    }
-  }
-
-  private const string _horizontalAlignmentPath = "x:ClientData/x:TextHAlign";
-
-  /// <summary>
-  /// Horizontal alignment for text
-  /// </summary>
-  public eTextAlignHorizontalVml HorizontalAlignment {
-    get {
-      switch (GetXmlNodeString(_horizontalAlignmentPath)) {
-        case "Center":
-          return eTextAlignHorizontalVml.Center;
-        case "Right":
-          return eTextAlignHorizontalVml.Right;
-        default:
-          return eTextAlignHorizontalVml.Left;
-      }
-    }
-    set {
-      switch (value) {
-        case eTextAlignHorizontalVml.Center:
-          SetXmlNodeString(_horizontalAlignmentPath, "Center");
-          break;
-        case eTextAlignHorizontalVml.Right:
-          SetXmlNodeString(_horizontalAlignmentPath, "Right");
-          break;
-        default:
-          DeleteNode(_horizontalAlignmentPath);
-          break;
-      }
-    }
-  }
-
-  private const string _visiblePath = "x:ClientData/x:Visible";
-
-  /// <summary>
-  /// If the drawing object is visible.
-  /// </summary>
-  public bool Visible {
-    get => (TopNode.SelectSingleNode(_visiblePath, NameSpaceManager) != null);
-    set {
-      if (value) {
-        CreateNode(_visiblePath);
-        Style = SetStyle(Style, "visibility", "visible");
-      } else {
-        DeleteNode(_visiblePath);
-        Style = SetStyle(Style, "visibility", "hidden");
-      }
-    }
-  }
-
-  private const string _textboxStylePath = "v:textbox/@style";
-
-  /// <summary>
-  /// Autofits the drawingobject
-  /// </summary>
-  public bool AutoFit {
-    get {
-      GetStyle(GetXmlNodeString(_textboxStylePath), "mso-fit-shape-to-text", out var value);
-      return value == "t";
-    }
-    set =>
-      SetXmlNodeString(
-          _textboxStylePath,
-          SetStyle(GetXmlNodeString(_textboxStylePath), "mso-fit-shape-to-text", value ? "t" : ""));
-  }
-
-  private const string _lockedPath = "x:ClientData/x:Locked";
-
-  /// <summary>
-  /// If the object is locked when the sheet is protected
-  /// </summary>
-  public bool Locked {
-    get => GetXmlNodeBool(_lockedPath, false);
-    set => SetXmlNodeBool(_lockedPath, value, false);
-  }
-
-  private const string _lockTextPath = "x:ClientData/x:LockText";
-
-  /// <summary>
-  /// Specifies that the object's text is locked
-  /// </summary>
-  public bool LockText {
-    get => GetXmlNodeBool(_lockTextPath, false);
-    set => SetXmlNodeBool(_lockTextPath, value, false);
-  }
-
-  private ExcelVmlDrawingPosition _from;
-
-  /// <summary>
-  /// From position. For comments only when Visible=true.
-  /// </summary>
-  public ExcelVmlDrawingPosition From {
-    get {
-      if (_from == null) {
-        _from = new(
-            NameSpaceManager,
-            TopNode.SelectSingleNode("x:ClientData", NameSpaceManager),
-            0);
-      }
-      return _from;
-    }
-  }
-
-  private ExcelVmlDrawingPosition _to;
-
-  /// <summary>
-  /// To position. For comments only when Visible=true.
-  /// </summary>
-  public ExcelVmlDrawingPosition To {
-    get {
-      if (_to == null) {
-        _to = new(NameSpaceManager, TopNode.SelectSingleNode("x:ClientData", NameSpaceManager), 4);
-      }
-      return _to;
-    }
-  }
-
-  private const string _stylePath = "@style";
-
-  internal string Style {
-    get => GetXmlNodeString(_stylePath);
-    set => SetXmlNodeString(_stylePath, value);
-  }
-
-  ulong IRangeId.RangeID {
-    get => ExcelCellBase.GetCellId(Range.Worksheet.SheetID, Range.Start.Row, Range.Start.Column);
-    set {}
-  }
-}
diff --git a/EPPlus/Drawing/Vml/ExcelVmlDrawingCommentCollection.cs b/EPPlus/Drawing/Vml/ExcelVmlDrawingCommentCollection.cs
deleted file mode 100644
index deb294c..0000000
--- a/EPPlus/Drawing/Vml/ExcelVmlDrawingCommentCollection.cs
+++ /dev/null
@@ -1,188 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		Initial Release		        2010-06-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Xml;
-
-namespace OfficeOpenXml.Drawing.Vml;
-
-internal class ExcelVmlDrawingCommentCollection : ExcelVmlDrawingBaseCollection, IEnumerable {
-  internal RangeCollection _drawings;
-
-  internal ExcelVmlDrawingCommentCollection(ExcelPackage pck, ExcelWorksheet ws, Uri uri)
-      : base(pck, ws, uri) {
-    if (uri == null) {
-      VmlDrawingXml.LoadXml(CreateVmlDrawings());
-      _drawings = new(new());
-    } else {
-      AddDrawingsFromXml(ws);
-    }
-  }
-
-  protected void AddDrawingsFromXml(ExcelWorksheet ws) {
-    var nodes = VmlDrawingXml.SelectNodes("//v:shape", NameSpaceManager);
-    var list = new List<IRangeId>();
-    foreach (XmlNode node in nodes) {
-      var rowNode = node.SelectSingleNode("x:ClientData/x:Row", NameSpaceManager);
-      var colNode = node.SelectSingleNode("x:ClientData/x:Column", NameSpaceManager);
-      if (rowNode != null && colNode != null) {
-        var row = int.Parse(rowNode.InnerText) + 1;
-        var col = int.Parse(colNode.InnerText) + 1;
-        list.Add(new ExcelVmlDrawingComment(node, ws.Cells[row, col], NameSpaceManager));
-      } else {
-        list.Add(new ExcelVmlDrawingComment(node, ws.Cells[1, 1], NameSpaceManager));
-      }
-    }
-    list.Sort((r1, r2) =>
-        (r1.RangeID < r2.RangeID
-                ? -1
-                : r1.RangeID > r2.RangeID
-                    ? 1
-                    : 0)); //Vml drawings are not sorted. Sort to avoid missmatches.
-    _drawings = new(list);
-  }
-
-  private string CreateVmlDrawings() {
-    string vml = string.Format(
-        "<xml xmlns:v=\"{0}\" xmlns:o=\"{1}\" xmlns:x=\"{2}\">",
-        ExcelPackage._schemaMicrosoftVml,
-        ExcelPackage._schemaMicrosoftOffice,
-        ExcelPackage._schemaMicrosoftExcel);
-
-    vml += "<o:shapelayout v:ext=\"edit\">";
-    vml += "<o:idmap v:ext=\"edit\" data=\"1\"/>";
-    vml += "</o:shapelayout>";
-
-    vml +=
-        "<v:shapetype id=\"_x0000_t202\" coordsize=\"21600,21600\" o:spt=\"202\" path=\"m,l,21600r21600,l21600,xe\">";
-    vml += "<v:stroke joinstyle=\"miter\" />";
-    vml += "<v:path gradientshapeok=\"t\" o:connecttype=\"rect\" />";
-    vml += "</v:shapetype>";
-    vml += "</xml>";
-
-    return vml;
-  }
-
-  internal ExcelVmlDrawingComment Add(ExcelRangeBase cell) {
-    XmlNode node = AddDrawing(cell);
-    var draw = new ExcelVmlDrawingComment(node, cell, NameSpaceManager);
-    _drawings.Add(draw);
-    return draw;
-  }
-
-  private XmlNode AddDrawing(ExcelRangeBase cell) {
-    int row = cell.Start.Row,
-        col = cell.Start.Column;
-    var node = VmlDrawingXml.CreateElement("v", "shape", ExcelPackage._schemaMicrosoftVml);
-
-    var id = ExcelCellBase.GetCellId(cell.Worksheet.SheetID, cell._fromRow, cell._fromCol);
-    var ix = _drawings.IndexOf(id);
-    if (ix < 0 && (~ix < _drawings.Count)) {
-      ix = ~ix;
-      var prevDraw = _drawings[ix] as ExcelVmlDrawingBase;
-      prevDraw.TopNode.ParentNode.InsertBefore(node, prevDraw.TopNode);
-    } else {
-      VmlDrawingXml.DocumentElement.AppendChild(node);
-    }
-
-    node.SetAttribute("id", GetNewId());
-    node.SetAttribute("type", "#_x0000_t202");
-    node.SetAttribute("style", "position:absolute;z-index:1; visibility:hidden");
-    //node.SetAttribute("style", "position:absolute; margin-left:59.25pt;margin-top:1.5pt;width:108pt;height:59.25pt;z-index:1; visibility:hidden");
-    node.SetAttribute("fillcolor", "#ffffe1");
-    node.SetAttribute("insetmode", ExcelPackage._schemaMicrosoftOffice, "auto");
-
-    string vml = "<v:fill color2=\"#ffffe1\" />";
-    vml += "<v:shadow on=\"t\" color=\"black\" obscured=\"t\" />";
-    vml += "<v:path o:connecttype=\"none\" />";
-    vml += "<v:textbox style=\"mso-direction-alt:auto\">";
-    vml += "<div style=\"text-align:left\" />";
-    vml += "</v:textbox>";
-    vml += "<x:ClientData ObjectType=\"Note\">";
-    vml += "<x:MoveWithCells />";
-    vml += "<x:SizeWithCells />";
-    vml += string.Format(
-        "<x:Anchor>{0}, 15, {1}, 2, {2}, 31, {3}, 1</x:Anchor>",
-        col,
-        row - 1,
-        col + 2,
-        row + 3);
-    vml += "<x:AutoFill>False</x:AutoFill>";
-    vml += string.Format("<x:Row>{0}</x:Row>", row - 1);
-    ;
-    vml += string.Format("<x:Column>{0}</x:Column>", col - 1);
-    vml += "</x:ClientData>";
-
-    node.InnerXml = vml;
-    return node;
-  }
-
-  private int _nextID;
-
-  /// <summary>
-  /// returns the next drawing id.
-  /// </summary>
-  /// <returns></returns>
-  internal string GetNewId() {
-    if (_nextID == 0) {
-      foreach (ExcelVmlDrawingComment draw in this) {
-        if (draw.Id.Length > 3 && draw.Id.StartsWith("vml")) {
-          if (int.TryParse(draw.Id.Substring(3, draw.Id.Length - 3), out var id)) {
-            if (id > _nextID) {
-              _nextID = id;
-            }
-          }
-        }
-      }
-    }
-    _nextID++;
-    return "vml" + _nextID;
-  }
-
-  internal ExcelVmlDrawingBase this[ulong rangeId] => _drawings[rangeId] as ExcelVmlDrawingComment;
-
-  internal bool ContainsKey(ulong rangeId) {
-    return _drawings.ContainsKey(rangeId);
-  }
-
-  internal int Count => _drawings.Count;
-
-  public IEnumerator GetEnumerator() {
-    return _drawings;
-  }
-
-  IEnumerator IEnumerable.GetEnumerator() {
-    return _drawings;
-  }
-}
diff --git a/EPPlus/Drawing/Vml/ExcelVmlDrawingPosition.cs b/EPPlus/Drawing/Vml/ExcelVmlDrawingPosition.cs
deleted file mode 100644
index ec28659..0000000
--- a/EPPlus/Drawing/Vml/ExcelVmlDrawingPosition.cs
+++ /dev/null
@@ -1,101 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		Initial Release		        2010-06-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System.Xml;
-
-namespace OfficeOpenXml.Drawing.Vml;
-
-/// <summary>
-/// The position of a VML drawing. Used for comments
-/// </summary>
-public class ExcelVmlDrawingPosition : XmlHelper {
-  private readonly int _startPos;
-
-  internal ExcelVmlDrawingPosition(XmlNamespaceManager ns, XmlNode topNode, int startPos)
-      : base(ns, topNode) {
-    _startPos = startPos;
-  }
-
-  /// <summary>
-  /// Row. Zero based
-  /// </summary>
-  public int Row {
-    get => GetNumber(2);
-    set => SetNumber(2, value);
-  }
-
-  /// <summary>
-  /// Row offset in pixels. Zero based
-  /// </summary>
-  public int RowOffset {
-    get => GetNumber(3);
-    set => SetNumber(3, value);
-  }
-
-  /// <summary>
-  /// Column. Zero based
-  /// </summary>
-  public int Column {
-    get => GetNumber(0);
-    set => SetNumber(0, value);
-  }
-
-  /// <summary>
-  /// Column offset. Zero based
-  /// </summary>
-  public int ColumnOffset {
-    get => GetNumber(1);
-    set => SetNumber(1, value);
-  }
-
-  private void SetNumber(int pos, int value) {
-    string anchor = GetXmlNodeString("x:Anchor");
-    string[] numbers = anchor.Split(',');
-    if (numbers.Length == 8) {
-      numbers[_startPos + pos] = value.ToString();
-    } else {
-      throw (new("Anchor element is invalid in vmlDrawing"));
-    }
-    SetXmlNodeString("x:Anchor", string.Join(",", numbers));
-  }
-
-  private int GetNumber(int pos) {
-    string anchor = GetXmlNodeString("x:Anchor");
-    string[] numbers = anchor.Split(',');
-    if (numbers.Length == 8) {
-      if (int.TryParse(numbers[_startPos + pos], out var ret)) {
-        return ret;
-      }
-    }
-    throw (new("Anchor element is invalid in vmlDrawing"));
-  }
-}
diff --git a/EPPlus/EPPlus.csproj b/EPPlus/EPPlus.csproj
deleted file mode 100644
index 3cec524..0000000
--- a/EPPlus/EPPlus.csproj
+++ /dev/null
@@ -1,842 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProductVersion>9.0.30729</ProductVersion>
-    <SchemaVersion>2.0</SchemaVersion>
-    <ProjectGuid>{7B288026-5502-4A39-BF41-77E086F3E4A3}</ProjectGuid>
-    <OutputType>Library</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>OfficeOpenXml</RootNamespace>
-    <AssemblyName>EPPlus</AssemblyName>
-    <SignAssembly>true</SignAssembly>
-    <AssemblyOriginatorKeyFile>OpenOfficeXml.snk</AssemblyOriginatorKeyFile>
-    <SccProjectName>
-    </SccProjectName>
-    <SccLocalPath>
-    </SccLocalPath>
-    <SccAuxPath>
-    </SccAuxPath>
-    <SccProvider>
-    </SccProvider>
-    <FileUpgradeFlags>
-    </FileUpgradeFlags>
-    <UpgradeBackupLocation>
-    </UpgradeBackupLocation>
-    <OldToolsVersion>3.5</OldToolsVersion>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-    <PublishUrl>publish\</PublishUrl>
-    <Install>true</Install>
-    <InstallFrom>Disk</InstallFrom>
-    <UpdateEnabled>false</UpdateEnabled>
-    <UpdateMode>Foreground</UpdateMode>
-    <UpdateInterval>7</UpdateInterval>
-    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
-    <UpdatePeriodically>false</UpdatePeriodically>
-    <UpdateRequired>false</UpdateRequired>
-    <MapFileExtensions>true</MapFileExtensions>
-    <ApplicationRevision>0</ApplicationRevision>
-    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
-    <IsWebBootstrapper>false</IsWebBootstrapper>
-    <UseApplicationTrust>false</UseApplicationTrust>
-    <BootstrapperEnabled>true</BootstrapperEnabled>
-    <TargetFrameworkProfile>
-    </TargetFrameworkProfile>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <DocumentationFile>bin\Debug\EPPlus.XML</DocumentationFile>
-    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
-    <PlatformTarget>AnyCPU</PlatformTarget>
-    <NoWarn>
-    </NoWarn>
-    <Prefer32Bit>false</Prefer32Bit>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <DocumentationFile>bin\Release\EPPlus.XML</DocumentationFile>
-    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
-    <PlatformTarget>AnyCPU</PlatformTarget>
-    <Prefer32Bit>false</Prefer32Bit>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Core">
-      <HintPath>C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.Core.dll</HintPath>
-    </Reference>
-    <Reference Include="System.Data" />
-    <Reference Include="System.Drawing" />
-    <Reference Include="System.Security" />
-    <Reference Include="System.Xml" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="CellStore.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingAverageGroup.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingBeginsWith.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingBetween.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingColorScaleGroup.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingContainsBlanks.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingContainsErrors.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingContainsText.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingDataBarGroup.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingDuplicateValues.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingEndsWith.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingEqual.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingExpression.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingGreaterThan.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingGreaterThanOrEqual.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingThreeIconSet.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingFourIconSet.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingFiveIconSet.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingIconSetGroup.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingThreeColorScale.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingLessThan.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingLessThanOrEqual.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingNotBetween.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingNotContainsBlanks.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingNotContainsErrors.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingNotContainsText.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingNotEqual.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingStdDevGroup.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingTimePeriodGroup.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingTopBottomGroup.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingTwoColorScale.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingUniqueValues.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingWithFormula.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingWithFormula2.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingWithRank.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingWithReverse.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingWithShowValue.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingWithStdDev.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingWithText.cs" />
-    <Compile Include="ConditionalFormatting\ExcelConditionalFormattingIconDataBarValue.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingDataBar.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingFiveIconSet.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingFourIconSet.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingAboveStdDev.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingAboveOrEqualAverage.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingAverageGroup.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingAboveAverage.cs" />
-    <Compile Include="ConditionalFormatting\ExcelConditionalFormattingCollection.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\ExcelConditionalFormattingOperatorType.cs" />
-    <Compile Include="ConditionalFormatting\ExcelConditionalFormattingRuleFactory.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\ExcelConditionalFormattingConstants.cs" />
-    <Compile Include="ConditionalFormatting\ExcelConditionalFormattingTimePeriodType.cs" />
-    <Compile Include="ConditionalFormatting\ExcelConditionalFormattingColorScaleValue.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\ExcelConditionalFormattingEnums.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\ExcelConditionalFormattingValueObjectType.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingBeginsWith.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingBelowAverage.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingBelowOrEqualAverage.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingBelowStdDev.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingBetween.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingBottom.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingBottomPercent.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingContainsBlanks.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingContainsErrors.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingContainsText.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingDuplicateValues.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingEndsWith.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingEqual.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingExpression.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingGreaterThan.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingGreaterThanOrEqual.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingLast7Days.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingLastMonth.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingLastWeek.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingLessThan.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingLessThanOrEqual.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingNextMonth.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingNextWeek.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingNotBetween.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingNotContainsBlanks.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingNotContainsErrors.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingNotContainsText.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingNotEqual.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingRule.cs" />
-    <Compile Include="ConditionalFormatting\ExcelConditionalFormattingRuleType.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingThisMonth.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingThisWeek.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingThreeColorScale.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingThreeIconSet.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingTimePeriodGroup.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingToday.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingTomorrow.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingTop.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingTopPercent.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingTwoColorScale.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingRule.cs" />
-    <Compile Include="ConditionalFormatting\ExcelConditionalFormattingHelper.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IRangeConditionalFormatting.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\RangeConditionalFormatting.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingUniqueValues.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingYesterday.cs" />
-    <Compile Include="DataValidation\Contracts\IExcelDataValidation.cs" />
-    <Compile Include="DataValidation\Contracts\IExcelDataValidationAny.cs" />
-    <Compile Include="DataValidation\Contracts\IExcelDataValidationCustom.cs" />
-    <Compile Include="DataValidation\Contracts\IExcelDataValidationDateTime.cs" />
-    <Compile Include="DataValidation\Contracts\IExcelDataValidationDecimal.cs" />
-    <Compile Include="DataValidation\Contracts\IExcelDataValidationInt.cs" />
-    <Compile Include="DataValidation\Contracts\IExcelDataValidationList.cs" />
-    <Compile Include="DataValidation\Contracts\IExcelDataValidationTime.cs" />
-    <Compile Include="DataValidation\Contracts\IExcelDataValidationWithFormula.cs" />
-    <Compile Include="DataValidation\Contracts\IExcelDataValidationWithFormula2.cs" />
-    <Compile Include="DataValidation\Contracts\IExcelDataValidationWithOperator.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationAny.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationCustom.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationDateTime.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationFactory.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationTime.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationWithFormula.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationWithFormula2.cs" />
-    <Compile Include="DataValidation\ExcelTime.cs" />
-    <Compile Include="DataValidation\Formulas\Contracts\IExcelDataValidationFormula.cs" />
-    <Compile Include="DataValidation\Formulas\Contracts\IExcelDataValidationFormulaDateTime.cs" />
-    <Compile Include="DataValidation\Formulas\Contracts\IExcelDataValidationFormulaTime.cs" />
-    <Compile Include="DataValidation\Formulas\ExcelDataValidationFormula.cs" />
-    <Compile Include="DataValidation\Formulas\Contracts\IExcelDataValidationFormulaList.cs" />
-    <Compile Include="DataValidation\Formulas\ExcelDataValidationFormulaCustom.cs" />
-    <Compile Include="DataValidation\Formulas\ExcelDataValidationFormulaDateTime.cs" />
-    <Compile Include="DataValidation\Formulas\ExcelDataValidationFormulaList.cs" />
-    <Compile Include="DataValidation\Formulas\Contracts\IExcelDataValidationFormulaWithValue.cs" />
-    <Compile Include="DataValidation\Formulas\Contracts\IExcelDataValidationFormulaDecimal.cs" />
-    <Compile Include="DataValidation\Formulas\Contracts\IExcelDataValidationFormulaInt.cs" />
-    <Compile Include="DataValidation\Formulas\ExcelDataValidationFormulaTime.cs" />
-    <Compile Include="DataValidation\Formulas\ExcelDataValidationFormulaValue.cs" />
-    <Compile Include="DataValidation\Formulas\ExcelDataValidationFormulaDecimal.cs" />
-    <Compile Include="DataValidation\Formulas\ExcelDataValidationFormulaInt.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationOperator.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationWarningStyle.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationDecimal.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationList.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationInt.cs" />
-    <Compile Include="DataValidation\IRangeDataValidation.cs" />
-    <Compile Include="DataValidation\RangeDataValidation.cs" />
-    <Compile Include="Drawing\Chart\ExcelBarChartSerie.cs" />
-    <Compile Include="Drawing\Chart\ExcelSurfaceChartSerie.cs" />
-    <Compile Include="Drawing\Chart\ExcelSurfaceChart.cs" />
-    <Compile Include="Drawing\Chart\ExcelRadarChart.cs" />
-    <Compile Include="Drawing\Chart\ExcelBubbleChartSerie.cs" />
-    <Compile Include="Drawing\Chart\ExcelLineChartSerie.cs" />
-    <Compile Include="Drawing\Chart\ExcelChart.cs" />
-    <Compile Include="Drawing\Chart\ExcelChartCollection.cs" />
-    <Compile Include="Drawing\Chart\ExcelChartTrendline.cs" />
-    <Compile Include="Drawing\Chart\ExcelBubbleChart.cs" />
-    <Compile Include="Drawing\Chart\ExcelChartSurface.cs" />
-    <Compile Include="Drawing\ExcelDrawingBase.cs" />
-    <Compile Include="Drawing\ExcelPicture.cs" />
-    <Compile Include="Drawing\Chart\ExcelRadarChartSerie.cs" />
-    <Compile Include="Drawing\Vml\ExcelVmlDrawingPictureCollection.cs" />
-    <Compile Include="Drawing\Vml\ExcelVmlDrawingCommentCollection.cs" />
-    <Compile Include="Drawing\Vml\ExcelVmlDrawingPicture.cs" />
-    <Compile Include="Drawing\Vml\ExcelVmlDrawingBase.cs" />
-    <Compile Include="Encryption\EncryptionHandler.cs" />
-    <Compile Include="Encryption\EncryptionHeader.cs" />
-    <Compile Include="Encryption\EncryptionInfo.cs" />
-    <Compile Include="Encryption\EncryptionVerifier.cs" />
-    <Compile Include="ExcelBackgroundImage.cs" />
-    <Compile Include="DataValidation\ExcelDataValidation.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationCollection.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationType.cs" />
-    <Compile Include="ExcelEncryption.cs" />
-    <Compile Include="ExcelProtectedRange.cs" />
-    <Compile Include="ExcelProtectedRangeCollection.cs" />
-    <Compile Include="ExcelStyleCollection.cs" />
-    <Compile Include="ExcelColumn.cs" />
-    <Compile Include="Drawing\ExcelDrawings.cs" />
-    <Compile Include="ExcelHeaderFooter.cs" />
-    <Compile Include="ExcelPackage.cs" />
-    <Compile Include="ExcelRange.cs" />
-    <Compile Include="ExcelRow.cs" />
-    <Compile Include="Drawing\ExcelShape.cs" />
-    <Compile Include="ExcelStyles.cs" />
-    <Compile Include="ExcelProtection.cs" />
-    <Compile Include="ExcelTextFormat.cs" />
-    <Compile Include="FormulaParsing\CalculateExtentions.cs" />
-    <Compile Include="FormulaParsing\DependencyChain\DependenyChainFactory.cs" />
-    <Compile Include="FormulaParsing\DependencyChain\DependencyChain.cs" />
-    <Compile Include="FormulaParsing\DependencyChain\FormulaCell.cs" />
-    <Compile Include="FormulaParsing\EpplusExcelDataProvider.cs" />
-    <Compile Include="FormulaParsing\ExcelCalculationOption.cs" />
-    <Compile Include="FormulaParsing\ExcelCell.cs" />
-    <Compile Include="FormulaParsing\ExcelDataProvider.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\AddressTranslator.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\CellReferenceProvider.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\ExcelAddressInfo.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\ExcelAddressUtil.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\ExcelReferenceType.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\FormulaDependencies.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\FormulaDependency.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\FormulaDependencyFactory.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\IndexToAddressTranslator.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\LookupValueMatcher.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\NumericExpressionEvaluator.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\RangeAddress.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\RangeAddressFactory.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\ValueMatcher.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\WildCardValueMatcher.cs" />
-    <Compile Include="FormulaParsing\ExcelValues.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\CompileResultValidator.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\CompileResultValidators.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\CellStateHelper.cs" />
-    <Compile Include="FormulaParsing\Excel\ExcelCellState.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\ArgumentCollectionUtil.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\ArgumentParser.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\ArgumentParserFactory.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\ArgumentParsers.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\BoolArgumentParser.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\BuiltInFunctions.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\CollectionFlattener.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\DatabaseFunction.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\Daverage.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\Dcount.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\DcountA.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\Dget.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\Dmax.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\Dmin.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\Dsum.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\Dvar.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="FormulaParsing\Excel\Functions\Database\Dvarp.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\ExcelDatabase.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\ExcelDatabaseCriteria.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\ExcelDatabaseCriteriaField.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\ExcelDatabaseField.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\ExcelDatabaseRow.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\RowMatcher.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Date.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\DateParsingFunction.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\DateStringParser.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Day.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Days360.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Edate.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Eomonth.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Hour.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\IsoWeekNum.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Weeknum.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Minute.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Month.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Now.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Second.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Time.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\TimeBaseFunction.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\TimeStringParser.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Today.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Weekday.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Workday.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Year.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Yearfrac.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DecimalCompileResultValidator.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DoubleArgumentParser.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DoubleEnumerableArgConverter.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\ErrorHandlingFunction.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\ExcelFunction.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\FunctionArgument.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\FunctionRepository.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\FunctionsModule.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\HiddenValuesHandlingFunction.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\IFunctionModule.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\IFunctionNameProvider.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\ErrorType.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\IsBlank.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\IsErr.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\IsError.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\IsEven.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\IsLogical.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\IsNa.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\IsNonText.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\IsNumber.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\IsOdd.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\IsText.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\N.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\Na.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\IntArgumentParser.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Logical\And.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Logical\False.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Logical\If.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Logical\IfError.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Logical\IfNa.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Logical\Not.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Logical\Or.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Logical\True.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Abs.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Acos.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Acosh.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Asin.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Asinh.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Atan.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Atan2.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Atanh.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Average.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\AverageA.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\AverageIf.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\AverageIfs.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Ceiling.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Cos.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Cosh.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Count.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\CountA.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\CountBlank.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\CountIf.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\CountIfs.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Degrees.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Exp.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Fact.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Floor.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Large.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Ln.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Log.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Log10.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\MathHelper.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Max.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Maxa.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Median.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Min.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Mina.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Mod.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\MultipleRangeCriteriasFunction.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Pi.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Power.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Product.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Quotient.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Rand.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\RandBetween.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Round.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Rounddown.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Roundup.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Sign.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Sin.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Sinh.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Small.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Sqrt.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\SqrtPi.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Stdev.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\StdevP.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Subtotal.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Sum.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\SumIf.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\SumIfs.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\SumProduct.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Sumsq.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Tan.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Tanh.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Trunc.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Var.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\VarMethods.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\VarP.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Numeric\CInt.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\ObjectEnumerableArgConverter.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\Address.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\ArrayLookupNavigator.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\Choose.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\Column.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\Columns.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\ExcelLookupNavigator.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\HLookup.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\Index.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\Indirect.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\Lookup.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\LookupArguments.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\LookupDirection.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\LookupFunction.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\LookupNavigator.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\LookupNavigatorFactory.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\Match.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\Offset.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\Row.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\Rows.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\VLookup.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\CharFunction.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Concatenate.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\CStr.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Exact.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Find.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Fixed.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Hyperlink.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Left.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Len.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Lower.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Rept.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Text.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Mid.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Proper.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Replace.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Right.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Substitute.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\T.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Upper.cs" />
-    <Compile Include="FormulaParsing\Excel\Operators\IOperator.cs" />
-    <Compile Include="FormulaParsing\Excel\Operators\Operator.cs" />
-    <Compile Include="FormulaParsing\Excel\Operators\Operators.cs" />
-    <Compile Include="FormulaParsing\Excel\Operators\OperatorsDict.cs" />
-    <Compile Include="FormulaParsing\Exceptions\CircularReferenceException.cs" />
-    <Compile Include="FormulaParsing\Exceptions\ExcelErrorCodes.cs" />
-    <Compile Include="FormulaParsing\Exceptions\ExcelErrorValueException.cs" />
-    <Compile Include="FormulaParsing\Exceptions\UnrecognizedTokenException.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\AtomicExpression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\BooleanExpression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\CompileResult.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\CompileResultFactory.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\CompileStrategy\CompileStrategy.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\CompileStrategy\CompileStrategyFactory.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\CompileStrategy\DefaultCompileStrategy.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\CompileStrategy\ICompileStrategyFactory.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\CompileStrategy\StringConcatStrategy.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\ExcelErrorExpression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\DataType.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\DateExpression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\DecimalExpression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\EnumerableExpression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\ExcelAddressExpression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\Expression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\ExpressionCompiler.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\ConstantExpressions.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\ExpressionConverter.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\ExpressionFactory.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\ExpressionGraph.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\ExpressionGraphBuilder.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\FunctionArgumentExpression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\FunctionCompilers\DefaultCompiler.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\FunctionCompilers\ErrorHandlingFunctionCompiler.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\FunctionCompilers\FunctionCompiler.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\FunctionCompilers\FunctionCompilerFactory.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\FunctionCompilers\IfErrorFunctionCompiler.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\FunctionCompilers\IfFunctionCompiler.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\FunctionCompilers\IfNaFunctionCompiler.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\FunctionCompilers\LookupFunctionCompiler.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\FunctionExpression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\GroupExpression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\IExpressionCompiler.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\IExpressionConverter.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\IExpressionFactory.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\IExpressionGraphBuilder.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\IntegerExpression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\NamedValueExpression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\StringExpression.cs" />
-    <Compile Include="FormulaParsing\FormulaParser.cs" />
-    <Compile Include="FormulaParsing\FormulaParserManager.cs" />
-    <Compile Include="FormulaParsing\Logging\IFormulaParserLogger.cs" />
-    <Compile Include="FormulaParsing\INameValueProvider.cs" />
-    <Compile Include="FormulaParsing\IParsingLifetimeEventHandler.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\FunctionNameProvider.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\ILexer.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\ISourceCodeTokenizer.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\ISyntacticAnalyzer.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\ITokenFactory.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\ITokenSeparatorProvider.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\Lexer.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\SourceCodeTokenizer.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\SyntacticAnalyzer.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\Token.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\TokenFactory.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\TokenizerContext.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\TokenSeparatorProvider.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\TokenType.cs" />
-    <Compile Include="FormulaParsing\EpplusNameValueProvider.cs" />
-    <Compile Include="FormulaParsing\Logging\LoggerFactory.cs" />
-    <Compile Include="FormulaParsing\Logging\TextFileLogger.cs" />
-    <Compile Include="FormulaParsing\NameValueProvider.cs" />
-    <Compile Include="FormulaParsing\ParsedValue.cs" />
-    <Compile Include="FormulaParsing\ParsingConfiguration.cs" />
-    <Compile Include="FormulaParsing\ParsingContext.cs" />
-    <Compile Include="FormulaParsing\ParsingScope.cs" />
-    <Compile Include="FormulaParsing\ParsingScopes.cs" />
-    <Compile Include="FormulaParsing\Utilities\ArgumentInfo.cs" />
-    <Compile Include="FormulaParsing\Utilities\ExtensionMethods.cs" />
-    <Compile Include="FormulaParsing\Utilities\IdProvider.cs" />
-    <Compile Include="FormulaParsing\Utilities\IntegerIdProvider.cs" />
-    <Compile Include="FormulaParsing\Utilities\RegexConstants.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="FormulaParsing\Utilities\Require.cs" />
-    <Compile Include="Packaging\DotNetZip\ComHelper.cs" />
-    <Compile Include="Packaging\DotNetZip\CRC32.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\EncryptionAlgorithm.cs" />
-    <Compile Include="Packaging\DotNetZip\Events.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\Exceptions.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\ExtractExistingFileAction.cs" />
-    <Compile Include="Packaging\DotNetZip\FileSelector.cs" />
-    <Compile Include="Packaging\DotNetZip\OffsetStream.cs" />
-    <Compile Include="Packaging\DotNetZip\Shared.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\WinZipAes.cs" />
-    <Compile Include="Packaging\DotNetZip\ZipConstants.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\ZipCrypto.cs" />
-    <Compile Include="Packaging\DotNetZip\ZipDirEntry.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\ZipEntry.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\ZipEntry.Extract.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\ZipEntry.Read.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\ZipEntry.Write.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\ZipEntrySource.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\ZipErrorAction.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\ZipFile.AddUpdate.cs" />
-    <Compile Include="Packaging\DotNetZip\ZipFile.Check.cs" />
-    <Compile Include="Packaging\DotNetZip\ZipFile.cs" />
-    <Compile Include="Packaging\DotNetZip\ZipFile.Events.cs" />
-    <Compile Include="Packaging\DotNetZip\ZipFile.Extract.cs" />
-    <Compile Include="Packaging\DotNetZip\ZipFile.Read.cs" />
-    <Compile Include="Packaging\DotNetZip\ZipFile.Save.cs" />
-    <Compile Include="Packaging\DotNetZip\ZipFile.SaveSelfExtractor.cs" />
-    <Compile Include="Packaging\DotNetZip\ZipFile.Selector.cs" />
-    <Compile Include="Packaging\DotNetZip\ZipFile.x-IEnumerable.cs" />
-    <Compile Include="Packaging\DotNetZip\ZipInputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\ZipOutputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\ZipSegmentedStream.cs" />
-    <Compile Include="Packaging\DotNetZip\Zlib\Deflate.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\Zlib\DeflateStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\Zlib\GZipStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\Zlib\Inflate.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\Zlib\InfTree.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\Zlib\ParallelDeflateOutputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\Zlib\Tree.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\Zlib\Zlib.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\Zlib\ZlibBaseStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\Zlib\ZlibCodec.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\Zlib\ZlibConstants.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\Zlib\ZlibStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="RangeCollection.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Utils\ConvertUtil.cs" />
-    <Compile Include="Utils\UriHelper.cs" />
-    <Compile Include="Packaging\ZipPackage.cs" />
-    <Compile Include="VBA\ExcelVbaModule.cs" />
-    <Compile Include="VBA\ExcelVbaModuleAttribute.cs" />
-    <Compile Include="VBA\ExcelVbaModuleCollection.cs" />
-    <Compile Include="VBA\ExcelVbaProject.cs" />
-    <Compile Include="ExcelWorkbookView.cs" />
-    <Compile Include="ExcelWorksheetView.cs" />
-    <Compile Include="Style\Dxf\DxfStyleBase.cs" />
-    <Compile Include="Style\Dxf\ExcelDxfBorder.cs" />
-    <Compile Include="Style\Dxf\ExcelDxfBorderItem.cs" />
-    <Compile Include="Style\Dxf\ExcelDxfColor.cs" />
-    <Compile Include="Style\Dxf\ExcelDxfFill.cs" />
-    <Compile Include="Style\Dxf\ExcelDxfFontBase.cs" />
-    <Compile Include="Style\Dxf\ExcelDxfNumberFormat.cs" />
-    <Compile Include="Style\Dxf\ExcelDxfStyle.cs" />
-    <Compile Include="Style\ExcelGradientFill.cs" />
-    <Compile Include="Style\XmlAccess\ExcelGradientFillXml.cs" />
-    <Compile Include="Table\PivotTable\ExcelPivotTableFieldGroup.cs" />
-    <Compile Include="Table\PivotTable\ExcelPivotTableFieldItem.cs" />
-    <Compile Include="Table\PivotTable\ExcelPivotTablePageFieldSettings.cs" />
-    <Compile Include="Table\PivotTable\ExcelPivotTableDataField.cs" />
-    <Compile Include="Table\PivotTable\ExcelPivotTableFieldCollection.cs" />
-    <Compile Include="Style\IStyle.cs" />
-    <Compile Include="OfficeProperties.cs" />
-    <Compile Include="ExcelWorkbook.cs" />
-    <Compile Include="ExcelWorksheet.cs" />
-    <Compile Include="ExcelWorksheets.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="Style\XmlAccess\ExcelBorderXml.cs" />
-    <Compile Include="Style\XmlAccess\ExcelBorderItemXml.cs" />
-    <Compile Include="Style\XmlAccess\ExcelXfsXml.cs" />
-    <Compile Include="Style\XmlAccess\ExcelNamedStyleXml.cs" />
-    <Compile Include="Style\XmlAccess\ExcelColorXml.cs" />
-    <Compile Include="Style\XmlAccess\ExcelFillXml.cs" />
-    <Compile Include="Style\XmlAccess\ExcelFontXml.cs" />
-    <Compile Include="Style\XmlAccess\ExcelNumberFormatXml.cs" />
-    <Compile Include="Style\StyleChangeEventArgs.cs" />
-    <Compile Include="Table\PivotTable\ExcelPivotCacheDefinition.cs" />
-    <Compile Include="Table\PivotTable\ExcelPivotTableField.cs" />
-    <Compile Include="Table\PivotTable\ExcelPivotTableCollection.cs" />
-    <Compile Include="Table\PivotTable\ExcelPivotTable.cs" />
-    <Compile Include="Table\ExcelTableColumnCollection.cs" />
-    <Compile Include="Table\ExcelTable.cs" />
-    <Compile Include="Table\ExcelTableCollection.cs" />
-    <Compile Include="Table\ExcelTableColumn.cs" />
-    <Compile Include="Utils\AddressUtility.cs" />
-    <Compile Include="Utils\Argument.cs" />
-    <Compile Include="Utils\ArgumentExtensions.cs" />
-    <Compile Include="Utils\CompoundDocument.cs" />
-    <Compile Include="Utils\IArgument.cs" />
-    <Compile Include="Utils\Require.cs" />
-    <Compile Include="Utils\SqRefUtility.cs" />
-    <Compile Include="VBA\ExcelVbaProtection.cs" />
-    <Compile Include="VBA\ExcelVbaReference.cs" />
-    <Compile Include="VBA\ExcelVbaSignature.cs" />
-    <Compile Include="XmlHelper.cs" />
-    <Compile Include="XmlHelperFactory.cs" />
-    <Compile Include="Packaging\ZipPackagePart.cs" />
-    <Compile Include="Packaging\ZipPackageRelationship.cs" />
-    <Compile Include="Packaging\ZipPackageRelationshipCollection.cs" />
-    <Compile Include="Packaging\ZipPackageRelationshipBase.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="Drawing\Chart\ExcelLineChart.cs" />
-    <Compile Include="Drawing\Vml\ExcelVmlDrawingComment.cs" />
-    <Compile Include="Drawing\Vml\ExcelVmlDrawingPosition.cs" />
-    <Compile Include="Drawing\Vml\ExcelVmlDrawingBaseCollection.cs" />
-    <Compile Include="ExcelAddress.cs" />
-    <Compile Include="ExcelCellAddress.cs" />
-    <Compile Include="ExcelComment.cs" />
-    <Compile Include="ExcelCommentCollection.cs" />
-    <Compile Include="ExcelSheetProtection.cs" />
-    <Compile Include="Drawing\Chart\ExcelChartLegend.cs" />
-    <Compile Include="Drawing\Chart\ExcelChartPlotArea.cs" />
-    <Compile Include="Drawing\Chart\ExcelChartSerieDataLabel.cs" />
-    <Compile Include="Drawing\Chart\ExcelScatterChartSerie.cs" />
-    <Compile Include="Drawing\Chart\ExcelChartTitle.cs" />
-    <Compile Include="Drawing\ExcelDrawingBorder.cs" />
-    <Compile Include="Drawing\Chart\ExcelOfPieChart.cs" />
-    <Compile Include="Drawing\ExcelDrawingFill.cs" />
-    <Compile Include="Drawing\Chart\ExcelPieChartSerie.cs" />
-    <Compile Include="Drawing\ExcelView3D.cs" />
-    <Compile Include="Drawing\Chart\ExcelBarChart.cs" />
-    <Compile Include="Drawing\Chart\ExcelChartAxis.cs" />
-    <Compile Include="Drawing\Chart\ExcelChartDataLabel.cs" />
-    <Compile Include="Drawing\Chart\ExcelChartSerie.cs" />
-    <Compile Include="Drawing\Chart\ExcelChartSeries.cs" />
-    <Compile Include="Drawing\Chart\ExcelDoughnutChart.cs" />
-    <Compile Include="Drawing\Chart\ExcelPieChart.cs" />
-    <Compile Include="Drawing\Chart\ExcelScatterChart.cs" />
-    <Compile Include="ExcelCellBase.cs" />
-    <Compile Include="ExcelHyperLink.cs" />
-    <Compile Include="ExcelNamedRange.cs" />
-    <Compile Include="ExcelNamedRangeCollection.cs" />
-    <Compile Include="ExcelPrinterSettings.cs" />
-    <Compile Include="ExcelRangeBase.cs" />
-    <Compile Include="IRangeID.cs" />
-    <Compile Include="Style\ExcelParagraph.cs" />
-    <Compile Include="Style\ExcelParagraphCollection.cs" />
-    <Compile Include="Style\ExcelBorder.cs" />
-    <Compile Include="Style\ExcelBorderItem.cs" />
-    <Compile Include="Style\ExcelColor.cs" />
-    <Compile Include="Style\ExcelFill.cs" />
-    <Compile Include="Style\ExcelRichText.cs" />
-    <Compile Include="Style\ExcelRichTextCollection.cs" />
-    <Compile Include="Utils\IExcelCell.cs" />
-    <Compile Include="Style\ExcelStyle.cs" />
-    <Compile Include="Style\ExcelFont.cs" />
-    <Compile Include="Style\XmlAccess\StyleXmlHelper.cs" />
-    <Compile Include="Style\ExcelNumberFormat.cs" />
-    <Compile Include="Style\StyleBase.cs" />
-    <Compile Include="Style\ExcelTextFont.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="OpenOfficeXml.snk" />
-  </ItemGroup>
-  <ItemGroup>
-    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
-      <Visible>False</Visible>
-      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
-      <Install>false</Install>
-    </BootstrapperPackage>
-    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
-      <Visible>False</Visible>
-      <ProductName>.NET Framework 3.5 SP1</ProductName>
-      <Install>true</Install>
-    </BootstrapperPackage>
-    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
-      <Visible>False</Visible>
-      <ProductName>Windows Installer 3.1</ProductName>
-      <Install>true</Install>
-    </BootstrapperPackage>
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="ConditionalFormatting\CF Implementation.cs" />
-  </ItemGroup>
-  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
-  <PropertyGroup>
-    <PostBuildEvent>
-    </PostBuildEvent>
-    <PreBuildEvent>
-    </PreBuildEvent>
-  </PropertyGroup>
-</Project>
\ No newline at end of file
diff --git a/EPPlus/EPPlusNet4.csproj b/EPPlus/EPPlusNet4.csproj
deleted file mode 100644
index 3f7b3b0..0000000
--- a/EPPlus/EPPlusNet4.csproj
+++ /dev/null
@@ -1,860 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProductVersion>9.0.30729</ProductVersion>
-    <SchemaVersion>2.0</SchemaVersion>
-    <ProjectGuid>{BE4A6343-F411-44A3-8D6F-F40747ED7BA5}</ProjectGuid>
-    <OutputType>Library</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>OfficeOpenXml</RootNamespace>
-    <AssemblyName>EPPlus</AssemblyName>
-    <SignAssembly>true</SignAssembly>
-    <AssemblyOriginatorKeyFile>OpenOfficeXml.snk</AssemblyOriginatorKeyFile>
-    <SccProjectName>
-    </SccProjectName>
-    <SccLocalPath>
-    </SccLocalPath>
-    <SccAuxPath>
-    </SccAuxPath>
-    <SccProvider>
-    </SccProvider>
-    <FileUpgradeFlags>
-    </FileUpgradeFlags>
-    <UpgradeBackupLocation>
-    </UpgradeBackupLocation>
-    <OldToolsVersion>3.5</OldToolsVersion>
-    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
-    <PublishUrl>publish\</PublishUrl>
-    <Install>true</Install>
-    <InstallFrom>Disk</InstallFrom>
-    <UpdateEnabled>false</UpdateEnabled>
-    <UpdateMode>Foreground</UpdateMode>
-    <UpdateInterval>7</UpdateInterval>
-    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
-    <UpdatePeriodically>false</UpdatePeriodically>
-    <UpdateRequired>false</UpdateRequired>
-    <MapFileExtensions>true</MapFileExtensions>
-    <ApplicationRevision>0</ApplicationRevision>
-    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
-    <IsWebBootstrapper>false</IsWebBootstrapper>
-    <UseApplicationTrust>false</UseApplicationTrust>
-    <BootstrapperEnabled>true</BootstrapperEnabled>
-    <TargetFrameworkProfile>Client</TargetFrameworkProfile>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug4\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <DocumentationFile>bin\Debug4\EPPlus.XML</DocumentationFile>
-    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
-    <PlatformTarget>AnyCPU</PlatformTarget>
-    <NoWarn>15191, CS1591</NoWarn>
-    <Prefer32Bit>false</Prefer32Bit>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release4\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <DocumentationFile>bin\Release4\EPPlus.XML</DocumentationFile>
-    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
-    <PlatformTarget>AnyCPU</PlatformTarget>
-    <Prefer32Bit>false</Prefer32Bit>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'DevTest|AnyCPU'">
-    <OutputPath>bin\</OutputPath>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="PresentationCore" />
-    <Reference Include="System" />
-    <Reference Include="System.Core">
-      <HintPath>C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.Core.dll</HintPath>
-    </Reference>
-    <Reference Include="System.Data" />
-    <Reference Include="System.Drawing" />
-    <Reference Include="System.Security" />
-    <Reference Include="System.Xml" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="CellStore.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingAverageGroup.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingBeginsWith.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingBetween.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingColorScaleGroup.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingContainsBlanks.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingContainsErrors.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingContainsText.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingDataBarGroup.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingDuplicateValues.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingEndsWith.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingEqual.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingExpression.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingGreaterThan.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingGreaterThanOrEqual.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingThreeIconSet.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingFourIconSet.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingFiveIconSet.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingIconSetGroup.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingThreeColorScale.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingLessThan.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingLessThanOrEqual.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingNotBetween.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingNotContainsBlanks.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingNotContainsErrors.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingNotContainsText.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingNotEqual.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingStdDevGroup.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingTimePeriodGroup.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingTopBottomGroup.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingTwoColorScale.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingUniqueValues.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingWithFormula.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingWithFormula2.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingWithRank.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingWithReverse.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingWithShowValue.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingWithStdDev.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingWithText.cs" />
-    <Compile Include="ConditionalFormatting\ExcelConditionalFormattingIconDataBarValue.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingDataBar.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingFiveIconSet.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingFourIconSet.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingAboveStdDev.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingAboveOrEqualAverage.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingAverageGroup.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingAboveAverage.cs" />
-    <Compile Include="ConditionalFormatting\ExcelConditionalFormattingCollection.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\ExcelConditionalFormattingOperatorType.cs" />
-    <Compile Include="ConditionalFormatting\ExcelConditionalFormattingRuleFactory.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\ExcelConditionalFormattingConstants.cs" />
-    <Compile Include="ConditionalFormatting\ExcelConditionalFormattingTimePeriodType.cs" />
-    <Compile Include="ConditionalFormatting\ExcelConditionalFormattingColorScaleValue.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\ExcelConditionalFormattingEnums.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\ExcelConditionalFormattingValueObjectType.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingBeginsWith.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingBelowAverage.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingBelowOrEqualAverage.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingBelowStdDev.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingBetween.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingBottom.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingBottomPercent.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingContainsBlanks.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingContainsErrors.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingContainsText.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingDuplicateValues.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingEndsWith.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingEqual.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingExpression.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingGreaterThan.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingGreaterThanOrEqual.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingLast7Days.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingLastMonth.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingLastWeek.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingLessThan.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingLessThanOrEqual.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingNextMonth.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingNextWeek.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingNotBetween.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingNotContainsBlanks.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingNotContainsErrors.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingNotContainsText.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingNotEqual.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingRule.cs" />
-    <Compile Include="ConditionalFormatting\ExcelConditionalFormattingRuleType.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingThisMonth.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingThisWeek.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingThreeColorScale.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingThreeIconSet.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingTimePeriodGroup.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingToday.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingTomorrow.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingTop.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingTopPercent.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingTwoColorScale.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IExcelConditionalFormattingRule.cs" />
-    <Compile Include="ConditionalFormatting\ExcelConditionalFormattingHelper.cs" />
-    <Compile Include="ConditionalFormatting\Contracts\IRangeConditionalFormatting.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\RangeConditionalFormatting.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingUniqueValues.cs" />
-    <Compile Include="ConditionalFormatting\Rules\ExcelConditionalFormattingYesterday.cs" />
-    <Compile Include="FontSize.cs" />
-    <Compile Include="DataValidation\Contracts\IExcelDataValidation.cs" />
-    <Compile Include="DataValidation\Contracts\IExcelDataValidationAny.cs" />
-    <Compile Include="DataValidation\Contracts\IExcelDataValidationCustom.cs" />
-    <Compile Include="DataValidation\Contracts\IExcelDataValidationDateTime.cs" />
-    <Compile Include="DataValidation\Contracts\IExcelDataValidationDecimal.cs" />
-    <Compile Include="DataValidation\Contracts\IExcelDataValidationInt.cs" />
-    <Compile Include="DataValidation\Contracts\IExcelDataValidationList.cs" />
-    <Compile Include="DataValidation\Contracts\IExcelDataValidationTime.cs" />
-    <Compile Include="DataValidation\Contracts\IExcelDataValidationWithFormula.cs" />
-    <Compile Include="DataValidation\Contracts\IExcelDataValidationWithFormula2.cs" />
-    <Compile Include="DataValidation\Contracts\IExcelDataValidationWithOperator.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationAny.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationCustom.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationDateTime.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationFactory.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationTime.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationWithFormula.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationWithFormula2.cs" />
-    <Compile Include="DataValidation\ExcelTime.cs" />
-    <Compile Include="DataValidation\Formulas\Contracts\IExcelDataValidationFormula.cs" />
-    <Compile Include="DataValidation\Formulas\Contracts\IExcelDataValidationFormulaDateTime.cs" />
-    <Compile Include="DataValidation\Formulas\Contracts\IExcelDataValidationFormulaTime.cs" />
-    <Compile Include="DataValidation\Formulas\ExcelDataValidationFormula.cs" />
-    <Compile Include="DataValidation\Formulas\Contracts\IExcelDataValidationFormulaList.cs" />
-    <Compile Include="DataValidation\Formulas\ExcelDataValidationFormulaCustom.cs" />
-    <Compile Include="DataValidation\Formulas\ExcelDataValidationFormulaDateTime.cs" />
-    <Compile Include="DataValidation\Formulas\ExcelDataValidationFormulaList.cs" />
-    <Compile Include="DataValidation\Formulas\Contracts\IExcelDataValidationFormulaWithValue.cs" />
-    <Compile Include="DataValidation\Formulas\Contracts\IExcelDataValidationFormulaDecimal.cs" />
-    <Compile Include="DataValidation\Formulas\Contracts\IExcelDataValidationFormulaInt.cs" />
-    <Compile Include="DataValidation\Formulas\ExcelDataValidationFormulaTime.cs" />
-    <Compile Include="DataValidation\Formulas\ExcelDataValidationFormulaValue.cs" />
-    <Compile Include="DataValidation\Formulas\ExcelDataValidationFormulaDecimal.cs" />
-    <Compile Include="DataValidation\Formulas\ExcelDataValidationFormulaInt.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationOperator.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationWarningStyle.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationDecimal.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationList.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationInt.cs" />
-    <Compile Include="DataValidation\IRangeDataValidation.cs" />
-    <Compile Include="DataValidation\RangeDataValidation.cs" />
-    <Compile Include="Drawing\Chart\ExcelBarChartSerie.cs" />
-    <Compile Include="Drawing\Chart\ExcelSurfaceChartSerie.cs" />
-    <Compile Include="Drawing\Chart\ExcelSurfaceChart.cs" />
-    <Compile Include="Drawing\Chart\ExcelRadarChart.cs" />
-    <Compile Include="Drawing\Chart\ExcelBubbleChartSerie.cs" />
-    <Compile Include="Drawing\Chart\ExcelLineChartSerie.cs" />
-    <Compile Include="Drawing\Chart\ExcelChart.cs" />
-    <Compile Include="Drawing\Chart\ExcelChartCollection.cs" />
-    <Compile Include="Drawing\Chart\ExcelChartTrendline.cs" />
-    <Compile Include="Drawing\Chart\ExcelBubbleChart.cs" />
-    <Compile Include="Drawing\Chart\ExcelChartSurface.cs" />
-    <Compile Include="Drawing\ExcelDrawingBase.cs" />
-    <Compile Include="Drawing\ExcelDrawingLineEnd.cs" />
-    <Compile Include="Drawing\ExcelPicture.cs" />
-    <Compile Include="Drawing\Chart\ExcelRadarChartSerie.cs" />
-    <Compile Include="Drawing\Vml\ExcelVmlDrawingPictureCollection.cs" />
-    <Compile Include="Drawing\Vml\ExcelVmlDrawingCommentCollection.cs" />
-    <Compile Include="Drawing\Vml\ExcelVmlDrawingPicture.cs" />
-    <Compile Include="Drawing\Vml\ExcelVmlDrawingBase.cs" />
-    <Compile Include="Encryption\EncryptionHandler.cs" />
-    <Compile Include="Encryption\EncryptionHeader.cs" />
-    <Compile Include="Encryption\EncryptionInfo.cs" />
-    <Compile Include="Encryption\EncryptionVerifier.cs" />
-    <Compile Include="ExcelBackgroundImage.cs" />
-    <Compile Include="DataValidation\ExcelDataValidation.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationCollection.cs" />
-    <Compile Include="DataValidation\ExcelDataValidationType.cs" />
-    <Compile Include="ExcelEncryption.cs" />
-    <Compile Include="ExcelProtectedRange.cs" />
-    <Compile Include="ExcelProtectedRangeCollection.cs" />
-    <Compile Include="ExcelRangeCopyOptionFlags.cs" />
-    <Compile Include="ExcelStyleCollection.cs" />
-    <Compile Include="ExcelColumn.cs" />
-    <Compile Include="Drawing\ExcelDrawings.cs" />
-    <Compile Include="ExcelHeaderFooter.cs" />
-    <Compile Include="ExcelPackage.cs" />
-    <Compile Include="ExcelRange.cs" />
-    <Compile Include="ExcelRow.cs" />
-    <Compile Include="Drawing\ExcelShape.cs" />
-    <Compile Include="ExcelStyles.cs" />
-    <Compile Include="ExcelProtection.cs" />
-    <Compile Include="ExcelTextFormat.cs" />
-    <Compile Include="FormulaParsing\CalculateExtentions.cs" />
-    <Compile Include="FormulaParsing\DependencyChain\DependenyChainFactory.cs" />
-    <Compile Include="FormulaParsing\DependencyChain\DependencyChain.cs" />
-    <Compile Include="FormulaParsing\DependencyChain\FormulaCell.cs" />
-    <Compile Include="FormulaParsing\EpplusExcelDataProvider.cs" />
-    <Compile Include="FormulaParsing\ExcelCalculationOption.cs" />
-    <Compile Include="FormulaParsing\ExcelCell.cs" />
-    <Compile Include="FormulaParsing\ExcelDataProvider.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\AddressTranslator.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\CellReferenceProvider.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\ExcelAddressInfo.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\ExcelAddressUtil.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\ExcelReferenceType.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\ExpressionEvaluator.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\FormulaDependencies.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\FormulaDependency.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\FormulaDependencyFactory.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\IndexToAddressTranslator.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\LookupValueMatcher.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\RangeAddress.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\RangeAddressFactory.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\ValueMatcher.cs" />
-    <Compile Include="FormulaParsing\ExcelUtilities\WildCardValueMatcher.cs" />
-    <Compile Include="FormulaParsing\ExcelValues.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\CompileResultValidator.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\CompileResultValidators.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\CellStateHelper.cs" />
-    <Compile Include="FormulaParsing\Excel\ExcelCellState.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\ArgumentCollectionUtil.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\ArgumentParser.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\ArgumentParserFactory.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\ArgumentParsers.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\BoolArgumentParser.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\BuiltInFunctions.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\CollectionFlattener.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\DatabaseFunction.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\Daverage.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\Dcount.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\DcountA.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\Dget.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\Dmax.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\Dmin.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\Dsum.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\Dvar.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="FormulaParsing\Excel\Functions\Database\Dvarp.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\ExcelDatabase.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\ExcelDatabaseCriteria.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\ExcelDatabaseCriteriaField.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\ExcelDatabaseField.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\ExcelDatabaseRow.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Database\RowMatcher.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Date.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\DateParsingFunction.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\DateStringParser.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\DateValue.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Day.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Days360.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Edate.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Eomonth.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Hour.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\IsoWeekNum.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\TimeValue.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Weeknum.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Minute.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Month.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Now.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Second.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Time.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\TimeBaseFunction.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\TimeStringParser.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Today.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Weekday.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Workday.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Year.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DateTime\Yearfrac.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DecimalCompileResultValidator.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DoubleArgumentParser.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\DoubleEnumerableArgConverter.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\ErrorHandlingFunction.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\ExcelFunction.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\FunctionArgument.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\FunctionRepository.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\FunctionsModule.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\HiddenValuesHandlingFunction.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\IFunctionModule.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\IFunctionNameProvider.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\ErrorType.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\IsBlank.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\IsErr.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\IsError.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\IsEven.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\IsLogical.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\IsNa.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\IsNonText.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\IsNumber.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\IsOdd.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\IsText.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\N.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Information\Na.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\IntArgumentParser.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Logical\And.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Logical\False.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Logical\If.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Logical\IfError.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Logical\IfNa.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Logical\Not.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Logical\Or.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Logical\True.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Abs.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Acos.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Acosh.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Asin.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Asinh.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Atan.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Atan2.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Atanh.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Average.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\AverageA.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\AverageIf.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\AverageIfs.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Ceiling.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Cos.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Cosh.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Count.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\CountA.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\CountBlank.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\CountIf.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\CountIfs.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Degrees.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Exp.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Fact.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Floor.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Large.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Ln.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Log.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Log10.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\MathHelper.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Max.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Maxa.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Median.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Min.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Mina.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Mod.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\MultipleRangeCriteriasFunction.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Pi.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Power.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Product.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Quotient.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Rank.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Rand.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\RandBetween.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Round.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Rounddown.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Roundup.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Sign.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Sin.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Sinh.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Small.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Sqrt.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\SqrtPi.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Stdev.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\StdevP.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Subtotal.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Sum.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\SumIf.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\SumIfs.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\SumProduct.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Sumsq.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Tan.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Tanh.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Trunc.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\Var.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\VarMethods.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Math\VarP.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Numeric\CInt.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\ObjectEnumerableArgConverter.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\Address.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\ArrayLookupNavigator.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\Choose.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\Column.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\Columns.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\ExcelLookupNavigator.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\HLookup.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\Index.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\Indirect.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\Lookup.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\LookupArguments.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\LookupDirection.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\LookupFunction.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\LookupNavigator.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\LookupNavigatorFactory.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\Match.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\Offset.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\Row.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\Rows.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\RefAndLookup\VLookup.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\CharFunction.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Concatenate.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\CStr.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Exact.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Find.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Fixed.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Hyperlink.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Left.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Len.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Lower.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Rept.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Search.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Text.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Mid.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Proper.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Replace.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Right.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Substitute.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\T.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Upper.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\Text\Value.cs" />
-    <Compile Include="FormulaParsing\Excel\Operators\IOperator.cs" />
-    <Compile Include="FormulaParsing\Excel\Operators\Operator.cs" />
-    <Compile Include="FormulaParsing\Excel\Operators\Operators.cs" />
-    <Compile Include="FormulaParsing\Excel\Operators\OperatorsDict.cs" />
-    <Compile Include="FormulaParsing\Exceptions\CircularReferenceException.cs" />
-    <Compile Include="FormulaParsing\Exceptions\ExcelErrorCodes.cs" />
-    <Compile Include="FormulaParsing\Exceptions\ExcelErrorValueException.cs" />
-    <Compile Include="FormulaParsing\Exceptions\UnrecognizedTokenException.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\AtomicExpression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\BooleanExpression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\CompileResult.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\CompileResultFactory.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\CompileStrategy\CompileStrategy.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\CompileStrategy\CompileStrategyFactory.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\CompileStrategy\DefaultCompileStrategy.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\CompileStrategy\ICompileStrategyFactory.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\CompileStrategy\StringConcatStrategy.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\ExcelErrorExpression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\DataType.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\DateExpression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\DecimalExpression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\EnumerableExpression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\ExcelAddressExpression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\Expression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\ExpressionCompiler.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\ConstantExpressions.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\ExpressionConverter.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\ExpressionFactory.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\ExpressionGraph.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\ExpressionGraphBuilder.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\FunctionArgumentExpression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\FunctionCompilers\DefaultCompiler.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\FunctionCompilers\ErrorHandlingFunctionCompiler.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\FunctionCompilers\FunctionCompiler.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\FunctionCompilers\FunctionCompilerFactory.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\FunctionCompilers\IfErrorFunctionCompiler.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\FunctionCompilers\IfFunctionCompiler.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\FunctionCompilers\IfNaFunctionCompiler.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\FunctionCompilers\LookupFunctionCompiler.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\FunctionExpression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\GroupExpression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\IExpressionCompiler.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\IExpressionConverter.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\IExpressionFactory.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\IExpressionGraphBuilder.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\IntegerExpression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\NamedValueExpression.cs" />
-    <Compile Include="FormulaParsing\ExpressionGraph\StringExpression.cs" />
-    <Compile Include="FormulaParsing\FormulaParser.cs" />
-    <Compile Include="FormulaParsing\FormulaParserManager.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\ITokenIndexProvider.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\TokenHandler.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\TokenSeparatorHandlers\BracketHandler.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\TokenSeparatorHandlers\MultipleCharSeparatorHandler.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\TokenSeparatorHandlers\SeparatorHandler.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\TokenSeparatorHandlers\SheetnameHandler.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\TokenSeparatorHandlers\StringHandler.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\TokenSeparatorHandlers\TokenSeparatorHandler.cs" />
-    <Compile Include="FormulaParsing\Logging\IFormulaParserLogger.cs" />
-    <Compile Include="FormulaParsing\INameValueProvider.cs" />
-    <Compile Include="FormulaParsing\IParsingLifetimeEventHandler.cs" />
-    <Compile Include="FormulaParsing\Excel\Functions\FunctionNameProvider.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\ILexer.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\ISourceCodeTokenizer.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\ISyntacticAnalyzer.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\ITokenFactory.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\ITokenSeparatorProvider.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\Lexer.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\SourceCodeTokenizer.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\SyntacticAnalyzer.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\Token.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\TokenFactory.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\TokenizerContext.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\TokenSeparatorProvider.cs" />
-    <Compile Include="FormulaParsing\LexicalAnalysis\TokenType.cs" />
-    <Compile Include="FormulaParsing\EpplusNameValueProvider.cs" />
-    <Compile Include="FormulaParsing\Logging\LoggerFactory.cs" />
-    <Compile Include="FormulaParsing\Logging\TextFileLogger.cs" />
-    <Compile Include="FormulaParsing\NameValueProvider.cs" />
-    <Compile Include="FormulaParsing\ParsedValue.cs" />
-    <Compile Include="FormulaParsing\ParsingConfiguration.cs" />
-    <Compile Include="FormulaParsing\ParsingContext.cs" />
-    <Compile Include="FormulaParsing\ParsingScope.cs" />
-    <Compile Include="FormulaParsing\ParsingScopes.cs" />
-    <Compile Include="FormulaParsing\Utilities\ArgumentInfo.cs" />
-    <Compile Include="FormulaParsing\Utilities\ExtensionMethods.cs" />
-    <Compile Include="FormulaParsing\Utilities\IdProvider.cs" />
-    <Compile Include="FormulaParsing\Utilities\IntegerIdProvider.cs" />
-    <Compile Include="FormulaParsing\Utilities\RegexConstants.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="FormulaParsing\Utilities\Require.cs" />
-    <Compile Include="Packaging\DotNetZip\ComHelper.cs" />
-    <Compile Include="Packaging\DotNetZip\CRC32.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\EncryptionAlgorithm.cs" />
-    <Compile Include="Packaging\DotNetZip\Events.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\Exceptions.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\ExtractExistingFileAction.cs" />
-    <Compile Include="Packaging\DotNetZip\FileSelector.cs" />
-    <Compile Include="Packaging\DotNetZip\OffsetStream.cs" />
-    <Compile Include="Packaging\DotNetZip\Shared.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\WinZipAes.cs" />
-    <Compile Include="Packaging\DotNetZip\ZipConstants.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\ZipCrypto.cs" />
-    <Compile Include="Packaging\DotNetZip\ZipDirEntry.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\ZipEntry.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\ZipEntry.Extract.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\ZipEntry.Read.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\ZipEntry.Write.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\ZipEntrySource.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\ZipErrorAction.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\ZipFile.AddUpdate.cs" />
-    <Compile Include="Packaging\DotNetZip\ZipFile.Check.cs" />
-    <Compile Include="Packaging\DotNetZip\ZipFile.cs" />
-    <Compile Include="Packaging\DotNetZip\ZipFile.Events.cs" />
-    <Compile Include="Packaging\DotNetZip\ZipFile.Extract.cs" />
-    <Compile Include="Packaging\DotNetZip\ZipFile.Read.cs" />
-    <Compile Include="Packaging\DotNetZip\ZipFile.Save.cs" />
-    <Compile Include="Packaging\DotNetZip\ZipFile.SaveSelfExtractor.cs" />
-    <Compile Include="Packaging\DotNetZip\ZipFile.Selector.cs" />
-    <Compile Include="Packaging\DotNetZip\ZipFile.x-IEnumerable.cs" />
-    <Compile Include="Packaging\DotNetZip\ZipInputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\ZipOutputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\ZipSegmentedStream.cs" />
-    <Compile Include="Packaging\DotNetZip\Zlib\Deflate.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\Zlib\DeflateStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\Zlib\GZipStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\Zlib\Inflate.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\Zlib\InfTree.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\Zlib\ParallelDeflateOutputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\Zlib\Tree.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\Zlib\Zlib.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\Zlib\ZlibBaseStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\Zlib\ZlibCodec.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\Zlib\ZlibConstants.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Packaging\DotNetZip\Zlib\ZlibStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="RangeCollection.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Utils\ConvertUtil.cs" />
-    <Compile Include="Utils\UriHelper.cs" />
-    <Compile Include="Packaging\ZipPackage.cs" />
-    <Compile Include="VBA\ExcelVbaModule.cs" />
-    <Compile Include="VBA\ExcelVbaModuleAttribute.cs" />
-    <Compile Include="VBA\ExcelVbaModuleCollection.cs" />
-    <Compile Include="VBA\ExcelVbaProject.cs" />
-    <Compile Include="ExcelWorkbookView.cs" />
-    <Compile Include="ExcelWorksheetView.cs" />
-    <Compile Include="Style\Dxf\DxfStyleBase.cs" />
-    <Compile Include="Style\Dxf\ExcelDxfBorder.cs" />
-    <Compile Include="Style\Dxf\ExcelDxfBorderItem.cs" />
-    <Compile Include="Style\Dxf\ExcelDxfColor.cs" />
-    <Compile Include="Style\Dxf\ExcelDxfFill.cs" />
-    <Compile Include="Style\Dxf\ExcelDxfFontBase.cs" />
-    <Compile Include="Style\Dxf\ExcelDxfNumberFormat.cs" />
-    <Compile Include="Style\Dxf\ExcelDxfStyle.cs" />
-    <Compile Include="Style\ExcelGradientFill.cs" />
-    <Compile Include="Style\XmlAccess\ExcelGradientFillXml.cs" />
-    <Compile Include="Table\PivotTable\ExcelPivotTableFieldGroup.cs" />
-    <Compile Include="Table\PivotTable\ExcelPivotTableFieldItem.cs" />
-    <Compile Include="Table\PivotTable\ExcelPivotTablePageFieldSettings.cs" />
-    <Compile Include="Table\PivotTable\ExcelPivotTableDataField.cs" />
-    <Compile Include="Table\PivotTable\ExcelPivotTableFieldCollection.cs" />
-    <Compile Include="Style\IStyle.cs" />
-    <Compile Include="OfficeProperties.cs" />
-    <Compile Include="ExcelWorkbook.cs" />
-    <Compile Include="ExcelWorksheet.cs" />
-    <Compile Include="ExcelWorksheets.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="Style\XmlAccess\ExcelBorderXml.cs" />
-    <Compile Include="Style\XmlAccess\ExcelBorderItemXml.cs" />
-    <Compile Include="Style\XmlAccess\ExcelXfsXml.cs" />
-    <Compile Include="Style\XmlAccess\ExcelNamedStyleXml.cs" />
-    <Compile Include="Style\XmlAccess\ExcelColorXml.cs" />
-    <Compile Include="Style\XmlAccess\ExcelFillXml.cs" />
-    <Compile Include="Style\XmlAccess\ExcelFontXml.cs" />
-    <Compile Include="Style\XmlAccess\ExcelNumberFormatXml.cs" />
-    <Compile Include="Style\StyleChangeEventArgs.cs" />
-    <Compile Include="Table\PivotTable\ExcelPivotCacheDefinition.cs" />
-    <Compile Include="Table\PivotTable\ExcelPivotTableField.cs" />
-    <Compile Include="Table\PivotTable\ExcelPivotTableCollection.cs" />
-    <Compile Include="Table\PivotTable\ExcelPivotTable.cs" />
-    <Compile Include="Table\ExcelTableColumnCollection.cs" />
-    <Compile Include="Table\ExcelTable.cs" />
-    <Compile Include="Table\ExcelTableCollection.cs" />
-    <Compile Include="Table\ExcelTableColumn.cs" />
-    <Compile Include="Utils\AddressUtility.cs" />
-    <Compile Include="Utils\Argument.cs" />
-    <Compile Include="Utils\ArgumentExtensions.cs" />
-    <Compile Include="Utils\CompoundDocument.cs" />
-    <Compile Include="Utils\IArgument.cs" />
-    <Compile Include="Utils\Require.cs" />
-    <Compile Include="Utils\SqRefUtility.cs" />
-    <Compile Include="VBA\ExcelVbaProtection.cs" />
-    <Compile Include="VBA\ExcelVbaReference.cs" />
-    <Compile Include="VBA\ExcelVbaSignature.cs" />
-    <Compile Include="XmlHelper.cs" />
-    <Compile Include="XmlHelperFactory.cs" />
-    <Compile Include="Packaging\ZipPackagePart.cs" />
-    <Compile Include="Packaging\ZipPackageRelationship.cs" />
-    <Compile Include="Packaging\ZipPackageRelationshipCollection.cs" />
-    <Compile Include="Packaging\ZipPackageRelationshipBase.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="Drawing\Chart\ExcelLineChart.cs" />
-    <Compile Include="Drawing\Vml\ExcelVmlDrawingComment.cs" />
-    <Compile Include="Drawing\Vml\ExcelVmlDrawingPosition.cs" />
-    <Compile Include="Drawing\Vml\ExcelVmlDrawingBaseCollection.cs" />
-    <Compile Include="ExcelAddress.cs" />
-    <Compile Include="ExcelCellAddress.cs" />
-    <Compile Include="ExcelComment.cs" />
-    <Compile Include="ExcelCommentCollection.cs" />
-    <Compile Include="ExcelSheetProtection.cs" />
-    <Compile Include="Drawing\Chart\ExcelChartLegend.cs" />
-    <Compile Include="Drawing\Chart\ExcelChartPlotArea.cs" />
-    <Compile Include="Drawing\Chart\ExcelChartSerieDataLabel.cs" />
-    <Compile Include="Drawing\Chart\ExcelScatterChartSerie.cs" />
-    <Compile Include="Drawing\Chart\ExcelChartTitle.cs" />
-    <Compile Include="Drawing\ExcelDrawingBorder.cs" />
-    <Compile Include="Drawing\Chart\ExcelOfPieChart.cs" />
-    <Compile Include="Drawing\ExcelDrawingFill.cs" />
-    <Compile Include="Drawing\Chart\ExcelPieChartSerie.cs" />
-    <Compile Include="Drawing\ExcelView3D.cs" />
-    <Compile Include="Drawing\Chart\ExcelBarChart.cs" />
-    <Compile Include="Drawing\Chart\ExcelChartAxis.cs" />
-    <Compile Include="Drawing\Chart\ExcelChartDataLabel.cs" />
-    <Compile Include="Drawing\Chart\ExcelChartSerie.cs" />
-    <Compile Include="Drawing\Chart\ExcelChartSeries.cs" />
-    <Compile Include="Drawing\Chart\ExcelDoughnutChart.cs" />
-    <Compile Include="Drawing\Chart\ExcelPieChart.cs" />
-    <Compile Include="Drawing\Chart\ExcelScatterChart.cs" />
-    <Compile Include="ExcelCellBase.cs" />
-    <Compile Include="ExcelHyperLink.cs" />
-    <Compile Include="ExcelNamedRange.cs" />
-    <Compile Include="ExcelNamedRangeCollection.cs" />
-    <Compile Include="ExcelPrinterSettings.cs" />
-    <Compile Include="ExcelRangeBase.cs" />
-    <Compile Include="IRangeID.cs" />
-    <Compile Include="Style\ExcelParagraph.cs" />
-    <Compile Include="Style\ExcelParagraphCollection.cs" />
-    <Compile Include="Style\ExcelBorder.cs" />
-    <Compile Include="Style\ExcelBorderItem.cs" />
-    <Compile Include="Style\ExcelColor.cs" />
-    <Compile Include="Style\ExcelFill.cs" />
-    <Compile Include="Style\ExcelRichText.cs" />
-    <Compile Include="Style\ExcelRichTextCollection.cs" />
-    <Compile Include="Utils\IExcelCell.cs" />
-    <Compile Include="Style\ExcelStyle.cs" />
-    <Compile Include="Style\ExcelFont.cs" />
-    <Compile Include="Style\XmlAccess\StyleXmlHelper.cs" />
-    <Compile Include="Style\ExcelNumberFormat.cs" />
-    <Compile Include="Style\StyleBase.cs" />
-    <Compile Include="Style\ExcelTextFont.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="OpenOfficeXml.snk" />
-  </ItemGroup>
-  <ItemGroup>
-    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
-      <Visible>False</Visible>
-      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
-      <Install>false</Install>
-    </BootstrapperPackage>
-    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
-      <Visible>False</Visible>
-      <ProductName>.NET Framework 3.5 SP1</ProductName>
-      <Install>true</Install>
-    </BootstrapperPackage>
-    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
-      <Visible>False</Visible>
-      <ProductName>Windows Installer 3.1</ProductName>
-      <Install>true</Install>
-    </BootstrapperPackage>
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="ConditionalFormatting\CF Implementation.cs" />
-  </ItemGroup>
-  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
-  <PropertyGroup>
-    <PostBuildEvent>
-    </PostBuildEvent>
-    <PreBuildEvent>
-    </PreBuildEvent>
-  </PropertyGroup>
-</Project>
\ No newline at end of file
diff --git a/EPPlus/EPPlusSDK.csproj b/EPPlus/EPPlusSDK.csproj
deleted file mode 100644
index 2a2e866..0000000
--- a/EPPlus/EPPlusSDK.csproj
+++ /dev/null
@@ -1,9 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <TargetFramework>net8.0</TargetFramework>
-    <RootNamespace>OfficeOpenXml</RootNamespace>
-    <AssemblyName>EPPlus</AssemblyName>
-    <PackageId>Appsheet.EPPlus</PackageId>
-    <Version>1.0.6</Version>
-  </PropertyGroup>
-</Project>
diff --git a/EPPlus/ExcelAddress.cs b/EPPlus/ExcelAddress.cs
deleted file mode 100644
index 51ad999..0000000
--- a/EPPlus/ExcelAddress.cs
+++ /dev/null
@@ -1,1216 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Jan Källman		Added		18-MAR-2010
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-
-namespace OfficeOpenXml;
-
-public class ExcelTableAddress {
-  public string Name { get; set; }
-
-  public string ColumnSpan { get; set; }
-
-  public bool IsAll { get; set; }
-
-  public bool IsHeader { get; set; }
-
-  public bool IsData { get; set; }
-
-  public bool IsTotals { get; set; }
-
-  public bool IsThisRow { get; set; }
-}
-
-/// <summary>
-/// A range address
-/// </summary>
-/// <remarks>Examples of addresses are "A1" "B1:C2" "A:A" "1:1" "A1:E2,G3:G5" </remarks>
-public class ExcelAddressBase : ExcelCellBase {
-  protected internal int _fromRow = -1,
-      _toRow,
-      _fromCol,
-      _toCol;
-  protected internal bool _fromRowFixed,
-      _fromColFixed,
-      _toRowFixed,
-      _toColFixed;
-  protected internal string _wb;
-  protected internal string _ws;
-  protected internal string _address;
-
-  protected internal event EventHandler AddressChange;
-
-  internal enum eAddressCollition {
-    No,
-    Partly,
-    Inside,
-    Equal,
-  }
-
-  internal enum eShiftType {
-    Right,
-    Down,
-    EntireRow,
-    EntireColumn,
-  }
-
-  internal ExcelAddressBase() {}
-
-  /// <summary>
-  /// Creates an Address object
-  /// </summary>
-  /// <param name="fromRow">start row</param>
-  /// <param name="fromCol">start column</param>
-  /// <param name="toRow">End row</param>
-  /// <param name="toColumn">End column</param>
-  public ExcelAddressBase(int fromRow, int fromCol, int toRow, int toColumn) {
-    _fromRow = fromRow;
-    _toRow = toRow;
-    _fromCol = fromCol;
-    _toCol = toColumn;
-    Validate();
-
-    _address = GetAddress(_fromRow, _fromCol, _toRow, _toCol);
-  }
-
-  /// <summary>
-  /// Creates an Address object
-  /// </summary>
-  /// <param name="fromRow">start row</param>
-  /// <param name="fromCol">start column</param>
-  /// <param name="toRow">End row</param>
-  /// <param name="toColumn">End column</param>
-  /// <param name="fromRowFixed">start row fixed</param>
-  /// <param name="fromColFixed">start column fixed</param>
-  /// <param name="toRowFixed">End row fixed</param>
-  /// <param name="toColFixed">End column fixed</param>
-  public ExcelAddressBase(
-      int fromRow,
-      int fromCol,
-      int toRow,
-      int toColumn,
-      bool fromRowFixed,
-      bool fromColFixed,
-      bool toRowFixed,
-      bool toColFixed) {
-    _fromRow = fromRow;
-    _toRow = toRow;
-    _fromCol = fromCol;
-    _toCol = toColumn;
-    _fromRowFixed = fromRowFixed;
-    _fromColFixed = fromColFixed;
-    _toRowFixed = toRowFixed;
-    _toColFixed = toColFixed;
-    Validate();
-
-    _address = GetAddress(
-        _fromRow,
-        _fromCol,
-        _toRow,
-        _toCol,
-        _fromRowFixed,
-        fromColFixed,
-        _toRowFixed,
-        _toColFixed);
-  }
-
-  /// <summary>
-  /// Creates an Address object
-  /// </summary>
-  /// <remarks>Examples of addresses are "A1" "B1:C2" "A:A" "1:1" "A1:E2,G3:G5" </remarks>
-  /// <param name="address">The Excel Address</param>
-  public ExcelAddressBase(string address) {
-    SetAddress(address);
-  }
-
-  /// <summary>
-  /// Creates an Address object
-  /// </summary>
-  /// <remarks>Examples of addresses are "A1" "B1:C2" "A:A" "1:1" "A1:E2,G3:G5" </remarks>
-  /// <param name="address">The Excel Address</param>
-  /// <param name="pck">Reference to the package to find information about tables and names</param>
-  /// <param name="referenceAddress">The address</param>
-  protected ExcelAddressBase(
-      string address,
-      ExcelWorkbook workbook,
-      ExcelAddressBase referenceAddress) {
-    SetAddress(address);
-    SetRcFromTable(workbook, referenceAddress);
-  }
-
-  internal void SetRcFromTable(ExcelWorkbook workbook, ExcelAddressBase referenceAddress) {
-    if (string.IsNullOrEmpty(_wb) && Table != null) {
-      foreach (var ws in workbook.Worksheets) {
-        foreach (var t in ws.Tables) {
-          if (t.Name.Equals(Table.Name, StringComparison.InvariantCultureIgnoreCase)) {
-            _ws = ws.Name;
-            if (Table.IsAll) {
-              _fromRow = t.Address._fromRow;
-              _toRow = t.Address._toRow;
-            } else {
-              if (Table.IsThisRow) {
-                if (referenceAddress == null) {
-                  _fromRow = -1;
-                  _toRow = -1;
-                } else {
-                  _fromRow = referenceAddress._fromRow;
-                  _toRow = _fromRow;
-                }
-              } else if (Table.IsHeader && Table.IsData) {
-                _fromRow = t.Address._fromRow;
-                _toRow = t.ShowTotal ? t.Address._toRow - 1 : t.Address._toRow;
-              } else if (Table.IsData && Table.IsTotals) {
-                _fromRow = t.ShowHeader ? t.Address._fromRow + 1 : t.Address._fromRow;
-                _toRow = t.Address._toRow;
-              } else if (Table.IsHeader) {
-                _fromRow = t.ShowHeader ? t.Address._fromRow : -1;
-                _toRow = t.ShowHeader ? t.Address._fromRow : -1;
-              } else if (Table.IsTotals) {
-                _fromRow = t.ShowTotal ? t.Address._toRow : -1;
-                _toRow = t.ShowTotal ? t.Address._toRow : -1;
-              } else {
-                _fromRow = t.ShowHeader ? t.Address._fromRow + 1 : t.Address._fromRow;
-                _toRow = t.ShowTotal ? t.Address._toRow - 1 : t.Address._toRow;
-              }
-            }
-
-            if (string.IsNullOrEmpty(Table.ColumnSpan)) {
-              _fromCol = t.Address._fromCol;
-              _toCol = t.Address._toCol;
-              return;
-            }
-            var col = t.Address._fromCol;
-            var cols = Table.ColumnSpan.Split(':');
-            foreach (var c in t.Columns) {
-              if (_fromCol <= 0
-                  && cols[0]
-                      .Equals(
-                          c.Name,
-                          StringComparison.InvariantCultureIgnoreCase)) //Issue15063 Add invariant igore case
-              {
-                _fromCol = col;
-                if (cols.Length == 1) {
-                  _toCol = _fromCol;
-                  return;
-                }
-              } else if (cols.Length > 1
-                  && _fromCol > 0
-                  && cols[1]
-                      .Equals(
-                          c.Name,
-                          StringComparison.InvariantCultureIgnoreCase)) //Issue15063 Add invariant igore case
-              {
-                _toCol = col;
-                return;
-              }
-
-              col++;
-            }
-          }
-        }
-      }
-    }
-  }
-
-  /// <summary>
-  /// Address is an defined name
-  /// </summary>
-  /// <param name="address">the name</param>
-  /// <param name="isName">Should always be true</param>
-  internal ExcelAddressBase(string address, bool isName) {
-    if (isName) {
-      _address = address;
-      _fromRow = -1;
-      _fromCol = -1;
-      _toRow = -1;
-      _toCol = -1;
-      _start = null;
-      _end = null;
-    } else {
-      SetAddress(address);
-    }
-  }
-
-  protected internal void SetAddress(string address) {
-    address = address.Trim();
-    if (address.StartsWith("'")) {
-      SetWbWs(address);
-    } else if (address.StartsWith(
-        "[")) //Remove any external reference
-    {
-      SetWbWs(address);
-    } else {
-      _address = address;
-    }
-    if (_address.IndexOfAny(new[] { ',', '!', '[' }) > -1) {
-      //Advanced address. Including Sheet or multi or table.
-      ExtractAddress(_address);
-    } else {
-      //Simple address
-      GetRowColFromAddress(
-          _address,
-          out _fromRow,
-          out _fromCol,
-          out _toRow,
-          out _toCol,
-          out _fromRowFixed,
-          out _fromColFixed,
-          out _toRowFixed,
-          out _toColFixed);
-      _addresses = null;
-      _start = null;
-      _end = null;
-    }
-    _address = address;
-    Validate();
-  }
-
-  internal void ChangeAddress() {
-    if (AddressChange != null) {
-      AddressChange(this, new());
-    }
-  }
-
-  private void SetWbWs(string address) {
-    int pos = 0;
-
-    // Get Workbook, if any
-    if (address[pos] == '[') {
-      pos = address.IndexOf("]");
-      _wb = address.Substring(1, pos - 1);
-      pos++;
-    } else {
-      _wb = "";
-    }
-
-    // Get Worksheet
-    if (address[pos] == '\'') {
-      int startPos = pos;
-      pos = address.IndexOf("'", pos + 1);
-      while (pos < address.Length && address[pos + 1] == '\'') {
-        pos = address.IndexOf("'", pos + 2);
-      }
-      _ws = address.Substring(startPos + 1, pos - startPos - 1).Replace("''", "'");
-      pos++;
-    } else {
-      int startPos = pos;
-      pos = address.IndexOf("!", pos);
-      if (pos > -1) {
-        _ws = address.Substring(startPos, pos - startPos);
-      }
-    }
-
-    // Get Address
-    pos = address.IndexOf("!", pos);
-    if (pos > -1) {
-      _address = address.Substring(pos + 1);
-    } else {
-      _address = "";
-    }
-  }
-
-  internal void ChangeWorksheet(string wsName, string newWs) {
-    if (_ws == wsName) {
-      _ws = newWs;
-    }
-    var fullAddress = GetAddress();
-
-    if (Addresses != null) {
-      foreach (var a in Addresses) {
-        if (a._ws == wsName) {
-          a._ws = newWs;
-          fullAddress += "," + a.GetAddress();
-        } else {
-          fullAddress += "," + a._address;
-        }
-      }
-    }
-    _address = fullAddress;
-  }
-
-  private string GetAddress() {
-    var adr = "";
-    if (string.IsNullOrEmpty(_wb)) {
-      adr = "[" + _wb + "]";
-    }
-
-    if (string.IsNullOrEmpty(_ws)) {
-      adr += string.Format("'{0}'!", _ws);
-    }
-    adr += GetAddress(_fromRow, _fromCol, _toRow, _toCol);
-    return adr;
-  }
-
-  private ExcelCellAddress _start;
-
-  /// <summary>
-  /// Gets the row and column of the top left cell.
-  /// </summary>
-  /// <value>The start row column.</value>
-  public ExcelCellAddress Start {
-    get {
-      if (_start == null) {
-        _start = new(_fromRow, _fromCol);
-      }
-      return _start;
-    }
-  }
-
-  private ExcelCellAddress _end;
-
-  /// <summary>
-  /// Gets the row and column of the bottom right cell.
-  /// </summary>
-  /// <value>The end row column.</value>
-  public ExcelCellAddress End {
-    get {
-      if (_end == null) {
-        _end = new(_toRow, _toCol);
-      }
-      return _end;
-    }
-  }
-
-  private ExcelTableAddress _table;
-
-  public ExcelTableAddress Table => _table;
-
-  /// <summary>
-  /// The address for the range
-  /// </summary>
-  public virtual string Address => _address;
-
-  /// <summary>
-  /// If the address is a defined name
-  /// </summary>
-  public bool IsName => _fromRow < 0;
-
-  /// <summary>
-  /// Returns the address text
-  /// </summary>
-  /// <returns></returns>
-  public override string ToString() {
-    return _address;
-  }
-
-  private string _firstAddress;
-
-  /// <summary>
-  /// returns the first address if the address is a multi address.
-  /// A1:A2,B1:B2 returns A1:A2
-  /// </summary>
-  internal string FirstAddress {
-    get {
-      if (string.IsNullOrEmpty(_firstAddress)) {
-        return _address;
-      }
-      return _firstAddress;
-    }
-  }
-
-  internal string AddressSpaceSeparated => _address.Replace(',', ' '); //Conditional formatting and a few other places use space as separator for mulit addresses.
-
-  /// <summary>
-  /// Validate the address
-  /// </summary>
-  protected void Validate() {
-    if (_fromRow > _toRow || _fromCol > _toCol) {
-      throw new ArgumentOutOfRangeException(
-          "Start cell Address must be less or equal to End cell address");
-    }
-  }
-
-  internal string WorkSheet => _ws;
-
-  protected internal List<ExcelAddress> _addresses;
-
-  internal virtual List<ExcelAddress> Addresses => _addresses;
-
-  private bool ExtractAddress(string fullAddress) {
-    var brackPos = new Stack<int>();
-    var bracketParts = new List<string>();
-    string first = "",
-        second = "";
-    bool isText = false,
-        hasSheet = false;
-    try {
-      if (fullAddress == "#REF!") {
-        SetAddress(ref fullAddress, ref second, ref hasSheet);
-        return true;
-      }
-      if (fullAddress.StartsWith("!")) {
-        // invalid address!
-        return false;
-      }
-      for (int i = 0; i < fullAddress.Length; i++) {
-        var c = fullAddress[i];
-        if (c == '\'') {
-          if (isText && i + 1 < fullAddress.Length && fullAddress[i] == '\'') {
-            if (hasSheet) {
-              second += c;
-            } else {
-              first += c;
-            }
-          }
-          isText = !isText;
-        } else {
-          if (brackPos.Count > 0) {
-            if (c == '[' && !isText) {
-              brackPos.Push(i);
-            } else if (c == ']' && !isText) {
-              if (brackPos.Count > 0) {
-                var from = brackPos.Pop();
-                bracketParts.Add(fullAddress.Substring(from + 1, i - from - 1));
-
-                if (brackPos.Count == 0) {
-                  HandleBrackets(first, second, bracketParts);
-                }
-              } else {
-                //Invalid address!
-                return false;
-              }
-            }
-          } else if (c == '[' && !isText) {
-            brackPos.Push(i);
-          } else if (c == '!' && !isText && !first.EndsWith("#REF") && !second.EndsWith("#REF")) {
-            hasSheet = true;
-          } else if (c == ',' && !isText) {
-            SetAddress(ref first, ref second, ref hasSheet);
-          } else {
-            if (hasSheet) {
-              second += c;
-            } else {
-              first += c;
-            }
-          }
-        }
-      }
-      if (Table == null) {
-        SetAddress(ref first, ref second, ref hasSheet);
-      }
-      return true;
-    } catch {
-      return false;
-    }
-  }
-
-  private void HandleBrackets(string first, string second, List<string> bracketParts) {
-    if (!string.IsNullOrEmpty(first)) {
-      _table = new();
-      Table.Name = first;
-      foreach (var s in bracketParts) {
-        if (s.IndexOf("[") < 0) {
-          switch (s.ToLower(CultureInfo.InvariantCulture)) {
-            case "#all":
-              _table.IsAll = true;
-              break;
-            case "#headers":
-              _table.IsHeader = true;
-              break;
-            case "#data":
-              _table.IsData = true;
-              break;
-            case "#totals":
-              _table.IsTotals = true;
-              break;
-            case "#this row":
-              _table.IsThisRow = true;
-              break;
-            default:
-              if (string.IsNullOrEmpty(_table.ColumnSpan)) {
-                _table.ColumnSpan = s;
-              } else {
-                _table.ColumnSpan += ":" + s;
-              }
-              break;
-          }
-        }
-      }
-    }
-  }
-
-  internal eAddressCollition Collide(ExcelAddressBase address) {
-    if (address.WorkSheet != WorkSheet && address.WorkSheet != null) {
-      return eAddressCollition.No;
-    }
-
-    if (address._fromRow > _toRow
-        || address._fromCol > _toCol
-        || _fromRow > address._toRow
-        || _fromCol > address._toCol) {
-      return eAddressCollition.No;
-    }
-    if (address._fromRow == _fromRow
-        && address._fromCol == _fromCol
-        && address._toRow == _toRow
-        && address._toCol == _toCol) {
-      return eAddressCollition.Equal;
-    }
-    if (address._fromRow >= _fromRow
-        && address._toRow <= _toRow
-        && address._fromCol >= _fromCol
-        && address._toCol <= _toCol) {
-      return eAddressCollition.Inside;
-    }
-    return eAddressCollition.Partly;
-  }
-
-  internal ExcelAddressBase AddRow(int row, int rows, bool setFixed = false) {
-    if (row > _toRow) {
-      return this;
-    }
-    if (row <= _fromRow) {
-      return new(
-          (setFixed && _fromRowFixed ? _fromRow : _fromRow + rows),
-          _fromCol,
-          (setFixed && _toRowFixed ? _toRow : _toRow + rows),
-          _toCol,
-          _fromRowFixed,
-          _fromColFixed,
-          _toRowFixed,
-          _toColFixed);
-    }
-    return new(
-        _fromRow,
-        _fromCol,
-        (setFixed && _toRowFixed ? _toRow : _toRow + rows),
-        _toCol,
-        _fromRowFixed,
-        _fromColFixed,
-        _toRowFixed,
-        _toColFixed);
-  }
-
-  internal ExcelAddressBase DeleteRow(int row, int rows, bool setFixed = false) {
-    if (row
-        > _toRow) //After
-    {
-      return this;
-    }
-    if (row + rows
-        <= _fromRow) //Before
-    {
-      return new(
-          (setFixed && _fromRowFixed ? _fromRow : _fromRow - rows),
-          _fromCol,
-          (setFixed && _toRowFixed ? _toRow : _toRow - rows),
-          _toCol,
-          _fromRowFixed,
-          _fromColFixed,
-          _toRowFixed,
-          _toColFixed);
-    }
-    if (row <= _fromRow
-        && row + rows
-            > _toRow) //Inside
-    {
-      return null;
-    } //Partly
-    if (row <= _fromRow) {
-      return new(
-          row,
-          _fromCol,
-          (setFixed && _toRowFixed ? _toRow : _toRow - rows),
-          _toCol,
-          _fromRowFixed,
-          _fromColFixed,
-          _toRowFixed,
-          _toColFixed);
-    }
-    return new(
-        _fromRow,
-        _fromCol,
-        (setFixed && _toRowFixed
-                ? _toRow
-                : _toRow - rows < row
-                    ? row - 1
-                    : _toRow - rows),
-        _toCol,
-        _fromRowFixed,
-        _fromColFixed,
-        _toRowFixed,
-        _toColFixed);
-  }
-
-  internal ExcelAddressBase AddColumn(int col, int cols, bool setFixed = false) {
-    if (col > _toCol) {
-      return this;
-    }
-    if (col <= _fromCol) {
-      return new(
-          _fromRow,
-          (setFixed && _fromColFixed ? _fromCol : _fromCol + cols),
-          _toRow,
-          (setFixed && _toColFixed ? _toCol : _toCol + cols),
-          _fromRowFixed,
-          _fromColFixed,
-          _toRowFixed,
-          _toColFixed);
-    }
-    return new(
-        _fromRow,
-        _fromCol,
-        _toRow,
-        (setFixed && _toColFixed ? _toCol : _toCol + cols),
-        _fromRowFixed,
-        _fromColFixed,
-        _toRowFixed,
-        _toColFixed);
-  }
-
-  internal ExcelAddressBase DeleteColumn(int col, int cols, bool setFixed = false) {
-    if (col
-        > _toCol) //After
-    {
-      return this;
-    }
-    if (col + cols
-        <= _fromCol) //Before
-    {
-      return new(
-          _fromRow,
-          (setFixed && _fromColFixed ? _fromCol : _fromCol - cols),
-          _toRow,
-          (setFixed && _toColFixed ? _toCol : _toCol - cols),
-          _fromRowFixed,
-          _fromColFixed,
-          _toRowFixed,
-          _toColFixed);
-    }
-    if (col <= _fromCol
-        && col + cols
-            > _toCol) //Inside
-    {
-      return null;
-    } //Partly
-    if (col <= _fromCol) {
-      return new(
-          _fromRow,
-          col,
-          _toRow,
-          (setFixed && _toColFixed ? _toCol : _toCol - cols),
-          _fromRowFixed,
-          _fromColFixed,
-          _toRowFixed,
-          _toColFixed);
-    }
-    return new(
-        _fromRow,
-        _fromCol,
-        _toRow,
-        (setFixed && _toColFixed
-                ? _toCol
-                : _toCol - cols < col
-                    ? col - 1
-                    : _toCol - cols),
-        _fromRowFixed,
-        _fromColFixed,
-        _toRowFixed,
-        _toColFixed);
-  }
-
-  internal ExcelAddressBase Insert(
-      ExcelAddressBase address,
-      eShiftType shift /*, out ExcelAddressBase topAddress, out ExcelAddressBase leftAddress, out ExcelAddressBase rightAddress, out ExcelAddressBase bottomAddress*/) {
-    //Before or after, no change
-    //if ((_toRow > address._fromRow && _toCol > address.column) ||
-    //    (_fromRow > address._toRow && column > address._toCol))
-    if (_toRow < address._fromRow
-        || _toCol < address._fromCol
-        || (_fromRow > address._toRow && _fromCol > address._toCol)) {
-      //topAddress = null;
-      //leftAddress = null;
-      //rightAddress = null;
-      //bottomAddress = null;
-      return this;
-    }
-
-    int rows = address.Rows;
-    int cols = address.Columns;
-    string retAddress = "";
-    if (shift == eShiftType.Right) {
-      if (address._fromRow > _fromRow) {
-        retAddress = GetAddress(
-            _fromRow,
-            _fromCol,
-            address._fromRow,
-            _toCol,
-            _fromRowFixed,
-            _fromColFixed,
-            _toRowFixed,
-            _toColFixed);
-      }
-      if (address._fromCol > _fromCol) {
-        retAddress = GetAddress(
-            _fromRow < address._fromRow ? _fromRow : address._fromRow,
-            _fromCol,
-            address._fromRow,
-            _toCol,
-            _fromRowFixed,
-            _fromColFixed,
-            _toRowFixed,
-            _toColFixed);
-      }
-    }
-    if (_toRow < address._fromRow) {
-      if (_fromRow < address._fromRow) {}
-    }
-    return null;
-  }
-
-  private void SetAddress(ref string first, ref string second, ref bool hasSheet) {
-    string ws,
-        address;
-    if (hasSheet) {
-      ws = first;
-      address = second;
-      first = "";
-      second = "";
-    } else {
-      address = first;
-      ws = "";
-      first = "";
-    }
-    hasSheet = false;
-    if (string.IsNullOrEmpty(_firstAddress)) {
-      if (string.IsNullOrEmpty(_ws) || !string.IsNullOrEmpty(ws)) {
-        _ws = ws;
-      }
-      _firstAddress = address;
-      GetRowColFromAddress(
-          address,
-          out _fromRow,
-          out _fromCol,
-          out _toRow,
-          out _toCol,
-          out _fromRowFixed,
-          out _fromColFixed,
-          out _toRowFixed,
-          out _toColFixed);
-    } else {
-      if (_addresses == null) {
-        _addresses = new();
-      }
-      _addresses.Add(new(_ws, address));
-    }
-  }
-
-  internal enum AddressType {
-    Invalid,
-    InternalAddress,
-    ExternalAddress,
-    InternalName,
-    ExternalName,
-    Formula,
-  }
-
-  internal static AddressType IsValid(string address) {
-    if (address == "#REF!") {
-      return AddressType.Invalid;
-    }
-    if (double.TryParse(
-        address,
-        NumberStyles.Any,
-        CultureInfo.InvariantCulture,
-        out _)) //A double, no valid address
-    {
-      return AddressType.Invalid;
-    }
-    if (IsFormula(address)) {
-      return AddressType.Formula;
-    }
-    if (SplitAddress(address, out var wb, out _, out var intAddress)) {
-      if (intAddress.Contains(
-          "[")) //Table reference
-      {
-        return string.IsNullOrEmpty(wb) ? AddressType.InternalAddress : AddressType.ExternalAddress;
-      }
-      if (intAddress.Contains(",")) {
-        intAddress = intAddress.Substring(0, intAddress.IndexOf(','));
-      }
-      if (IsAddress(intAddress)) {
-        return string.IsNullOrEmpty(wb) ? AddressType.InternalAddress : AddressType.ExternalAddress;
-      }
-      return string.IsNullOrEmpty(wb) ? AddressType.InternalName : AddressType.ExternalName;
-    }
-    return AddressType.Invalid;
-  }
-
-  private static bool IsAddress(string intAddress) {
-    if (string.IsNullOrEmpty(intAddress)) {
-      return false;
-    }
-    var cells = intAddress.Split(':');
-    int toRow,
-        toCol;
-
-    if (!GetRowCol(cells[0], out var fromRow, out var fromCol, false)) {
-      return false;
-    }
-    if (cells.Length > 1) {
-      if (!GetRowCol(cells[1], out toRow, out toCol, false)) {
-        return false;
-      }
-    } else {
-      toRow = fromRow;
-      toCol = fromCol;
-    }
-    if (fromRow <= toRow
-        && fromCol <= toCol
-        && fromCol > -1
-        && toCol <= ExcelPackage.MaxColumns
-        && fromRow > -1
-        && toRow <= ExcelPackage.MaxRows) {
-      return true;
-    }
-    return false;
-  }
-
-  private static bool SplitAddress(
-      string address,
-      out string wb,
-      out string ws,
-      out string intAddress) {
-    wb = "";
-    ws = "";
-    intAddress = "";
-    var text = "";
-    bool isText = false;
-    var brackPos = -1;
-    for (int i = 0; i < address.Length; i++) {
-      if (address[i] == '\'') {
-        isText = !isText;
-        if (i > 0 && address[i - 1] == '\'') {
-          text += "'";
-        }
-      } else {
-        if (address[i] == '!' && !isText) {
-          if (text.Length > 0 && text[0] == '[') {
-            wb = text.Substring(1, text.IndexOf("]") - 1);
-            ws = text.Substring(text.IndexOf("]") + 1);
-          } else {
-            ws = text;
-          }
-          intAddress = address.Substring(i + 1);
-          return true;
-        }
-        if (address[i] == '[' && !isText) {
-          if (i
-              > 0) //Table reference return full address;
-          {
-            intAddress = address;
-            return true;
-          }
-          brackPos = i;
-        } else if (address[i] == ']' && !isText) {
-          if (brackPos > -1) {
-            wb = text;
-            text = "";
-          } else {
-            return false;
-          }
-        } else {
-          text += address[i];
-        }
-      }
-    }
-    intAddress = text;
-    return true;
-  }
-
-  private static bool IsFormula(string address) {
-    var isText = false;
-    for (int i = 0; i < address.Length; i++) {
-      if (address[i] == '\'') {
-        isText = !isText;
-      } else {
-        if (isText == false
-            && address
-                .Substring(i, 1)
-                .IndexOfAny(new[] { '(', ')', '+', '-', '*', '/', '.', '=', '^', '&', '%', '\"' })
-                > -1) {
-          return true;
-        }
-      }
-    }
-    return false;
-  }
-
-  public int Rows => _toRow - _fromRow + 1;
-
-  public int Columns => _toCol - _fromCol + 1;
-
-  internal static String GetWorkbookPart(string address) {
-    int ix;
-    if (address[0] == '[') {
-      ix = address.IndexOf(']') + 1;
-      if (ix > 0) {
-        return address.Substring(1, ix - 2);
-      }
-    }
-    return "";
-  }
-
-  internal static string GetWorksheetPart(string address, string defaultWorkSheet, ref int endIx) {
-    if (address == "") {
-      return defaultWorkSheet;
-    }
-    var ix = 0;
-    if (address[0] == '[') {
-      ix = address.IndexOf(']') + 1;
-    }
-    if (ix > 0 && ix < address.Length) {
-      if (address[ix] == '\'') {
-        return GetString(address, ix, out endIx);
-      }
-      var ixEnd = address.IndexOf('!', ix);
-      if (ixEnd > ix) {
-        return address.Substring(ix, ixEnd - ix);
-      }
-      return defaultWorkSheet;
-    }
-    return defaultWorkSheet;
-  }
-
-  internal static void SplitAddress(
-      string fullAddress,
-      out string wb,
-      out string ws,
-      out string address,
-      string defaultWorksheet = "") {
-    wb = GetWorkbookPart(fullAddress);
-    int ix = 0;
-    ws = GetWorksheetPart(fullAddress, defaultWorksheet, ref ix);
-    if (ix < fullAddress.Length) {
-      if (fullAddress[ix] == '!') {
-        address = fullAddress.Substring(ix + 1);
-      } else {
-        address = fullAddress.Substring(ix);
-      }
-    } else {
-      address = "";
-    }
-  }
-
-  private static string GetString(string address, int ix, out int endIx) {
-    var strIx = address.IndexOf("''");
-    while (strIx > -1) {
-      strIx = address.IndexOf("''");
-    }
-    endIx = address.IndexOf("'");
-    return address.Substring(ix, endIx - ix).Replace("''", "'");
-  }
-
-  internal bool IsValidRowCol() {
-    return !(_fromRow > _toRow
-            || _fromCol > _toCol
-            || _fromRow < 1
-            || _fromCol < 1
-            || _toRow > ExcelPackage.MaxRows
-            || _toCol > ExcelPackage.MaxColumns);
-  }
-}
-
-/// <summary>
-/// Range address with the address property readonly
-/// </summary>
-public class ExcelAddress : ExcelAddressBase {
-  internal ExcelAddress() {}
-
-  public ExcelAddress(int fromRow, int fromCol, int toRow, int toColumn)
-      : base(fromRow, fromCol, toRow, toColumn) {
-    _ws = "";
-  }
-
-  public ExcelAddress(string address)
-      : base(address) {}
-
-  internal ExcelAddress(string ws, string address)
-      : base(address) {
-    if (string.IsNullOrEmpty(_ws)) {
-      _ws = ws;
-    }
-  }
-
-  internal ExcelAddress(string ws, string address, bool isName)
-      : base(address, isName) {
-    if (string.IsNullOrEmpty(_ws)) {
-      _ws = ws;
-    }
-  }
-
-  public ExcelAddress(string address, ExcelWorkbook workbook, ExcelAddressBase referenceAddress)
-      : base(address, workbook, referenceAddress) {}
-
-  /// <summary>
-  /// The address for the range
-  /// </summary>
-  /// <remarks>Examples of addresses are "A1" "B1:C2" "A:A" "1:1" "A1:E2,G3:G5" </remarks>
-  public new string Address {
-    get {
-      if (string.IsNullOrEmpty(_address) && _fromRow > 0) {
-        _address = GetAddress(_fromRow, _fromCol, _toRow, _toCol);
-      }
-      return _address;
-    }
-    set {
-      SetAddress(value);
-      ChangeAddress();
-    }
-  }
-}
-
-public class ExcelFormulaAddress : ExcelAddressBase {
-  private bool _fromRowFixed,
-      _toRowFixed,
-      _fromColFixed,
-      _toColFixed;
-
-  public ExcelFormulaAddress(int fromRow, int fromCol, int toRow, int toColumn)
-      : base(fromRow, fromCol, toRow, toColumn) {
-    _ws = "";
-  }
-
-  public ExcelFormulaAddress(string address)
-      : base(address) {
-    SetFixed();
-  }
-
-  private void SetFixed() {
-    if (Address.IndexOf("[") >= 0) {
-      return;
-    }
-    var address = FirstAddress;
-    if (_fromRow == _toRow && _fromCol == _toCol) {
-      GetFixed(address, out _fromRowFixed, out _fromColFixed);
-    } else {
-      var cells = address.Split(':');
-      GetFixed(cells[0], out _fromRowFixed, out _fromColFixed);
-      GetFixed(cells[1], out _toRowFixed, out _toColFixed);
-    }
-  }
-
-  private void GetFixed(string address, out bool rowFixed, out bool colFixed) {
-    rowFixed = colFixed = false;
-    var ix = address.IndexOf('$');
-    while (ix > -1) {
-      ix++;
-      if (ix < address.Length) {
-        if (address[ix] >= '0' && address[ix] <= '9') {
-          rowFixed = true;
-          break;
-        }
-        colFixed = true;
-      }
-      ix = address.IndexOf('$', ix);
-    }
-  }
-
-  /// <summary>
-  /// The address for the range
-  /// </summary>
-  /// <remarks>Examples of addresses are "A1" "B1:C2" "A:A" "1:1" "A1:E2,G3:G5" </remarks>
-  public new string Address {
-    get {
-      if (string.IsNullOrEmpty(_address) && _fromRow > 0) {
-        _address = GetAddress(
-            _fromRow,
-            _fromCol,
-            _toRow,
-            _toCol,
-            _fromRowFixed,
-            _toRowFixed,
-            _fromColFixed,
-            _toColFixed);
-      }
-      return _address;
-    }
-    set {
-      SetAddress(value);
-      ChangeAddress();
-      SetFixed();
-    }
-  }
-
-  internal new List<ExcelFormulaAddress> _addresses;
-
-  public new List<ExcelFormulaAddress> Addresses {
-    get {
-      if (_addresses == null) {
-        _addresses = new();
-      }
-      return _addresses;
-    }
-  }
-
-  internal string GetOffset(int row, int column) {
-    int fromRow = _fromRow,
-        fromCol = _fromCol,
-        toRow = _toRow,
-        tocol = _toCol;
-    var isMulti = (fromRow != toRow || fromCol != tocol);
-    if (!_fromRowFixed) {
-      fromRow += row;
-    }
-    if (!_fromColFixed) {
-      fromCol += column;
-    }
-    if (isMulti) {
-      if (!_toRowFixed) {
-        toRow += row;
-      }
-      if (!_toColFixed) {
-        tocol += column;
-      }
-    } else {
-      toRow = fromRow;
-      tocol = fromCol;
-    }
-    string a = GetAddress(
-        fromRow,
-        fromCol,
-        toRow,
-        tocol,
-        _fromRowFixed,
-        _fromColFixed,
-        _toRowFixed,
-        _toColFixed);
-    if (Addresses != null) {
-      foreach (var sa in Addresses) {
-        a += "," + sa.GetOffset(row, column);
-      }
-    }
-    return a;
-  }
-}
diff --git a/EPPlus/ExcelCellAddress.cs b/EPPlus/ExcelCellAddress.cs
deleted file mode 100644
index b765a73..0000000
--- a/EPPlus/ExcelCellAddress.cs
+++ /dev/null
@@ -1,133 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- *  Starnuto Di Topo & Jan Källman  Initial Release		        2010-03-14
- * Jan Källman		License changed GPL-->LGPL 2011-12-27
- *******************************************************************************/
-
-using System;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// A single cell address
-/// </summary>
-public class ExcelCellAddress {
-  public ExcelCellAddress()
-      : this(1, 1) {}
-
-  private int _row;
-  private int _column;
-  private string _address;
-
-  /// <summary>
-  /// Initializes a new instance of the ExcelCellAddress class.
-  /// </summary>
-  /// <param name="row">The row.</param>
-  /// <param name="column">The column.</param>
-  public ExcelCellAddress(int row, int column) {
-    Row = row;
-    Column = column;
-  }
-
-  /// <summary>
-  /// Initializes a new instance of the ExcelCellAddress class.
-  /// </summary>
-  ///<param name="address">The address</param>
-  public ExcelCellAddress(string address) {
-    Address = address;
-  }
-
-  /// <summary>
-  /// Row
-  /// </summary>
-  public int Row {
-    get => _row;
-    private set {
-      if (value <= 0) {
-        throw new ArgumentOutOfRangeException("value", "Row cannot be less than 1.");
-      }
-      _row = value;
-      if (_column > 0) {
-        _address = ExcelCellBase.GetAddress(_row, _column);
-      } else {
-        _address = "#REF!";
-      }
-    }
-  }
-
-  /// <summary>
-  /// Column
-  /// </summary>
-  public int Column {
-    get => _column;
-    private set {
-      if (value <= 0) {
-        throw new ArgumentOutOfRangeException("value", "Column cannot be less than 1.");
-      }
-      _column = value;
-      if (_row > 0) {
-        _address = ExcelCellBase.GetAddress(_row, _column);
-      } else {
-        _address = "#REF!";
-      }
-    }
-  }
-
-  /// <summary>
-  /// Celladdress
-  /// </summary>
-  public string Address {
-    get => _address;
-    internal set {
-      _address = value;
-      ExcelCellBase.GetRowColFromAddress(_address, out _row, out _column);
-    }
-  }
-
-  /// <summary>
-  /// If the address is an invalid reference (#REF!)
-  /// </summary>
-  public bool IsRef => _row <= 0;
-
-  /// <summary>
-  /// Returns the letter corresponding to the supplied 1-based column index.
-  /// </summary>
-  /// <param name="column">Index of the column (1-based)</param>
-  /// <returns>The corresponding letter, like A for 1.</returns>
-  public static string GetColumnLetter(int column) {
-    if (column > ExcelPackage.MaxColumns || column < 1) {
-      throw new InvalidOperationException(
-          "Invalid 1-based column index: "
-              + column
-              + ". Valid range is 1 to "
-              + ExcelPackage.MaxColumns);
-    }
-    return ExcelCellBase.GetColumnLetter(column);
-  }
-}
diff --git a/EPPlus/ExcelCellBase.cs b/EPPlus/ExcelCellBase.cs
deleted file mode 100644
index 5a0b25e..0000000
--- a/EPPlus/ExcelCellBase.cs
+++ /dev/null
@@ -1,1255 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Jan Källman		Initial Release		        2009-10-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-27
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using OfficeOpenXml.FormulaParsing;
-using OfficeOpenXml.FormulaParsing.Excel.Functions;
-using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// Base class containing cell address manipulating methods.
-/// </summary>
-public abstract class ExcelCellBase {
-  /// <summary>
-  /// Get the sheet, row and column from the CellID
-  /// </summary>
-  /// <param name="cellId"></param>
-  /// <param name="sheet"></param>
-  /// <param name="row"></param>
-  /// <param name="col"></param>
-  static internal void SplitCellId(ulong cellId, out int sheet, out int row, out int col) {
-    sheet = (int)(cellId % 0x8000);
-    col = ((int)(cellId >> 15) & 0x3FF);
-    row = ((int)(cellId >> 29));
-  }
-
-  /// <summary>
-  /// Get the cellID for the cell.
-  /// </summary>
-  /// <param name="sheetId"></param>
-  /// <param name="row"></param>
-  /// <param name="col"></param>
-  /// <returns></returns>
-  internal static ulong GetCellId(int sheetId, int row, int col) {
-    return ((ulong)sheetId) + (((ulong)col) << 15) + (((ulong)row) << 29);
-  }
-
-  private delegate string AddressTranslator(
-    string part,
-    int row,
-    int col,
-    int rowIncr,
-    int colIncr);
-
-  /// <summary>
-  /// Translates a R1C1 to an absolut address/Formula
-  /// </summary>
-  /// <param name="value">Address</param>
-  /// <param name="row">Current row</param>
-  /// <param name="col">Current column</param>
-  /// <returns>The RC address</returns>
-  public static string TranslateFromR1C1(string value, int row, int col) {
-    return Translate(value, ToAbs, row, col, -1, -1);
-  }
-
-  /// <summary>
-  /// Translates a R1C1 to an absolut address/Formula: Version 1
-  /// </summary>
-  /// <param name="value">Address</param>
-  /// <param name="row">Current row</param>
-  /// <param name="col">Current column</param>
-  /// <returns>The RC address</returns>
-  public static string TranslateFromR1C1_V1(string value, int row, int col) {
-    return Translate_V1(value, ToAbs_V1, row, col, -1, -1);
-  }
-
-  /// <summary>
-  /// Translates a absolut address to R1C1 Format
-  /// </summary>
-  /// <param name="value">R1C1 Address</param>
-  /// <param name="row">Current row</param>
-  /// <param name="col">Current column</param>
-  /// <returns>The absolut address/Formula</returns>
-  public static string TranslateToR1C1(string value, int row, int col) {
-    return Translate(value, ToR1C1, row, col, -1, -1);
-  }
-
-  /// <summary>
-  /// Translates a absolute address to R1C1 Format : Version 1
-  /// </summary>
-  /// <param name="value">R1C1 Address</param>
-  /// <param name="row">Current row</param>
-  /// <param name="col">Current column</param>
-  /// <returns>The absolut address/Formula</returns>
-  public static string TranslateToR1C1_V1(string value, int row, int col) {
-    return Translate_V1(value, ToR1C1_V1, row, col, -1, -1);
-  }
-
-  /// <summary>
-  /// Translates betweein R1C1 or absolute addresses : Version 1
-  /// </summary>
-  /// <param name="value">The addresss/function</param>
-  /// <param name="addressTranslator">The translating function</param>
-  /// <param name="row"></param>
-  /// <param name="col"></param>
-  /// <param name="rowIncr"></param>
-  /// <param name="colIncr"></param>
-  /// <returns></returns>
-  private static string Translate(
-      string value,
-      AddressTranslator addressTranslator,
-      int row,
-      int col,
-      int rowIncr,
-      int colIncr) {
-    if (value == "") {
-      return "";
-    }
-    bool isText = false;
-    string ret = "";
-    string part = "";
-    char prevTq = (char)0;
-    for (int pos = 0; pos < value.Length; pos++) {
-      char c = value[pos];
-      if (c == '"' || c == '\'') {
-        if (isText && prevTq != c) {
-          ret += c;
-          continue;
-        }
-
-        if (isText == false && part != "" && prevTq == c) {
-          ret += addressTranslator(part, row, col, rowIncr, colIncr);
-          part = "";
-        }
-        prevTq = c;
-        isText = !isText;
-        ret += c;
-      } else if (isText) {
-        ret += c;
-      } else {
-        if ((c == '-'
-                    || c == '+'
-                    || c == '*'
-                    || c == '/'
-                    || c == '='
-                    || c == '^'
-                    || c == ','
-                    || c == ':'
-                    || c == '<'
-                    || c == '>'
-                    || c == '('
-                    || c == ')'
-                    || c == '!'
-                    || c == ' '
-                    || c == '&'
-                    || c == '%')
-            && (pos == 0
-                    || value[pos - 1]
-                        != '[')) //Last part to allow for R1C1 style [-x]
-        {
-          ret += addressTranslator(part, row, col, rowIncr, colIncr) + c;
-          part = "";
-        } else {
-          part += c;
-        }
-      }
-    }
-    if (part != "") {
-      ret += addressTranslator(part, row, col, rowIncr, colIncr);
-    }
-    return ret;
-  }
-
-  private static string Translate_V1(
-      string value,
-      AddressTranslator addressTranslator,
-      int row,
-      int col,
-      int rowIncr,
-      int colIncr) {
-    if (value == "") {
-      return "";
-    }
-    bool isText = false;
-    string ret = "";
-    string part = "";
-    char prevTq = (char)0;
-    value = value.Replace("\n", ""); // Eliminate new line characters in the formula
-    for (int pos = 0; pos < value.Length; pos++) {
-      char c = value[pos];
-      if (c == '"' || c == '\'') {
-        if (isText && prevTq != c) {
-          ret += c;
-          continue;
-        }
-
-        if (isText == false && part != "" && prevTq == c) {
-          ret += addressTranslator(part, row, col, rowIncr, colIncr);
-          part = "";
-        }
-        prevTq = c;
-        isText = !isText;
-        ret += c;
-      } else if (isText) {
-        ret += c;
-      } else if (c
-          == ':') // Keep Range expressions together
-      {
-        part += c;
-      } else {
-        if ((c == '-'
-                    || c == '+'
-                    || c == '*'
-                    || c == '/'
-                    || c == '='
-                    || c == '^'
-                    || c == ','
-                    || c == '<'
-                    || c == '>'
-                    || c == '('
-                    || c == ')'
-                    || c == '!'
-                    || c == ' '
-                    || c == '&'
-                    || c == '%')
-            && (pos == 0
-                    || value[pos - 1]
-                        != '[')) //Last part to allow for R1C1 style [-x]
-        {
-          ret += addressTranslator(part, row, col, rowIncr, colIncr) + c;
-          part = "";
-        } else {
-          part += c;
-        }
-      }
-    }
-    if (part != "") {
-      ret += addressTranslator(part, row, col, rowIncr, colIncr);
-    }
-    return ret;
-  }
-
-  /// <summary>
-  /// Translate to R1C1
-  /// </summary>
-  /// <param name="part">the value to be translated</param>
-  /// <param name="row"></param>
-  /// <param name="col"></param>
-  /// <param name="rowIncr"></param>
-  /// <param name="colIncr"></param>
-  /// <returns></returns>
-  private static string ToR1C1(string part, int row, int col, int rowIncr, int colIncr) {
-    string ret = "R";
-    if (GetRowCol(part, out var addrRow, out var addrCol, false)) {
-      if (addrRow == 0 || addrCol == 0) {
-        return part;
-      }
-      if (part.IndexOf('$', 1) > 0) {
-        ret += addrRow.ToString();
-      } else if (addrRow - row != 0) {
-        ret += string.Format("[{0}]", addrRow - row);
-      }
-
-      if (part.StartsWith("$")) {
-        return ret + "C" + addrCol;
-      }
-      if (addrCol - col != 0) {
-        return ret + "C" + string.Format("[{0}]", addrCol - col);
-      }
-      return ret + "C";
-    }
-    return part;
-  }
-
-  private static string ToR1C1_V1(string part, int row, int col, int rowIncr, int colIncr) {
-    // Handle range expressions
-    if ((part.Length > 1) && (part.IndexOf(':', 1) > 0)) {
-      return RangeToR1C1_V1(part, row, col, rowIncr, colIncr);
-    }
-
-    string ret = "R";
-    if (GetRowCol(part, out var addrRow, out var addrCol, false)) {
-      if (addrRow == 0 || addrCol == 0) {
-        return part;
-      }
-      if (part.IndexOf('$', 1) > 0) {
-        ret += addrRow.ToString();
-      } else if (addrRow - row != 0) {
-        ret += string.Format("[{0}]", addrRow - row);
-      }
-
-      if (part.StartsWith("$")) {
-        return ret + "C" + addrCol;
-      }
-      if (addrCol - col != 0) {
-        return ret + "C" + string.Format("[{0}]", addrCol - col);
-      }
-      return ret + "C";
-    }
-    return part;
-  }
-
-  private static string RangeToR1C1_V1(string part, int row, int col, int rowIncr, int colIncr) {
-    // Split range expression
-    string[] cellValues = part.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
-
-    // Convert range expressions
-    string result = "";
-    result += RangeCellToR1C1_V1(cellValues[0], row, col, rowIncr, colIncr);
-    result += ":";
-    result +=
-        (cellValues.Length > 1)
-            ? RangeCellToR1C1_V1(cellValues[1], row, col, rowIncr, colIncr)
-            : "";
-
-    // Return converted range expression
-    return result;
-  }
-
-  private static string RangeCellToR1C1_V1(
-      string part,
-      int row,
-      int col,
-      int rowIncr,
-      int colIncr) {
-    string result = "";
-    if (GetRowCol_V1(
-        part,
-        out var addrRow,
-        out var addrCol,
-        false,
-        out var fixedRow,
-        out var fixedCol)) {
-      if (addrRow > 0) {
-        result += "R";
-        if (fixedRow) {
-          // Absolute row
-          result += addrRow.ToString();
-        } else if (addrRow - row != 0) {
-          // Relative row
-          result += string.Format("[{0}]", addrRow - row);
-        }
-      }
-
-      if (addrCol > 0) {
-        result += "C";
-        if (fixedCol) {
-          // Absolute column
-          result += addrCol;
-        } else if (addrCol - col != 0) {
-          // Relative column
-          result += string.Format("[{0}]", addrCol - col);
-        }
-      }
-      return result;
-    }
-    return part;
-  }
-
-  /// <summary>
-  /// Translates to absolute address
-  /// </summary>
-  /// <param name="part"></param>
-  /// <param name="row"></param>
-  /// <param name="col"></param>
-  /// <param name="rowIncr"></param>
-  /// <param name="colIncr"></param>
-  /// <returns></returns>
-  ///
-  private static string ToAbs(string part, int row, int col, int rowIncr, int colIncr) {
-    string check = part.ToUpper(CultureInfo.InvariantCulture);
-
-    int rStart = check.IndexOf("R");
-    if (rStart != 0) {
-      return part;
-    }
-    if (part.Length
-        == 1) //R
-    {
-      return GetAddress(row, col);
-    }
-
-    int cStart = check.IndexOf("C");
-    bool absoluteRow;
-    if (cStart == -1) {
-      int rNum = GetRc(part, row, out absoluteRow);
-      if (rNum > int.MinValue) {
-        return GetAddress(rNum, absoluteRow, col, false);
-      }
-      return part;
-    } else {
-      int rNum = GetRc(part.Substring(1, cStart - 1), row, out absoluteRow);
-      int cNum = GetRc(
-          part.Substring(cStart + 1, part.Length - cStart - 1),
-          col,
-          out var absoluteCol);
-      if (rNum > int.MinValue && cNum > int.MinValue) {
-        return GetAddress(rNum, absoluteRow, cNum, absoluteCol);
-      }
-      return part;
-    }
-  }
-
-  private static string ToAbs_V1(string part, int row, int col, int rowIncr, int colIncr) {
-    bool absoluteCol = false;
-    bool absoluteRow = false;
-    int colNum = -1;
-    int rowNum = -1;
-    int num;
-    int numLength;
-    int pos = 0;
-
-    // Handle range expressions
-    if ((part.Length > 1) && (part.IndexOf(':', 1) > 0)) {
-      return RangeToA1_V1(part, row, col, rowIncr, colIncr);
-    }
-
-    // Ensure part is present
-    if (string.IsNullOrWhiteSpace(part)) {
-      return "";
-    }
-
-    // Convert to upper case
-    string check = part.ToUpper(CultureInfo.InvariantCulture);
-
-    // Parse "R", if any
-    if (pos < part.Length && check[pos] == 'R') {
-      pos += 1;
-
-      if (pos >= part.Length) {
-        // Only "R" present
-        absoluteRow = false;
-        rowNum = row;
-      } else if (pos < part.Length && check[pos] == 'C') {
-        // "R" followed by "C"
-        absoluteRow = false;
-        rowNum = row;
-      } else if (pos < part.Length && check[pos] == '[') {
-        // "R" followed by relative row number
-        pos += 1;
-        num = GetNumber_V1(check.Substring(pos, part.Length - pos), out numLength);
-        if (num == Int32.MinValue) {
-          return part;
-        }
-        pos += numLength;
-
-        if (pos < part.Length && check[pos] == ']') {
-          pos += 1;
-        } else {
-          return part;
-        }
-
-        absoluteRow = false;
-        rowNum = row + num;
-      } else if (pos < part.Length) {
-        // "R" followed by absolute row number
-        num = GetNumber_V1(check.Substring(pos, part.Length - pos), out numLength);
-        if (rowNum == Int32.MinValue) {
-          return part;
-        }
-        pos += numLength;
-
-        absoluteRow = true;
-        rowNum = num;
-      }
-    }
-
-    // Parse "C", if any
-    if (pos < part.Length && check[pos] == 'C') {
-      pos += 1;
-
-      if (pos >= part.Length) {
-        // Only "C" present
-        absoluteCol = false;
-        colNum = col;
-      } else if (pos < part.Length && check[pos] == '[') {
-        // "C" followed by relative column number
-        pos += 1;
-        num = GetNumber_V1(check.Substring(pos, part.Length - pos), out numLength);
-        if (num == Int32.MinValue) {
-          return part;
-        }
-        pos += numLength;
-
-        if (pos < part.Length && check[pos] == ']') {
-          pos += 1;
-        } else {
-          return part;
-        }
-
-        absoluteCol = false;
-        colNum = col + num;
-      } else if (pos < part.Length) {
-        // "C" followed by absolute column number
-        num = GetNumber_V1(check.Substring(pos, part.Length - pos), out numLength);
-        if (num == Int32.MinValue) {
-          return part;
-        }
-        pos += numLength;
-
-        absoluteCol = true;
-        colNum = num;
-      }
-    }
-
-    // Ensure nothing remains unparsed
-    if (pos < part.Length) {
-      return part;
-    }
-
-    // Exit if neither row nor column is present
-    if ((rowNum == Int32.MinValue) && (colNum == Int32.MinValue)) {
-      return part;
-    }
-
-    // Append column
-    string result = "";
-    if (colNum >= 0) {
-      if (absoluteCol) {
-        result += "$";
-      }
-      result += GetColumnLetter(colNum);
-    }
-
-    // Append row
-    if (rowNum >= 0) {
-      if (absoluteRow) {
-        result += "$";
-      }
-      result += rowNum.ToString();
-    }
-
-    // Return result
-    return result;
-  }
-
-  private static int GetNumber_V1(string value, out int length) {
-    // Get number length
-    length = 0;
-
-    // Ensure value is present
-    if (string.IsNullOrWhiteSpace(value)) {
-      return Int32.MinValue;
-    }
-
-    // Check for sign
-    if ((length < value.Length) && ((value[length] == '-') || (value[length] == '+'))) {
-      length += 1;
-    }
-
-    // Get number length
-    while (length < value.Length && value[length] >= '0' && value[length] <= '9') {
-      length += 1;
-    }
-
-    // No number found
-    if (length == 0) {
-      return Int32.MinValue;
-    }
-
-    // Return number value
-    return (int.TryParse(value.Substring(0, length), out var result)) ? result : Int32.MinValue;
-  }
-
-  private static string RangeToA1_V1(string part, int row, int col, int rowIncr, int colIncr) {
-    // Split range expression
-    string[] cellValues = part.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
-
-    // Convert range expressions
-    string result = "";
-    result += ToAbs_V1(cellValues[0], row, col, rowIncr, colIncr);
-    result += ":";
-    result += ToAbs_V1(cellValues[1], row, col, rowIncr, colIncr);
-
-    // Return converted range expression
-    return result;
-  }
-
-  /// <summary>
-  /// Get the offset value for RC format
-  /// </summary>
-  /// <param name="value"></param>
-  /// <param name="offsetValue"></param>
-  /// <param name="fixedAddr"></param>
-  /// <returns></returns>
-  ///
-  private static int GetRc(string value, int offsetValue, out bool fixedAddr) {
-    if (value == "") {
-      fixedAddr = false;
-      return offsetValue;
-    }
-    int num;
-    if (value[0] == '['
-        && value[value.Length - 1]
-            == ']') //Offset?
-    {
-      fixedAddr = false;
-      if (int.TryParse(value.Substring(1, value.Length - 2), out num)) {
-        return (offsetValue + num);
-      }
-      return int.MinValue;
-    }
-    // Absolute address
-    fixedAddr = true;
-    if (int.TryParse(value, out num)) {
-      return num;
-    }
-    return int.MinValue;
-  }
-
-  /// <summary>
-  /// Returns the character representation of the numbered column
-  /// </summary>
-  /// <param name="iColumnNumber">The number of the column</param>
-  /// <returns>The letter representing the column</returns>
-  protected internal static string GetColumnLetter(int iColumnNumber) {
-    return GetColumnLetter(iColumnNumber, false);
-  }
-
-  protected internal static string GetColumnLetter(int iColumnNumber, bool fixedCol) {
-    if (iColumnNumber < 1) {
-      //throw new Exception("Column number is out of range");
-      return "#REF!";
-    }
-
-    string sCol = "";
-    do {
-      sCol = ((char)('A' + ((iColumnNumber - 1) % 26))) + sCol;
-      iColumnNumber = (iColumnNumber - ((iColumnNumber - 1) % 26)) / 26;
-    } while (iColumnNumber > 0);
-    return fixedCol ? "$" + sCol : sCol;
-  }
-
-  internal static bool GetRowColFromAddress(
-      string cellAddress,
-      out int fromRow,
-      out int fromColumn,
-      out int toRow,
-      out int toColumn) {
-    bool fixedFromRow,
-        fixedFromColumn,
-        fixedToRow,
-        fixedToColumn;
-    return GetRowColFromAddress(
-        cellAddress,
-        out fromRow,
-        out fromColumn,
-        out toRow,
-        out toColumn,
-        out fixedFromRow,
-        out fixedFromColumn,
-        out fixedToRow,
-        out fixedToColumn);
-  }
-
-  /// <summary>
-  /// Get the row/columns for a Cell-address
-  /// </summary>
-  /// <param name="cellAddress">The address</param>
-  /// <param name="fromRow">Returns the to column</param>
-  /// <param name="fromColumn">Returns the from column</param>
-  /// <param name="toRow">Returns the to row</param>
-  /// <param name="toColumn">Returns the from row</param>
-  /// <param name="fixedFromRow">Is the from row fixed?</param>
-  /// <param name="fixedFromColumn">Is the from column fixed?</param>
-  /// <param name="fixedToRow">Is the to row fixed?</param>
-  /// <param name="fixedToColumn">Is the to column fixed?</param>
-  /// <returns></returns>
-  internal static bool GetRowColFromAddress(
-      string cellAddress,
-      out int fromRow,
-      out int fromColumn,
-      out int toRow,
-      out int toColumn,
-      out bool fixedFromRow,
-      out bool fixedFromColumn,
-      out bool fixedToRow,
-      out bool fixedToColumn) {
-    bool ret;
-    if (cellAddress.IndexOf('[')
-        > 0) //External reference or reference to Table or Pivottable.
-    {
-      fromRow = -1;
-      fromColumn = -1;
-      toRow = -1;
-      toColumn = -1;
-      fixedFromRow = false;
-      fixedFromColumn = false;
-      fixedToRow = false;
-      fixedToColumn = false;
-      return false;
-    }
-
-    cellAddress = cellAddress.ToUpper(CultureInfo.InvariantCulture);
-    //This one can be removed when the worksheet Select format is fixed
-    if (cellAddress.IndexOf(' ') > 0) {
-      cellAddress = cellAddress.Substring(0, cellAddress.IndexOf(' '));
-    }
-
-    if (cellAddress.IndexOf(':') < 0) {
-      ret = GetRowColFromAddress(
-          cellAddress,
-          out fromRow,
-          out fromColumn,
-          out fixedFromRow,
-          out fixedFromColumn);
-      toColumn = fromColumn;
-      toRow = fromRow;
-      fixedToRow = fixedFromRow;
-      fixedToColumn = fixedFromColumn;
-    } else {
-      string[] cells = cellAddress.Split(':');
-      ret = GetRowColFromAddress(
-          cells[0],
-          out fromRow,
-          out fromColumn,
-          out fixedFromRow,
-          out fixedFromColumn);
-      if (ret) {
-        ret = GetRowColFromAddress(
-            cells[1],
-            out toRow,
-            out toColumn,
-            out fixedToRow,
-            out fixedToColumn);
-      } else {
-        GetRowColFromAddress(cells[1], out toRow, out toColumn, out fixedToRow, out fixedToColumn);
-      }
-
-      if (fromColumn <= 0) {
-        fromColumn = 1;
-      }
-      if (fromRow <= 0) {
-        fromRow = 1;
-      }
-      if (toColumn <= 0) {
-        toColumn = ExcelPackage.MaxColumns;
-      }
-      if (toRow <= 0) {
-        toRow = ExcelPackage.MaxRows;
-      }
-    }
-    return ret;
-  }
-
-  /// <summary>
-  /// Get the row/column for n Cell-address
-  /// </summary>
-  /// <param name="cellAddress">The address</param>
-  /// <param name="row">Returns Tthe row</param>
-  /// <param name="column">Returns the column</param>
-  /// <returns>true if valid</returns>
-  internal static bool GetRowColFromAddress(string cellAddress, out int row, out int column) {
-    return GetRowCol(cellAddress, out row, out column, true);
-  }
-
-  internal static bool GetRowColFromAddress(
-      string cellAddress,
-      out int row,
-      out int col,
-      out bool fixedRow,
-      out bool fixedCol) {
-    return GetRowCol(cellAddress, out row, out col, true, out fixedRow, out fixedCol);
-  }
-
-  /// <summary>
-  /// Get the row/column for a Cell-address
-  /// </summary>
-  /// <param name="address">the address</param>
-  /// <param name="row">returns the row</param>
-  /// <param name="col">returns the column</param>
-  /// <param name="throwException">throw exception if invalid, otherwise returns false</param>
-  /// <returns></returns>
-  internal static bool GetRowCol(string address, out int row, out int col, bool throwException) {
-    bool fixedRow,
-        fixedCol;
-    return GetRowCol(address, out row, out col, throwException, out fixedRow, out fixedCol);
-  }
-
-  internal static bool GetRowCol(
-      string address,
-      out int row,
-      out int col,
-      bool throwException,
-      out bool fixedRow,
-      out bool fixedCol) {
-    bool colPart = true;
-    int colStartIx = 0;
-    int colLength = 0;
-    col = 0;
-    row = 0;
-    fixedRow = false;
-    fixedCol = false;
-
-    if (address.EndsWith("#REF!")) {
-      row = 0;
-      col = 0;
-      return true;
-    }
-
-    int sheetMarkerIndex = address.IndexOf('!');
-    if (sheetMarkerIndex >= 0) {
-      colStartIx = sheetMarkerIndex + 1;
-    }
-    address = address.ToUpper(CultureInfo.InvariantCulture);
-    for (int i = colStartIx; i < address.Length; i++) {
-      char c = address[i];
-      if (colPart && (c >= 'A' && c <= 'Z') && colLength <= 3) {
-        col *= 26;
-        col += c - 64;
-        colLength++;
-      } else if (c >= '0' && c <= '9') {
-        row *= 10;
-        row += c - 48;
-        colPart = false;
-      } else if (c == '$') {
-        if (i == colStartIx) {
-          colStartIx++;
-          fixedCol = true;
-        } else {
-          colPart = false;
-          fixedRow = true;
-        }
-      } else {
-        row = 0;
-        col = 0;
-        if (throwException) {
-          throw (new(string.Format("Invalid Address format {0}", address)));
-        }
-        return false;
-      }
-    }
-    return row != 0 || col != 0;
-  }
-
-  internal static bool GetRowCol_V1(
-      string address,
-      out int row,
-      out int col,
-      bool throwException,
-      out bool fixedRow,
-      out bool fixedCol) {
-    bool colPart = true;
-    bool isFixed = false;
-    int colStartIx = 0;
-    int colLength = 0;
-    col = 0;
-    row = 0;
-    fixedRow = false;
-    fixedCol = false;
-
-    if (address.EndsWith("#REF!")) {
-      row = 0;
-      col = 0;
-      return true;
-    }
-
-    int sheetMarkerIndex = address.IndexOf('!');
-    if (sheetMarkerIndex >= 0) {
-      colStartIx = sheetMarkerIndex + 1;
-    }
-    address = address.ToUpper(CultureInfo.InvariantCulture);
-    for (int i = colStartIx; i < address.Length; i++) {
-      char c = address[i];
-      if (c == '$') {
-        // Absolute address
-        isFixed = true;
-      } else if (colPart && (c >= 'A' && c <= 'Z') && colLength <= 3) {
-        // Column portion of address
-        if (isFixed) {
-          fixedCol = true;
-          isFixed = false;
-        }
-
-        col *= 26;
-        col += c - 64;
-        colLength++;
-      } else if (c >= '0' && c <= '9') {
-        // Row portion of address
-        if (isFixed) {
-          fixedRow = true;
-          isFixed = false;
-        }
-
-        row *= 10;
-        row += c - 48;
-        colPart = false;
-      } else {
-        row = 0;
-        col = 0;
-        if (throwException) {
-          throw (new(string.Format("Invalid Address format {0}", address)));
-        }
-        return false;
-      }
-    }
-    return row != 0 || col != 0;
-  }
-
-  private static int GetColumn(string sCol) {
-    int col = 0;
-    int len = sCol.Length - 1;
-    for (int i = len; i >= 0; i--) {
-      col += (sCol[i] - 64) * (int)(Math.Pow(26, len - i));
-    }
-    return col;
-  }
-
-  /// <summary>
-  /// Returns the AlphaNumeric representation that Excel expects for a Cell Address
-  /// </summary>
-  /// <param name="row">The number of the row</param>
-  /// <param name="column">The number of the column in the worksheet</param>
-  /// <returns>The cell address in the format A1</returns>
-  public static string GetAddress(int row, int column) {
-    return GetAddress(row, column, false);
-  }
-
-  /// <summary>
-  /// Returns the AlphaNumeric representation that Excel expects for a Cell Address
-  /// </summary>
-  /// <param name="row">The number of the row</param>
-  /// <param name="column">The number of the column in the worksheet</param>
-  /// <param name="absoluteRow">Absolute row</param>
-  /// <param name="absoluteCol">Absolute column</param>
-  /// <returns>The cell address in the format A1</returns>
-  public static string GetAddress(int row, bool absoluteRow, int column, bool absoluteCol) {
-    return (absoluteCol ? "$" : "") + GetColumnLetter(column) + (absoluteRow ? "$" : "") + row;
-  }
-
-  /// <summary>
-  /// Returns the AlphaNumeric representation that Excel expects for a Cell Address
-  /// </summary>
-  /// <param name="row">The number of the row</param>
-  /// <param name="column">The number of the column in the worksheet</param>
-  /// <param name="absolute">Get an absolute address ($A$1)</param>
-  /// <returns>The cell address in the format A1</returns>
-  public static string GetAddress(int row, int column, bool absolute) {
-    if (row == 0 || column == 0) {
-      return "#REF!";
-    }
-    if (absolute) {
-      return ("$" + GetColumnLetter(column) + "$" + row);
-    }
-    return (GetColumnLetter(column) + row);
-  }
-
-  /// <summary>
-  /// Returns the AlphaNumeric representation that Excel expects for a Cell Address
-  /// </summary>
-  /// <param name="fromRow">From row number</param>
-  /// <param name="fromColumn">From column number</param>
-  /// <param name="toRow">To row number</param>
-  /// <param name="toColumn">From column number</param>
-  /// <returns>The cell address in the format A1</returns>
-  public static string GetAddress(int fromRow, int fromColumn, int toRow, int toColumn) {
-    return GetAddress(fromRow, fromColumn, toRow, toColumn, false);
-  }
-
-  /// <summary>
-  /// Returns the AlphaNumeric representation that Excel expects for a Cell Address
-  /// </summary>
-  /// <param name="fromRow">From row number</param>
-  /// <param name="fromColumn">From column number</param>
-  /// <param name="toRow">To row number</param>
-  /// <param name="toColumn">From column number</param>
-  /// <param name="absolute">if true address is absolute (like $A$1)</param>
-  /// <returns>The cell address in the format A1</returns>
-  public static string GetAddress(
-      int fromRow,
-      int fromColumn,
-      int toRow,
-      int toColumn,
-      bool absolute) {
-    if (fromRow == toRow && fromColumn == toColumn) {
-      return GetAddress(fromRow, fromColumn, absolute);
-    }
-    if (fromRow == 1 && toRow == ExcelPackage.MaxRows) {
-      var absChar = absolute ? "$" : "";
-      return absChar + GetColumnLetter(fromColumn) + ":" + absChar + GetColumnLetter(toColumn);
-    }
-    if (fromColumn == 1 && toColumn == ExcelPackage.MaxColumns) {
-      var absChar = absolute ? "$" : "";
-      return absChar + fromRow + ":" + absChar + toRow;
-    }
-    return GetAddress(fromRow, fromColumn, absolute) + ":" + GetAddress(toRow, toColumn, absolute);
-  }
-
-  /// <summary>
-  /// Returns the AlphaNumeric representation that Excel expects for a Cell Address
-  /// </summary>
-  /// <param name="fromRow">From row number</param>
-  /// <param name="fromColumn">From column number</param>
-  /// <param name="toRow">To row number</param>
-  /// <param name="toColumn">From column number</param>
-  /// <param name="fixedFromColumn"></param>
-  /// <param name="fixedFromRow"></param>
-  /// <param name="fixedToColumn"></param>
-  /// <param name="fixedToRow"></param>
-  /// <returns>The cell address in the format A1</returns>
-  public static string GetAddress(
-      int fromRow,
-      int fromColumn,
-      int toRow,
-      int toColumn,
-      bool fixedFromRow,
-      bool fixedFromColumn,
-      bool fixedToRow,
-      bool fixedToColumn) {
-    if (fromRow == toRow && fromColumn == toColumn) {
-      return GetAddress(fromRow, fixedFromRow, fromColumn, fixedFromColumn);
-    }
-    if (fromRow == 1 && toRow == ExcelPackage.MaxRows) {
-      return GetColumnLetter(fromColumn, fixedFromColumn)
-          + ":"
-          + GetColumnLetter(toColumn, fixedToColumn);
-    }
-    if (fromColumn == 1 && toColumn == ExcelPackage.MaxColumns) {
-      return (fixedFromRow ? "$" : "") + fromRow + ":" + (fixedToRow ? "$" : "") + toRow;
-    }
-    return GetAddress(fromRow, fixedFromRow, fromColumn, fixedFromColumn)
-        + ":"
-        + GetAddress(toRow, fixedToRow, toColumn, fixedToColumn);
-  }
-
-  /// <summary>
-  /// Get the full address including the worksheet name
-  /// </summary>
-  /// <param name="worksheetName">The name of the worksheet</param>
-  /// <param name="address">The address</param>
-  /// <returns>The full address</returns>
-  public static string GetFullAddress(string worksheetName, string address) {
-    return GetFullAddress(worksheetName, address, true);
-  }
-
-  internal static string GetFullAddress(string worksheetName, string address, bool fullRowCol) {
-    if (address.IndexOf("!") == -1 || address == "#REF!") {
-      if (fullRowCol) {
-        string[] cells = address.Split(':');
-        if (cells.Length > 0) {
-          address = string.Format("'{0}'!{1}", worksheetName, cells[0]);
-          if (cells.Length > 1) {
-            address += string.Format(":{0}", cells[1]);
-          }
-        }
-      } else {
-        var a = new ExcelAddressBase(address);
-        if ((a._fromRow == 1 && a._toRow == ExcelPackage.MaxRows)
-            || (a._fromCol == 1 && a._toCol == ExcelPackage.MaxColumns)) {
-          address = string.Format(
-              "'{0}'!{1}{2}:{3}{4}",
-              worksheetName,
-              GetColumnLetter(a._fromCol),
-              a._fromRow,
-              GetColumnLetter(a._toCol),
-              a._toRow);
-        } else {
-          address = GetFullAddress(worksheetName, address, true);
-        }
-      }
-    }
-    return address;
-  }
-
-  public static bool IsValidAddress(string address) {
-    address = address.ToUpper(CultureInfo.InvariantCulture);
-    string r1 = "",
-        c1 = "",
-        r2 = "",
-        c2 = "";
-    bool isSecond = false;
-    for (int i = 0; i < address.Length; i++) {
-      if (address[i] >= 'A' && address[i] <= 'Z') {
-        if (isSecond == false) {
-          if (r1 != "") {
-            return false;
-          }
-          c1 += address[i];
-          if (c1.Length > 3) {
-            return false;
-          }
-        } else {
-          if (r2 != "") {
-            return false;
-          }
-          c2 += address[i];
-          if (c2.Length > 3) {
-            return false;
-          }
-        }
-      } else if (address[i] >= '0' && address[i] <= '9') {
-        if (isSecond == false) {
-          r1 += address[i];
-          if (r1.Length > 7) {
-            return false;
-          }
-        } else {
-          r2 += address[i];
-          if (r2.Length > 7) {
-            return false;
-          }
-        }
-      } else if (address[i] == ':') {
-        isSecond = true;
-      } else if (address[i] == '$') {
-        if (i == address.Length - 1 || address[i + 1] == ':') {
-          return false;
-        }
-      } else {
-        return false;
-      }
-    }
-
-    if (r1 != ""
-        && c1 != ""
-        && r2 == ""
-        && c2
-            == "") //Single Cell
-    {
-      return (GetColumn(c1) <= ExcelPackage.MaxColumns && int.Parse(r1) <= ExcelPackage.MaxRows);
-    }
-    if (r1 != ""
-        && r2 != ""
-        && c1 != ""
-        && c2
-            != "") //Range
-    {
-      var iR2 = int.Parse(r2);
-      var iC2 = GetColumn(c2);
-
-      return GetColumn(c1) <= iC2
-          && int.Parse(r1) <= iR2
-          && iC2 <= ExcelPackage.MaxColumns
-          && iR2 <= ExcelPackage.MaxRows;
-    }
-    if (r1 == ""
-        && r2 == ""
-        && c1 != ""
-        && c2
-            != "") //Full Column
-    {
-      var c2N = GetColumn(c2);
-      return (GetColumn(c1) <= c2N && c2N <= ExcelPackage.MaxColumns);
-    }
-    if (r1 != "" && r2 != "" && c1 == "" && c2 == "") {
-      var iR2 = int.Parse(r2);
-
-      return int.Parse(r1) <= iR2 && iR2 <= ExcelPackage.MaxRows;
-    }
-    return false;
-  }
-
-  /// <summary>
-  /// Checks that a cell address (e.g. A5) is valid.
-  /// </summary>
-  /// <param name="cellAddress">The alphanumeric cell address</param>
-  /// <returns>True if the cell address is valid</returns>
-  public static bool IsValidCellAddress(string cellAddress) {
-    bool result = false;
-    try {
-      if (GetRowColFromAddress(cellAddress, out var row, out var col)) {
-        if (row > 0 && col > 0 && row <= ExcelPackage.MaxRows && col <= ExcelPackage.MaxColumns) {
-          result = true;
-        } else {
-          result = false;
-        }
-      }
-    } catch {}
-    return result;
-  }
-
-  /// <summary>
-  /// Updates the Excel formula so that all the cellAddresses are incremented by the row and column increments
-  /// if they fall after the afterRow and afterColumn.
-  /// Supports inserting rows and columns into existing templates.
-  /// </summary>
-  /// <param name="formula">The Excel formula</param>
-  /// <param name="rowIncrement">The amount to increment the cell reference by</param>
-  /// <param name="colIncrement">The amount to increment the cell reference by</param>
-  /// <param name="afterRow">Only change rows after this row</param>
-  /// <param name="afterColumn">Only change columns after this column</param>
-  /// <returns></returns>
-  internal static string UpdateFormulaReferences(
-      string formula,
-      int rowIncrement,
-      int colIncrement,
-      int afterRow,
-      int afterColumn,
-      bool setFixed = false) {
-    //return Translate(Formula, AddToRowColumnTranslator, afterRow, afterColumn, rowIncrement, colIncrement);
-    var d = new Dictionary<string, object>();
-    try {
-      var sct = new SourceCodeTokenizer(FunctionNameProvider.Empty, NameValueProvider.Empty);
-      var tokens = sct.Tokenize(formula);
-      String f = "";
-      foreach (var t in tokens) {
-        if (t.TokenType == TokenType.ExcelAddress) {
-          var a = new ExcelAddressBase(t.Value);
-
-          if (!String.IsNullOrEmpty(
-              a._ws)) // Bug 15339
-          {
-            // This is from a different worksheet, thus no update is required
-            f += a.Address;
-            continue;
-          }
-
-          if (rowIncrement > 0) {
-            a = a.AddRow(afterRow, rowIncrement, setFixed);
-          } else if (rowIncrement < 0) {
-            a = a.DeleteRow(afterRow, -rowIncrement, setFixed);
-          }
-          if (colIncrement > 0) {
-            a = a.AddColumn(afterColumn, colIncrement, setFixed);
-          } else if (colIncrement < 0) {
-            a = a.DeleteColumn(afterColumn, -colIncrement, setFixed);
-          }
-          if (a == null || !a.IsValidRowCol()) {
-            f += "#REF!";
-          } else {
-            f += a.Address;
-          }
-        } else {
-          f += t.Value;
-        }
-      }
-      return f;
-    } catch //Invalid formula, skip updateing addresses
-    {
-      return formula;
-    }
-  }
-}
diff --git a/EPPlus/ExcelColumn.cs b/EPPlus/ExcelColumn.cs
deleted file mode 100644
index 889c682..0000000
--- a/EPPlus/ExcelColumn.cs
+++ /dev/null
@@ -1,253 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan K�llman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Jan K�llman		Initial Release		        2009-10-01
- * Jan K�llman		License changed GPL-->LGPL 2011-12-27
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.Style;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// Represents one or more columns within the worksheet
-/// </summary>
-public class ExcelColumn : IRangeId {
-  private readonly ExcelWorksheet _worksheet;
-  private readonly XmlElement _colElement = null;
-
-  /// <summary>
-  /// Creates a new instance of the ExcelColumn class.
-  /// For internal use only!
-  /// </summary>
-  /// <param name="worksheet"></param>
-  /// <param name="col"></param>
-  protected internal ExcelColumn(ExcelWorksheet worksheet, int col) {
-    _worksheet = worksheet;
-    _columnMin = col;
-    _columnMax = col;
-    _width = _worksheet.DefaultColWidth;
-  }
-
-  internal int _columnMin;
-
-  /// <summary>
-  /// Sets the first column the definition refers to.
-  /// </summary>
-  public int ColumnMin => _columnMin;
-
-  //set { _columnMin=value; }
-  internal int _columnMax;
-
-  /// <summary>
-  /// Sets the last column the definition refers to.
-  /// </summary>
-  public int ColumnMax {
-    get => _columnMax;
-    set {
-      if (value < _columnMin && value > ExcelPackage.MaxColumns) {
-        throw new("ColumnMax out of range");
-      }
-
-      var cse = new CellsStoreEnumerator<object>(
-          _worksheet._values,
-          0,
-          0,
-          0,
-          ExcelPackage.MaxColumns);
-      while (cse.Next()) {
-        var c = cse.Value as ExcelColumn;
-        if (cse.Column > _columnMin && c.ColumnMax <= value && cse.Column != _columnMin) {
-          throw new(string.Format("ColumnMax can not span over existing column {0}.", c.ColumnMin));
-        }
-      }
-      _columnMax = value;
-    }
-  }
-
-  /// <summary>
-  /// Internal range id for the column
-  /// </summary>
-  internal ulong ColumnID => GetColumnId(_worksheet.SheetID, ColumnMin);
-
-  /// <summary>
-  /// Allows the column to be hidden in the worksheet
-  /// </summary>
-  internal bool _hidden;
-  public bool Hidden {
-    get => _hidden;
-    set => _hidden = value;
-  }
-
-  internal double VisualWidth {
-    get {
-      if (_hidden || (Collapsed && OutlineLevel > 0)) {
-        return 0;
-      }
-      return _width;
-    }
-  }
-  internal double _width;
-
-  /// <summary>
-  /// Sets the width of the column in the worksheet
-  /// </summary>
-  public double Width {
-    get => _width;
-    set {
-      _width = value;
-
-      if (_hidden && value != 0) {
-        _hidden = false;
-      }
-    }
-  }
-
-  /// <summary>
-  /// If set to true a column automaticlly resize(grow wider) when a user inputs numbers in a cell.
-  /// </summary>
-  public bool BestFit { get; set; }
-
-  /// <summary>
-  /// If the column is collapsed in outline mode
-  /// </summary>
-  public bool Collapsed { get; set; }
-
-  /// <summary>
-  /// Outline level. Zero if no outline
-  /// </summary>
-  public int OutlineLevel { get; set; }
-
-  /// <summary>
-  /// Phonetic
-  /// </summary>
-  public bool Phonetic { get; set; }
-
-  /// <summary>
-  /// The Style applied to the whole column. Only effects cells with no individual style set.
-  /// Use Range object if you want to set specific styles.
-  /// </summary>
-  public ExcelStyle Style {
-    get {
-      string letter = ExcelCellBase.GetColumnLetter(ColumnMin);
-      string endLetter = ExcelCellBase.GetColumnLetter(ColumnMax);
-      return _worksheet.Workbook.Styles.GetStyleObject(
-          StyleID,
-          _worksheet.PositionID,
-          letter + ":" + endLetter);
-    }
-  }
-  internal string _styleName = "";
-
-  /// <summary>
-  /// Sets the style for the entire column using a style name.
-  /// </summary>
-  public string StyleName {
-    get => _styleName;
-    set {
-      StyleID = _worksheet.Workbook.Styles.GetStyleIdFromName(value);
-      _styleName = value;
-    }
-  }
-
-  //internal int _styleID = 0;
-  /// <summary>
-  /// Sets the style for the entire column using the style ID.
-  /// </summary>
-  public int StyleID {
-    get => _worksheet._styles.GetValue(0, ColumnMin);
-    set => _worksheet._styles.SetValue(0, ColumnMin, value);
-  }
-
-  /// <summary>
-  /// Adds a manual page break after the column.
-  /// </summary>
-  public bool PageBreak { get; set; }
-  public bool Merged {
-    get => _worksheet.MergedCells[ColumnMin, 0] != null;
-    set => _worksheet.MergedCells.Add(new(1, ColumnMin, ExcelPackage.MaxRows, ColumnMax), true);
-  }
-
-  /// <summary>
-  /// Returns the range of columns covered by the column definition.
-  /// </summary>
-  /// <returns>A string describing the range of columns covered by the column definition.</returns>
-  public override string ToString() {
-    return string.Format(
-        "Column Range: {0} to {1}",
-        _colElement.GetAttribute("min"),
-        _colElement.GetAttribute("min"));
-  }
-
-  /// <summary>
-  /// Get the internal RangeID
-  /// </summary>
-  /// <param name="sheetId">Sheet no</param>
-  /// <param name="column">Column</param>
-  /// <returns></returns>
-  internal static ulong GetColumnId(int sheetId, int column) {
-    return ((ulong)sheetId) + (((ulong)column) << 15);
-  }
-
-  ulong IRangeId.RangeID {
-    get => ColumnID;
-    set {
-      int prevColMin = _columnMin;
-      _columnMin = ((int)(value >> 15) & 0x3FF);
-      _columnMax += prevColMin - ColumnMin;
-      //Todo:More Validation
-      if (_columnMax > ExcelPackage.MaxColumns) {
-        _columnMax = ExcelPackage.MaxColumns;
-      }
-    }
-  }
-
-  /// <summary>
-  /// Copies the current column to a new worksheet
-  /// </summary>
-  /// <param name="added">The worksheet where the copy will be created</param>
-  internal ExcelColumn Clone(ExcelWorksheet added) {
-    return Clone(added, ColumnMin);
-  }
-
-  internal ExcelColumn Clone(ExcelWorksheet added, int col) {
-    ExcelColumn newCol = added.Column(col);
-    newCol.ColumnMax = ColumnMax;
-    newCol.BestFit = BestFit;
-    newCol.Collapsed = Collapsed;
-    newCol.OutlineLevel = OutlineLevel;
-    newCol.PageBreak = PageBreak;
-    newCol.Phonetic = Phonetic;
-    newCol._styleName = _styleName;
-    newCol.StyleID = StyleID;
-    newCol.Width = Width;
-    newCol.Hidden = Hidden;
-    return newCol;
-  }
-}
diff --git a/EPPlus/ExcelComment.cs b/EPPlus/ExcelComment.cs
deleted file mode 100644
index 74df866..0000000
--- a/EPPlus/ExcelComment.cs
+++ /dev/null
@@ -1,141 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Jan Källman		Initial Release
- * Jan Källman		License changed GPL-->LGPL 2011-12-27
- *******************************************************************************/
-
-using System.Xml;
-using OfficeOpenXml.Drawing.Vml;
-using OfficeOpenXml.Style;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// An Excel Cell Comment
-/// </summary>
-public class ExcelComment : ExcelVmlDrawingComment {
-  private readonly XmlHelper _commentHelper;
-  private readonly string _text;
-
-  internal ExcelComment(XmlNamespaceManager ns, XmlNode commentTopNode, ExcelRangeBase cell)
-      : base(null, cell, cell.Worksheet.VmlDrawingsComments.NameSpaceManager) {
-    //_commentHelper = new XmlHelper(ns, commentTopNode);
-    _commentHelper = XmlHelperFactory.Create(ns, commentTopNode);
-    var textElem = commentTopNode.SelectSingleNode("d:text", ns);
-    if (textElem == null) {
-      textElem = commentTopNode.OwnerDocument.CreateElement("text", ExcelPackage._schemaMain);
-      commentTopNode.AppendChild(textElem);
-    }
-    if (!cell.Worksheet._vmlDrawings.ContainsKey(
-        ExcelCellBase.GetCellId(cell.Worksheet.SheetID, cell.Start.Row, cell.Start.Column))) {
-      cell.Worksheet._vmlDrawings.Add(cell);
-    }
-
-    TopNode = cell.Worksheet.VmlDrawingsComments[ExcelCellBase.GetCellId(
-          cell.Worksheet.SheetID,
-          cell.Start.Row,
-          cell.Start.Column)].TopNode;
-    RichText = new(ns, textElem);
-    var tNode = textElem.SelectSingleNode("d:t", ns);
-    if (tNode != null) {
-      _text = tNode.InnerText;
-    }
-  }
-
-  private const string _authorsPath = "d:comments/d:authors";
-  private const string _authorPath = "d:comments/d:authors/d:author";
-
-  /// <summary>
-  /// Author
-  /// </summary>
-  public string Author {
-    get {
-      int authorRef = _commentHelper.GetXmlNodeInt("@authorId");
-      return _commentHelper.TopNode.OwnerDocument
-          .SelectSingleNode(
-              string.Format("{0}[{1}]", _authorPath, authorRef + 1),
-              _commentHelper.NameSpaceManager)
-          .InnerText;
-    }
-  }
-
-  private int GetAuthor(string value) {
-    int authorRef = 0;
-    bool found = false;
-    foreach (XmlElement node in _commentHelper.TopNode.OwnerDocument.SelectNodes(
-        _authorPath,
-        _commentHelper.NameSpaceManager)) {
-      if (node.InnerText == value) {
-        found = true;
-        break;
-      }
-      authorRef++;
-    }
-    if (!found) {
-      var elem = _commentHelper.TopNode.OwnerDocument.CreateElement(
-          "d",
-          "author",
-          ExcelPackage._schemaMain);
-      _commentHelper.TopNode.OwnerDocument
-          .SelectSingleNode(_authorsPath, _commentHelper.NameSpaceManager)
-          .AppendChild(elem);
-      elem.InnerText = value;
-    }
-    return authorRef;
-  }
-
-  /// <summary>
-  /// The comment text
-  /// </summary>
-  public string Text {
-    get {
-      if (!string.IsNullOrEmpty(RichText.Text)) {
-        return RichText.Text;
-      }
-      return _text;
-    }
-  }
-
-  /// <summary>
-  /// Sets the font of the first richtext item.
-  /// </summary>
-  public ExcelRichText Font {
-    get {
-      if (RichText.Count > 0) {
-        return RichText[0];
-      }
-      return null;
-    }
-  }
-
-  /// <summary>
-  /// Richtext collection
-  /// </summary>
-  internal ExcelRichTextCollection RichText { get; set; }
-}
diff --git a/EPPlus/ExcelCommentCollection.cs b/EPPlus/ExcelCommentCollection.cs
deleted file mode 100644
index 70a4820..0000000
--- a/EPPlus/ExcelCommentCollection.cs
+++ /dev/null
@@ -1,145 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Jan Källman		License changed GPL-->LGPL 2011-12-27
- *******************************************************************************/
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Xml;
-using OfficeOpenXml.Packaging;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// Collection of Excelcomment objects
-/// </summary>
-public class ExcelCommentCollection : IEnumerable, IDisposable {
-  internal RangeCollection _comments;
-
-  internal ExcelCommentCollection(ExcelPackage pck, ExcelWorksheet ws, XmlNamespaceManager ns) {
-    CommentXml.PreserveWhitespace = false;
-    NameSpaceManager = ns;
-    Worksheet = ws;
-    CreateXml(pck);
-    AddCommentsFromXml();
-  }
-
-  private void CreateXml(ExcelPackage pck) {
-    var commentParts = Worksheet.Part.GetRelationshipsByType(ExcelPackage._schemaComment);
-    bool isLoaded = false;
-    CommentXml = new();
-    foreach (var commentPart in commentParts) {
-      Uri = UriHelper.ResolvePartUri(commentPart.SourceUri, commentPart.TargetUri);
-      Part = pck.Package.GetPart(Uri);
-      XmlHelper.LoadXmlSafe(CommentXml, Part.GetStream());
-      RelId = commentPart.Id;
-      isLoaded = true;
-    }
-    //Create a new document
-    if (!isLoaded) {
-      CommentXml.LoadXml(
-          "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><comments xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\"><authors /><commentList /></comments>");
-      Uri = null;
-    }
-  }
-
-  private void AddCommentsFromXml() {
-    var lst = new List<IRangeId>();
-    foreach (XmlElement node in CommentXml.SelectNodes(
-        "//d:commentList/d:comment",
-        NameSpaceManager)) {
-      var comment = new ExcelComment(
-          NameSpaceManager,
-          node,
-          new(Worksheet, node.GetAttribute("ref")));
-      lst.Add(comment);
-    }
-    _comments = new(lst);
-  }
-
-  /// <summary>
-  /// Access to the comment xml document
-  /// </summary>
-  public XmlDocument CommentXml { get; set; } = new();
-
-  internal Uri Uri { get; set; }
-
-  internal string RelId { get; set; }
-
-  internal XmlNamespaceManager NameSpaceManager { get; set; }
-
-  internal ZipPackagePart Part { get; set; }
-
-  /// <summary>
-  /// A reference to the worksheet object
-  /// </summary>
-  public ExcelWorksheet Worksheet { get; set; }
-
-  /// <summary>
-  /// Number of comments in the collection
-  /// </summary>
-  public int Count => _comments.Count;
-
-  /// <summary>
-  /// Indexer for the comments collection
-  /// </summary>
-  /// <param name="index">The index</param>
-  /// <returns>The comment</returns>
-  public ExcelComment this[int index] {
-    get {
-      if (index < 0 || index >= _comments.Count) {
-        throw (new ArgumentOutOfRangeException("Comment index out of range"));
-      }
-      return _comments[index] as ExcelComment;
-    }
-  }
-
-  /// <summary>
-  /// Indexer for the comments collection
-  /// </summary>
-  /// <param name="cell">The cell</param>
-  /// <returns>The comment</returns>
-  public ExcelComment this[ExcelCellAddress cell] {
-    get {
-      ulong cellId = ExcelCellBase.GetCellId(Worksheet.SheetID, cell.Row, cell.Column);
-      if (_comments.IndexOf(cellId) >= 0) {
-        return _comments[cellId] as ExcelComment;
-      }
-      return null;
-    }
-  }
-
-  void IDisposable.Dispose() {}
-
-  IEnumerator IEnumerable.GetEnumerator() {
-    return _comments;
-  }
-}
diff --git a/EPPlus/ExcelHyperLink.cs b/EPPlus/ExcelHyperLink.cs
deleted file mode 100644
index dc4aa3b..0000000
--- a/EPPlus/ExcelHyperLink.cs
+++ /dev/null
@@ -1,137 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		Added this class		        2010-01-24
- * Jan Källman		License changed GPL-->LGPL 2011-12-27
- *******************************************************************************/
-
-using System;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// HyperlinkClass
-/// </summary>
-public class ExcelHyperLink : Uri {
-  /// <summary>
-  /// A new hyperlink with the specified URI
-  /// </summary>
-  /// <param name="uriString">The URI</param>
-  public ExcelHyperLink(string uriString)
-      : base(uriString) {
-    OriginalUri = this;
-  }
-
-  /// <summary>
-  /// A new hyperlink with the specified URI. This syntax is obsolete
-  /// </summary>
-  /// <param name="uriString">The URI</param>
-  /// <param name="dontEscape"></param>
-  [Obsolete(
-      "base constructor 'System.Uri.Uri(string, bool)' is obsolete: 'The constructor has been deprecated. Please use new ExcelHyperLink(string). The dontEscape parameter is deprecated and is always false.")]
-  public ExcelHyperLink(string uriString, bool dontEscape)
-      : base(uriString, dontEscape) {
-    OriginalUri = this;
-  }
-
-  /// <summary>
-  /// A new hyperlink with the specified URI and kind
-  /// </summary>
-  /// <param name="uriString">The URI</param>
-  /// <param name="uriKind">Kind (absolute/relative or indeterminate)</param>
-  public ExcelHyperLink(string uriString, UriKind uriKind)
-      : base(uriString, uriKind) {
-    OriginalUri = this;
-  }
-
-  /// <summary>
-  /// Sheet internal reference
-  /// </summary>
-  /// <param name="referenceAddress">Address</param>
-  /// <param name="display">Displayed text</param>
-  public ExcelHyperLink(string referenceAddress, string display)
-      : base(
-          "xl://internal") //URI is not used on internal links so put a dummy uri here.
-  {
-    _referenceAddress = referenceAddress;
-    _display = display;
-  }
-
-  private string _referenceAddress;
-
-  /// <summary>
-  /// The Excel address for internal links.
-  /// </summary>
-  public string ReferenceAddress {
-    get => _referenceAddress;
-    set => _referenceAddress = value;
-  }
-
-  private string _display = "";
-
-  /// <summary>
-  /// Displayed text
-  /// </summary>
-  public string Display {
-    get => _display;
-    set => _display = value;
-  }
-
-  /// <summary>
-  /// Tooltip
-  /// </summary>
-  public string ToolTip { get; set; }
-
-  private int _colSpann;
-
-  /// <summary>
-  /// If the hyperlink spans multiple columns
-  /// </summary>
-  public int ColSpann {
-    get => _colSpann;
-    set => _colSpann = value;
-  }
-
-  private int _rowSpann;
-
-  /// <summary>
-  /// If the hyperlink spans multiple rows
-  /// </summary>
-  public int RowSpann {
-    get => _rowSpann;
-    set => _rowSpann = value;
-  }
-
-  /// <summary>
-  /// Used to handle non absolute URI's.
-  /// Is used if IsAblsoluteUri is true. The base URI will have a dummy value of xl://nonAbsolute.
-  /// </summary>
-  public Uri OriginalUri { get; internal set; }
-
-  internal string RId { get; set; }
-}
diff --git a/EPPlus/ExcelNamedRange.cs b/EPPlus/ExcelNamedRange.cs
deleted file mode 100644
index 96337ae..0000000
--- a/EPPlus/ExcelNamedRange.cs
+++ /dev/null
@@ -1,104 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		Added this class		        2010-01-28
- * Jan Källman		License changed GPL-->LGPL 2011-12-27
- *******************************************************************************/
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// A named range.
-/// </summary>
-public sealed class ExcelNamedRange : ExcelRangeBase {
-  private readonly ExcelWorksheet _sheet;
-
-  /// <summary>
-  /// A named range
-  /// </summary>
-  /// <param name="name">The name</param>
-  /// <param name="nameSheet">The sheet containing the name. null if its a global name</param>
-  /// <param name="sheet">Sheet where the address points</param>
-  /// <param name="address">The address</param>
-  /// <param name="index">The index in the collection</param>
-  public ExcelNamedRange(
-      string name,
-      ExcelWorksheet nameSheet,
-      ExcelWorksheet sheet,
-      string address,
-      int index)
-      : base(sheet, address) {
-    Name = name;
-    _sheet = nameSheet;
-    Index = index;
-  }
-
-  internal ExcelNamedRange(string name, ExcelWorkbook wb, ExcelWorksheet nameSheet, int index)
-      : base(wb, nameSheet, name, true) {
-    Name = name;
-    _sheet = nameSheet;
-    Index = index;
-  }
-
-  /// <summary>
-  /// Name of the range
-  /// </summary>
-  public string Name { get; internal set; }
-
-  /// <summary>
-  /// Is the named range local for the sheet
-  /// </summary>
-  public int LocalSheetId {
-    get {
-      if (_sheet == null) {
-        return -1;
-      }
-      return _sheet.PositionID - 1;
-    }
-  }
-
-  internal int Index { get; set; }
-
-  /// <summary>
-  /// Is the name hidden
-  /// </summary>
-  public bool IsNameHidden { get; set; }
-
-  /// <summary>
-  /// A comment for the Name
-  /// </summary>
-  public string NameComment { get; set; }
-
-  internal object NameValue { get; set; }
-
-  internal string NameFormula { get; set; }
-
-  public override string ToString() {
-    return Name;
-  }
-}
diff --git a/EPPlus/ExcelNamedRangeCollection.cs b/EPPlus/ExcelNamedRangeCollection.cs
deleted file mode 100644
index 3584a54..0000000
--- a/EPPlus/ExcelNamedRangeCollection.cs
+++ /dev/null
@@ -1,206 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		Added this class		        2010-01-28
- * Jan Källman		License changed GPL-->LGPL 2011-12-27
- *******************************************************************************/
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// Collection for named ranges
-/// </summary>
-public class ExcelNamedRangeCollection : IEnumerable<ExcelNamedRange> {
-  internal ExcelWorksheet _ws;
-  internal ExcelWorkbook _wb;
-
-  internal ExcelNamedRangeCollection(ExcelWorkbook wb) {
-    _wb = wb;
-    _ws = null;
-  }
-
-  internal ExcelNamedRangeCollection(ExcelWorkbook wb, ExcelWorksheet ws) {
-    _wb = wb;
-    _ws = ws;
-  }
-
-  private readonly List<ExcelNamedRange> _list = new();
-  private readonly Dictionary<string, int> _dic = new(StringComparer.InvariantCultureIgnoreCase);
-
-  /// <summary>
-  /// Add a new named range
-  /// </summary>
-  /// <param name="name">The name</param>
-  /// <param name="range">The range</param>
-  /// <returns></returns>
-  public ExcelNamedRange Add(string name, ExcelRangeBase range) {
-    ExcelNamedRange item;
-    if (range.IsName) {
-      item = new(name, _wb, _ws, _dic.Count);
-    } else {
-      item = new(name, _ws, range.Worksheet, range.Address, _dic.Count);
-    }
-
-    AddName(name, item);
-
-    return item;
-  }
-
-  private void AddName(string name, ExcelNamedRange item) {
-    // Is 'Name' already present
-    if (_dic.ContainsKey(name)) {
-      int index = _dic[name];
-      if ((0 <= index) && (index < _list.Count)) {
-        ExcelNamedRange listItem = _list[index];
-        if ((listItem != null)
-            && (listItem.FullAddress != null)
-            && (listItem.FullAddress == item.FullAddress)) {
-          return;
-        }
-
-        //throw new Exception(string.Format("Name '{0}' is defined in the worksheet more than once. First as '{1}' and second as '{2}'.", Name, listItem.FullAddress, item.FullAddress));
-        return;
-      }
-
-      //throw new Exception(string.Format("Name '{0}' is defined in the worksheet more than once.", Name));
-      return;
-    }
-
-    _dic.Add(name, _list.Count);
-    _list.Add(item);
-  }
-
-  /// <summary>
-  /// Add a defined name referencing value
-  /// </summary>
-  /// <param name="name"></param>
-  /// <param name="value"></param>
-  /// <returns></returns>
-  public ExcelNamedRange AddValue(string name, object value) {
-    var item = new ExcelNamedRange(name, _wb, _ws, _dic.Count);
-    item.NameValue = value;
-    AddName(name, item);
-    return item;
-  }
-
-  /// <summary>
-  /// Add a defined name referencing a formula -- the method name contains a typo.
-  /// This method is obsolete and will be removed in the future.
-  /// Use <see cref="AddFormula"/>
-  /// </summary>
-  /// <param name="name"></param>
-  /// <param name="formula"></param>
-  /// <returns></returns>
-  [Obsolete("Call AddFormula() instead.  See Issue Tracker Id #14687")]
-  public ExcelNamedRange AddFormla(string name, string formula) {
-    return AddFormula(name, formula);
-  }
-
-  /// <summary>
-  /// Add a defined name referencing a formula
-  /// </summary>
-  /// <param name="name"></param>
-  /// <param name="formula"></param>
-  /// <returns></returns>
-  public ExcelNamedRange AddFormula(string name, string formula) {
-    var item = new ExcelNamedRange(name, _wb, _ws, _dic.Count);
-    item.NameFormula = formula;
-    AddName(name, item);
-    return item;
-  }
-
-  /// <summary>
-  /// Remove a defined name from the collection
-  /// </summary>
-  /// <param name="name">The name</param>
-  public void Remove(string name) {
-    if (_dic.ContainsKey(name)) {
-      var ix = _dic[name];
-
-      for (int i = ix + 1; i < _list.Count; i++) {
-        _dic.Remove(_list[i].Name);
-        _list[i].Index--;
-        _dic.Add(_list[i].Name, _list[i].Index);
-      }
-      _dic.Remove(name);
-      _list.RemoveAt(ix);
-    }
-  }
-
-  /// <summary>
-  /// Checks collection for the presence of a key
-  /// </summary>
-  /// <param name="key">key to search for</param>
-  /// <returns>true if the key is in the collection</returns>
-  public bool ContainsKey(string key) {
-    return _dic.ContainsKey(key);
-  }
-
-  /// <summary>
-  /// The current number of items in the collection
-  /// </summary>
-  public int Count => _dic.Count;
-
-  /// <summary>
-  /// Name indexer
-  /// </summary>
-  /// <param name="name">The name (key) for a Named range</param>
-  /// <returns>a reference to the range</returns>
-  /// <remarks>
-  /// Throws a KeyNotFoundException if the key is not in the collection.
-  /// </remarks>
-  public ExcelNamedRange this[string name] => _list[_dic[name]];
-
-  public ExcelNamedRange this[int index] => _list[index];
-
-  /// <summary>
-  /// Implement interface method IEnumerator&lt;ExcelNamedRange&gt; GetEnumerator()
-  /// </summary>
-  /// <returns></returns>
-  public IEnumerator<ExcelNamedRange> GetEnumerator() {
-    return _list.GetEnumerator();
-  }
-
-  /// <summary>
-  /// Implement interface method IEnumeratable GetEnumerator()
-  /// </summary>
-  /// <returns></returns>
-  IEnumerator IEnumerable.GetEnumerator() {
-    return _list.GetEnumerator();
-  }
-
-  internal void Clear() {
-    while (Count > 0) {
-      Remove(_list[0].Name);
-    }
-  }
-}
diff --git a/EPPlus/ExcelPackage.cs b/EPPlus/ExcelPackage.cs
deleted file mode 100644
index 7d12a0e..0000000
--- a/EPPlus/ExcelPackage.cs
+++ /dev/null
@@ -1,215 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		                Initial Release		        2009-10-01
- * Starnuto Di Topo & Jan Källman   Added stream constructors
- *                                  and Load method Save as
- *                                  stream                      2010-03-14
- * Jan Källman		License changed GPL-->LGPL 2011-12-27
- *******************************************************************************/
-
-using System;
-using System.IO;
-using System.Xml;
-using OfficeOpenXml.Packaging;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// Represents an Excel XLSX file package.
-/// This is the top-level object to access all parts of the document.
-/// </summary>
-public sealed class ExcelPackage {
-  /// <summary>
-  /// Extention Schema types
-  /// </summary>
-  internal const string _schemaXmlExtension = "application/xml";
-  internal const string _schemaRelsExtension =
-      "application/vnd.openxmlformats-package.relationships+xml";
-
-  /// <summary>
-  /// Main Xml schema name
-  /// </summary>
-  internal const string _schemaMain = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
-
-  /// <summary>
-  /// Relationship schema name
-  /// </summary>
-  internal const string _schemaRelationships =
-      "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
-
-  internal const string _schemaMicrosoftVml = "urn:schemas-microsoft-com:vml";
-  internal const string _schemaMicrosoftOffice = "urn:schemas-microsoft-com:office:office";
-  internal const string _schemaMicrosoftExcel = "urn:schemas-microsoft-com:office:excel";
-
-  internal const string _schemaChart = "http://schemas.openxmlformats.org/drawingml/2006/chart";
-  internal const string _schemaHyperlink =
-      "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
-  internal const string _schemaComment =
-      "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
-
-  //Office properties
-  internal const string _schemaCore =
-      "http://schemas.openxmlformats.org/package/2006/metadata/core-properties";
-  internal const string _schemaExtended =
-      "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties";
-  internal const string _schemaCustom =
-      "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties";
-  internal const string _schemaDc = "http://purl.org/dc/elements/1.1/";
-  internal const string _schemaDcTerms = "http://purl.org/dc/terms/";
-  internal const string _schemaDcmiType = "http://purl.org/dc/dcmitype/";
-  internal const string _schemaXsi = "http://www.w3.org/2001/XMLSchema-instance";
-  internal const string _schemaVt =
-      "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes";
-
-  internal const string _contentTypeSharedString =
-      "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml";
-
-  /// <summary>
-  /// Maximum number of columns in a worksheet (16384).
-  /// </summary>
-  public const int MaxColumns = 16384;
-
-  /// <summary>
-  /// Maximum number of rows in a worksheet (1048576).
-  /// </summary>
-  public const int MaxRows = 1048576;
-
-  /// <summary>
-  /// Create a new, empty package.
-  /// </summary>
-  public ExcelPackage() {
-    Package = new();
-    Workbook = new(this, CreateDefaultNsm());
-  }
-
-  /// <summary>
-  /// Create a new instance of the ExcelPackage class based on an existing file.
-  /// </summary>
-  public ExcelPackage(FileInfo newFile) {
-    using var inputStream = newFile.OpenRead();
-    Package = new(inputStream);
-    Workbook = new(this, CreateDefaultNsm());
-  }
-
-  /// <summary>
-  /// Create a new instance of the ExcelPackage class based on a stream.
-  /// </summary>
-  public ExcelPackage(Stream newStream) {
-    Package = new(newStream);
-    Workbook = new(this, CreateDefaultNsm());
-  }
-
-  internal ZipPackage Package { get; }
-
-  /// <summary>
-  /// Returns a reference to the workbook component within the package.
-  /// All worksheets and cells can be accessed through the workbook.
-  /// </summary>
-  public ExcelWorkbook Workbook { get; }
-
-  private XmlNamespaceManager CreateDefaultNsm() {
-    //  Create a NamespaceManager to handle the default namespace,
-    //  and create a prefix for the default namespace:
-    NameTable nt = new NameTable();
-    var ns = new XmlNamespaceManager(nt);
-    ns.AddNamespace(string.Empty, _schemaMain);
-    ns.AddNamespace("d", _schemaMain);
-    ns.AddNamespace("r", _schemaRelationships);
-    ns.AddNamespace("c", _schemaChart);
-    ns.AddNamespace("vt", _schemaVt);
-    // extended properties (app.xml)
-    ns.AddNamespace("xp", _schemaExtended);
-    // custom properties
-    ns.AddNamespace("ctp", _schemaCustom);
-    // core properties
-    ns.AddNamespace("cp", _schemaCore);
-    // core property namespaces
-    ns.AddNamespace("dc", _schemaDc);
-    ns.AddNamespace("dcterms", _schemaDcTerms);
-    ns.AddNamespace("dcmitype", _schemaDcmiType);
-    ns.AddNamespace("xsi", _schemaXsi);
-    return ns;
-  }
-
-  internal XmlDocument GetXmlDocument(Uri uri) {
-    var xmlDocument = new XmlDocument();
-    var part = Package.GetPart(uri);
-    XmlHelper.LoadXmlSafe(xmlDocument, part.GetStream());
-    part.SaveHandler = writer => xmlDocument.Save(writer);
-    return xmlDocument;
-  }
-
-  internal ZipPackageRelationship CreateXmlDocument(
-      Uri uri,
-      string contentType,
-      string relationship,
-      XmlDocument newDoc) {
-    Package.CreatePart(uri, contentType, newDoc.Save);
-    return Package.CreateRelationship(
-        UriHelper.GetRelativeUri(new("/xl", UriKind.Relative), uri),
-        TargetMode.Internal,
-        relationship);
-  }
-
-  internal XmlDocument GetOrCreateXmlDocument(
-      Uri uri,
-      string contentType,
-      string relationship,
-      Func<XmlDocument> createDocument) {
-    if (Package.PartExists(uri)) {
-      return GetXmlDocument(uri);
-    }
-    var newDoc = createDocument();
-    CreateXmlDocument(uri, contentType, relationship, newDoc);
-    return newDoc;
-  }
-
-  internal XmlDocument GetOrCreateXmlDocument(
-      Uri uri,
-      string contentType,
-      string relationship,
-      string initialDocumentXml) =>
-    GetOrCreateXmlDocument(
-        uri,
-        contentType,
-        relationship,
-        () => {
-          var emptyDocument = new XmlDocument();
-          emptyDocument.LoadXml(initialDocumentXml);
-          return emptyDocument;
-        });
-
-  public byte[] GetAsByteArray() {
-    var result = new MemoryStream();
-    Workbook.Save();
-    Package.Save(result);
-    return result.ToArray();
-  }
-}
diff --git a/EPPlus/ExcelProtectedRange.cs b/EPPlus/ExcelProtectedRange.cs
deleted file mode 100644
index f89c544..0000000
--- a/EPPlus/ExcelProtectedRange.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System.Xml;
-
-namespace OfficeOpenXml;
-
-public class ExcelProtectedRange : XmlHelper {
-  public string Name => GetXmlNodeString("@name");
-
-  private ExcelAddress _address;
-
-  public ExcelAddress Address => _address ??= new(GetXmlNodeString("@sqref"));
-
-  internal ExcelProtectedRange(XmlNamespaceManager ns, XmlNode topNode)
-      : base(ns, topNode) {}
-}
diff --git a/EPPlus/ExcelProtectedRangeCollection.cs b/EPPlus/ExcelProtectedRangeCollection.cs
deleted file mode 100644
index 0b95ccf..0000000
--- a/EPPlus/ExcelProtectedRangeCollection.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using System.Collections;
-using System.Collections.Generic;
-using System.Xml;
-
-namespace OfficeOpenXml;
-
-public class ExcelProtectedRangeCollection : XmlHelper, IEnumerable<ExcelProtectedRange> {
-  internal ExcelProtectedRangeCollection(XmlNamespaceManager nsm, XmlNode topNode)
-      : base(nsm, topNode) {
-    foreach (XmlNode protectedRangeNode in topNode.SelectNodes(
-        "d:protectedRanges/d:protectedRange",
-        nsm)) {
-      if (!(protectedRangeNode is XmlElement)) {
-        continue;
-      }
-      _baseList.Add(new(nsm, topNode));
-    }
-  }
-
-  private readonly List<ExcelProtectedRange> _baseList = new();
-
-  public ExcelProtectedRange this[int index] => _baseList[index];
-
-  IEnumerator<ExcelProtectedRange> IEnumerable<ExcelProtectedRange>.GetEnumerator() {
-    return _baseList.GetEnumerator();
-  }
-
-  IEnumerator IEnumerable.GetEnumerator() {
-    return _baseList.GetEnumerator();
-  }
-}
diff --git a/EPPlus/ExcelProtection.cs b/EPPlus/ExcelProtection.cs
deleted file mode 100644
index 5d0c943..0000000
--- a/EPPlus/ExcelProtection.cs
+++ /dev/null
@@ -1,79 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		    Added		10-AUG-2010
- * Jan Källman		    License changed GPL-->LGPL 2011-12-27
- *******************************************************************************/
-
-using System.Collections.Immutable;
-using System.Xml;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// Sets protection on the workbook level
-///<seealso cref="ExcelEncryption"/>
-///<seealso cref="ExcelSheetProtection"/>
-/// </summary>
-public class ExcelProtection : XmlHelper {
-  protected override ImmutableArray<string> SchemaNodeOrder =>
-    ExcelWorkbook.WorkbookSchemaNodeOrder;
-
-  internal ExcelProtection(XmlNamespaceManager ns, XmlNode topNode)
-      : base(ns, topNode) {}
-
-  private const string _lockStructurePath = "d:workbookProtection/@lockStructure";
-
-  /// <summary>
-  /// Locks the structure,which prevents users from adding or deleting worksheets or from displaying hidden worksheets.
-  /// </summary>
-  public bool LockStructure {
-    get => GetXmlNodeBool(_lockStructurePath, false);
-    set => SetXmlNodeBool(_lockStructurePath, value, false);
-  }
-
-  private const string _lockWindowsPath = "d:workbookProtection/@lockWindows";
-
-  /// <summary>
-  /// Locks the position of the workbook window.
-  /// </summary>
-  public bool LockWindows {
-    get => GetXmlNodeBool(_lockWindowsPath, false);
-    set => SetXmlNodeBool(_lockWindowsPath, value, false);
-  }
-
-  private const string _lockRevisionPath = "d:workbookProtection/@lockRevision";
-
-  /// <summary>
-  /// Lock the workbook for revision
-  /// </summary>
-  public bool LockRevision {
-    get => GetXmlNodeBool(_lockRevisionPath, false);
-    set => SetXmlNodeBool(_lockRevisionPath, value, false);
-  }
-}
diff --git a/EPPlus/ExcelRange.cs b/EPPlus/ExcelRange.cs
deleted file mode 100644
index 92352fc..0000000
--- a/EPPlus/ExcelRange.cs
+++ /dev/null
@@ -1,123 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		    Initial Release		        2009-10-01
- * Jan Källman		    License changed GPL-->LGPL 2011-12-27
- *******************************************************************************/
-
-using System;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// A range of cells.
-/// </summary>
-public class ExcelRange : ExcelRangeBase {
-  internal ExcelRange(ExcelWorksheet sheet)
-      : base(sheet) {}
-
-  internal ExcelRange(ExcelWorksheet sheet, string address)
-      : base(sheet, address) {}
-
-  internal ExcelRange(ExcelWorksheet sheet, int fromRow, int fromCol, int toRow, int toCol)
-      : base(sheet) {
-    _fromRow = fromRow;
-    _fromCol = fromCol;
-    _toRow = toRow;
-    _toCol = toCol;
-  }
-
-  /// <summary>
-  /// Access the range using an address
-  /// </summary>
-  /// <param name="address">The address</param>
-  /// <returns>A range object</returns>
-  public ExcelRange this[string address] {
-    get {
-      if (_worksheet.Names.ContainsKey(address)) {
-        if (_worksheet.Names[address].IsName) {
-          return null;
-        }
-        Address = _worksheet.Names[address].Address;
-      } else {
-        Address = address;
-      }
-      return this;
-    }
-  }
-
-  /// <summary>
-  /// Access a single cell
-  /// </summary>
-  /// <param name="row">The row</param>
-  /// <param name="col">The column</param>
-  /// <returns>A range object</returns>
-  public ExcelRange this[int row, int col] {
-    get {
-      ValidateRowCol(row, col);
-
-      _fromCol = col;
-      _fromRow = row;
-      _toCol = col;
-      _toRow = row;
-      Address = GetAddress(_fromRow, _fromCol);
-      return this;
-    }
-  }
-
-  /// <summary>
-  /// Access a range of cells
-  /// </summary>
-  /// <param name="fromRow">Start row</param>
-  /// <param name="fromCol">Start column</param>
-  /// <param name="toRow">End Row</param>
-  /// <param name="toCol">End Column</param>
-  /// <returns></returns>
-  public ExcelRange this[int fromRow, int fromCol, int toRow, int toCol] {
-    get {
-      ValidateRowCol(fromRow, fromCol);
-      ValidateRowCol(toRow, toCol);
-
-      _fromCol = fromCol;
-      _fromRow = fromRow;
-      _toCol = toCol;
-      _toRow = toRow;
-      Address = GetAddress(_fromRow, _fromCol, _toRow, _toCol);
-      return this;
-    }
-  }
-
-  private static void ValidateRowCol(int row, int col) {
-    if (row < 1 || row > ExcelPackage.MaxRows) {
-      throw (new ArgumentException("Row out of range"));
-    }
-    if (col < 1 || col > ExcelPackage.MaxColumns) {
-      throw (new ArgumentException("Column out of range"));
-    }
-  }
-}
diff --git a/EPPlus/ExcelRangeBase.cs b/EPPlus/ExcelRangeBase.cs
deleted file mode 100644
index 9c82531..0000000
--- a/EPPlus/ExcelRangeBase.cs
+++ /dev/null
@@ -1,1535 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		    Initial Release		        2010-01-28
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- * Eyal Seagull		    Conditional Formatting      2012-04-03
- *******************************************************************************/
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Security;
-using System.Text;
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting;
-using OfficeOpenXml.DataValidation;
-using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-using OfficeOpenXml.Style;
-using OfficeOpenXml.Style.XmlAccess;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// A range of cells
-/// </summary>
-public class ExcelRangeBase
-    : ExcelAddress,
-      IExcelCell,
-      IDisposable,
-      IEnumerable<ExcelRangeBase>,
-      IEnumerator<ExcelRangeBase> {
-  /// <summary>
-  /// Reference to the worksheet
-  /// </summary>
-  protected ExcelWorksheet _worksheet;
-  internal ExcelWorkbook _workbook;
-
-  private delegate void ChangePropHandler(SetValueHandler method, object value);
-
-  private delegate void SetValueHandler(object value, int row, int col);
-
-  private ChangePropHandler _changePropMethod;
-  private int _styleID;
-
-  private class CopiedCell {
-    internal int Row { get; set; }
-
-    internal int Column { get; set; }
-
-    internal object Value { get; set; }
-
-    internal string Type { get; set; }
-
-    internal object Formula { get; set; }
-
-    internal int? StyleID { get; set; }
-
-    internal Uri HyperLink { get; set; }
-
-    internal ExcelComment Comment { get; set; }
-
-    internal Byte Flag { get; set; }
-  }
-
-  //private class CopiedFlag
-  //{
-  //    internal int Row { get; set; }
-  //    internal int Column { get; set; }
-  //    internal Byte Flag { get; set; }
-  //}
-
-
-  internal ExcelRangeBase(ExcelWorksheet worksheet) {
-    _worksheet = worksheet;
-    _ws = _worksheet.Name;
-    _workbook = _worksheet.Workbook;
-    AddressChange += ExcelRangeBase_AddressChange;
-    SetDelegate();
-  }
-
-  private void ExcelRangeBase_AddressChange(object sender, EventArgs e) {
-    if (Table != null) {
-      SetRcFromTable(_workbook, null);
-    }
-    SetDelegate();
-  }
-
-  internal ExcelRangeBase(ExcelWorksheet worksheet, string address)
-      : base(worksheet == null ? "" : worksheet.Name, address) {
-    _worksheet = worksheet;
-    _workbook = worksheet.Workbook;
-    SetRcFromTable(_workbook, null);
-    if (string.IsNullOrEmpty(_ws)) {
-      _ws = _worksheet == null ? "" : _worksheet.Name;
-    }
-    AddressChange += ExcelRangeBase_AddressChange;
-    SetDelegate();
-  }
-
-  internal ExcelRangeBase(ExcelWorkbook wb, ExcelWorksheet xlWorksheet, string address, bool isName)
-      : base(xlWorksheet == null ? "" : xlWorksheet.Name, address, isName) {
-    SetRcFromTable(wb, null);
-    _worksheet = xlWorksheet;
-    _workbook = wb;
-    if (string.IsNullOrEmpty(_ws)) {
-      _ws = xlWorksheet?.Name;
-    }
-    AddressChange += ExcelRangeBase_AddressChange;
-    SetDelegate();
-  }
-
-  ~ExcelRangeBase() {
-    //this.AddressChange -= new EventHandler(ExcelRangeBase_AddressChange);
-  }
-
-  private void SetDelegate() {
-    if (_fromRow == -1) {
-      _changePropMethod = SetUnknown;
-    }
-    //Single cell
-    else if (_fromRow == _toRow && _fromCol == _toCol && Addresses == null) {
-      _changePropMethod = SetSingle;
-    }
-    //Range (ex A1:A2)
-    else if (Addresses == null) {
-      _changePropMethod = SetRange;
-    }
-    //Multi Range (ex A1:A2,C1:C2)
-    else {
-      _changePropMethod = SetMultiRange;
-    }
-  }
-
-  /// <summary>
-  /// We dont know the address yet. Set the delegate first time a property is set.
-  /// </summary>
-  /// <param name="valueMethod"></param>
-  /// <param name="value"></param>
-  private void SetUnknown(SetValueHandler valueMethod, object value) {
-    //Address is not set use, selected range
-    if (_fromRow == -1) {
-      SetToSelectedRange();
-    }
-    SetDelegate();
-    _changePropMethod(valueMethod, value);
-  }
-
-  /// <summary>
-  /// Set a single cell
-  /// </summary>
-  /// <param name="valueMethod"></param>
-  /// <param name="value"></param>
-  private void SetSingle(SetValueHandler valueMethod, object value) {
-    valueMethod(value, _fromRow, _fromCol);
-  }
-
-  /// <summary>
-  /// Set a range
-  /// </summary>
-  /// <param name="valueMethod"></param>
-  /// <param name="value"></param>
-  private void SetRange(SetValueHandler valueMethod, object value) {
-    SetValueAddress(this, valueMethod, value);
-  }
-
-  /// <summary>
-  /// Set a multirange (A1:A2,C1:C2)
-  /// </summary>
-  /// <param name="valueMethod"></param>
-  /// <param name="value"></param>
-  private void SetMultiRange(SetValueHandler valueMethod, object value) {
-    SetValueAddress(this, valueMethod, value);
-    foreach (var address in Addresses) {
-      SetValueAddress(address, valueMethod, value);
-    }
-  }
-
-  /// <summary>
-  /// Set the property for an address
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="valueMethod"></param>
-  /// <param name="value"></param>
-  private void SetValueAddress(ExcelAddress address, SetValueHandler valueMethod, object value) {
-    IsRangeValid("");
-    if (_fromRow == 1
-        && _fromCol == 1
-        && _toRow == ExcelPackage.MaxRows
-        && _toCol
-            == ExcelPackage.MaxColumns) //Full sheet (ex ws.Cells.Value=0). Set value for A1 only to avoid hanging
-    {
-      throw (new ArgumentException(
-              "Can't reference all cells. Please use the indexer to set the range"));
-    }
-    for (int col = address.Start.Column; col <= address.End.Column; col++) {
-      for (int row = address.Start.Row; row <= address.End.Row; row++) {
-        valueMethod(value, row, col);
-      }
-    }
-  }
-
-  private void Set_StyleID(object value, int row, int col) {
-    _worksheet._styles.SetValue(row, col, (int)value);
-  }
-
-  private void Set_Value(object value, int row, int col) {
-    //ExcelCell c = _worksheet.Cell(row, col);
-    var sfi = _worksheet._formulas.GetValue(row, col);
-    if (sfi is int) {
-      SplitFormulas(_worksheet.Cells[row, col]);
-    }
-    if (sfi != null) {
-      _worksheet._formulas.SetValue(row, col, string.Empty);
-    }
-    _worksheet._values.SetValue(row, col, value);
-  }
-
-  private void Set_Formula(object value, int row, int col) {
-    //ExcelCell c = _worksheet.Cell(row, col);
-    var f = _worksheet._formulas.GetValue(row, col);
-    if (f is int i && i >= 0) {
-      SplitFormulas(_worksheet.Cells[row, col]);
-    }
-
-    string formula = (value == null ? string.Empty : value.ToString());
-    if (formula == string.Empty) {
-      _worksheet._formulas.SetValue(row, col, string.Empty);
-    } else {
-      if (formula[0] == '=') {
-        value = formula.Substring(1, formula.Length - 1); // remove any starting equalsign.
-      }
-      _worksheet._formulas.SetValue(row, col, formula);
-      _worksheet._values.SetValue(row, col, null);
-    }
-  }
-
-  /// <summary>
-  /// Handles shared formulas
-  /// </summary>
-  /// <param name="value">The  formula</param>
-  /// <param name="address">The address of the formula</param>
-  /// <param name="isArray">If the forumla is an array formula.</param>
-  private void Set_SharedFormula(string value, ExcelAddress address, bool isArray) {
-    if (_fromRow == 1
-        && _fromCol == 1
-        && _toRow == ExcelPackage.MaxRows
-        && _toCol
-            == ExcelPackage.MaxColumns) //Full sheet (ex ws.Cells.Value=0). Set value for A1 only to avoid hanging
-    {
-      throw (new InvalidOperationException("Can't set a formula for the entire worksheet"));
-    }
-    if (address.Start.Row == address.End.Row
-        && address.Start.Column == address.End.Column
-        && !isArray) //is it really a shared formula? Arrayformulas can be one cell only
-    {
-      //Nope, single cell. Set the formula
-      Set_Formula(value, address.Start.Row, address.Start.Column);
-      return;
-    }
-    //RemoveFormuls(address);
-    CheckAndSplitSharedFormula(address);
-    ExcelWorksheet.Formulas f = new ExcelWorksheet.Formulas(SourceCodeTokenizer.Default);
-    f.Formula = value;
-    f.Index = _worksheet.GetMaxShareFunctionIndex(isArray);
-    f.Address = address.FirstAddress;
-    f.StartCol = address.Start.Column;
-    f.StartRow = address.Start.Row;
-    f.IsArray = isArray;
-
-    _worksheet._sharedFormulas.Add(f.Index, f);
-    //_worksheet.Cell(address.Start.Row, address.Start.Column).SharedFormulaID = f.Index;
-    //_worksheet.Cell(address.Start.Row, address.Start.Column).Formula = value;
-
-    for (int col = address.Start.Column; col <= address.End.Column; col++) {
-      for (int row = address.Start.Row; row <= address.End.Row; row++) {
-        //_worksheet.Cell(row, col).SharedFormulaID = f.Index;
-        _worksheet._formulas.SetValue(row, col, f.Index);
-        _worksheet._values.SetValue(row, col, null);
-      }
-    }
-  }
-
-  private void Set_HyperLink(object value, int row, int col) {
-    //_worksheet.Cell(row, col).Hyperlink = value as Uri;
-    if (value is Uri uri) {
-      _worksheet._hyperLinks.SetValue(row, col, uri);
-
-      if (uri is ExcelHyperLink link) {
-        _worksheet._values.SetValue(row, col, link.Display);
-      } else {
-        _worksheet._values.SetValue(row, col, uri.OriginalString);
-      }
-    } else {
-      _worksheet._hyperLinks.SetValue(row, col, null);
-      _worksheet._values.SetValue(row, col, null);
-    }
-  }
-
-  private void Set_IsArrayFormula(object value, int row, int col) {
-    _worksheet._flags.SetFlagValue(row, col, (bool)value, CellFlags.ArrayFormula);
-  }
-
-  private void Set_IsRichText(object value, int row, int col) {
-    //_worksheet.Cell(row, col).IsRichText = (bool)value;
-    _worksheet._flags.SetFlagValue(row, col, (bool)value, CellFlags.RichText);
-  }
-
-  private void Exists_Comment(object value, int row, int col) {
-    ulong cellId = GetCellId(_worksheet.SheetID, row, col);
-    if (_worksheet.Comments._comments.ContainsKey(cellId)) {
-      throw (new InvalidOperationException(
-              string.Format(
-                  "Cell {0} already contain a comment.",
-                  new ExcelCellAddress(row, col).Address)));
-    }
-  }
-
-  private void SetToSelectedRange() {
-    if (_worksheet.View.SelectedRange == "") {
-      Address = "A1";
-    } else {
-      Address = _worksheet.View.SelectedRange;
-    }
-  }
-
-  private void IsRangeValid(string type) {
-    if (_fromRow <= 0) {
-      if (_address == "") {
-        SetToSelectedRange();
-      } else {
-        if (type == "") {
-          throw (new InvalidOperationException(
-                  string.Format("Range is not valid for this operation: {0}", _address)));
-        }
-        throw (new InvalidOperationException(
-                string.Format("Range is not valid for {0} : {1}", type, _address)));
-      }
-    }
-  }
-
-  /// <summary>
-  /// The styleobject for the range.
-  /// </summary>
-  public ExcelStyle Style {
-    get {
-      IsRangeValid("styling");
-      int s = 0;
-      if (!_worksheet._styles.Exists(
-          _fromRow,
-          _fromCol,
-          ref s)) //Cell exists
-      {
-        if (!_worksheet._styles.Exists(
-            _fromRow,
-            0,
-            ref s)) //No, check Row style
-        {
-          var c = Worksheet.GetColumn(_fromCol);
-          if (c == null) {
-            s = 0;
-          } else {
-            s = c.StyleID;
-          }
-        }
-      }
-      return _worksheet.Workbook.Styles.GetStyleObject(s, _worksheet.PositionID, Address);
-    }
-  }
-
-  /// <summary>
-  /// The named style
-  /// </summary>
-  public string StyleName {
-    get {
-      IsRangeValid("styling");
-      int xfId;
-      if (_fromRow == 1 && _toRow == ExcelPackage.MaxRows) {
-        xfId = GetColumnStyle(_fromCol);
-      } else if (_fromCol == 1 && _toCol == ExcelPackage.MaxColumns) {
-        xfId = 0;
-        if (!_worksheet._styles.Exists(_fromRow, 0, ref xfId)) {
-          xfId = GetColumnStyle(_fromCol);
-        }
-      } else {
-        xfId = 0;
-        if (!_worksheet._styles.Exists(_fromRow, _fromCol, ref xfId)) {
-          if (!_worksheet._styles.Exists(_fromRow, 0, ref xfId)) {
-            xfId = GetColumnStyle(_fromCol);
-          }
-        }
-      }
-      int nsId;
-      if (xfId <= 0) {
-        nsId = Style.Styles.CellXfs[0].XfId;
-      } else {
-        nsId = Style.Styles.CellXfs[xfId].XfId;
-      }
-      foreach (var ns in Style.Styles.NamedStyles) {
-        if (ns.StyleXfId == nsId) {
-          return ns.Name;
-        }
-      }
-
-      return "";
-    }
-    set {
-      _styleID = _worksheet.Workbook.Styles.GetStyleIdFromName(value);
-      int col = _fromCol;
-      if (_fromRow == 1
-          && _toRow
-              == ExcelPackage.MaxRows) //Full column
-      {
-        ExcelColumn column;
-        //Get the startcolumn
-        //ulong colID = ExcelColumn.GetColumnID(_worksheet.SheetID, column);
-        var c = _worksheet.GetValue(0, _fromCol);
-        if (c == null) {
-          column = _worksheet.Column(_fromCol);
-          //if (_worksheet._values.PrevCell(ref row, ref col))
-          //{
-          //    var prevCol = (ExcelColumn)_worksheet._values.GetValue(row, col);
-          //    column = prevCol.Clone(_worksheet, column);
-          //    prevCol.ColumnMax = column - 1;
-          //}
-        } else {
-          column = (ExcelColumn)c;
-        }
-
-        column.StyleName = value;
-        column.StyleID = _styleID;
-
-        //var index = _worksheet._columns.IndexOf(colID);
-        var cols = new CellsStoreEnumerator<object>(_worksheet._values, 0, _fromCol + 1, 0, _toCol);
-        if (cols.Next()) {
-          col = _fromCol;
-          while (column.ColumnMin <= _toCol) {
-            if (column.ColumnMax > _toCol) {
-              var newCol = _worksheet.CopyColumn(column, _toCol + 1, column.ColumnMax);
-              column.ColumnMax = _toCol;
-            }
-
-            column._styleName = value;
-            column.StyleID = _styleID;
-
-            if (cols.Value == null) {
-              break;
-            }
-            var nextCol = (ExcelColumn)cols.Value;
-            if (column.ColumnMax < nextCol.ColumnMax - 1) {
-              column.ColumnMax = nextCol.ColumnMax - 1;
-            }
-            column = nextCol;
-            cols.Next();
-          }
-        }
-        if (column.ColumnMax < _toCol) {
-          column.ColumnMax = _toCol;
-        }
-        //if (column.ColumnMin == column)
-        //{
-        //    column.ColumnMax = _toCol;
-        //}
-        //else if (column._columnMax < _toCol)
-        //{
-        //    var newCol = _worksheet.Column(column._columnMax + 1) as ExcelColumn;
-        //    newCol._columnMax = _toCol;
-
-        //    newCol._styleID = _styleID;
-        //    newCol._styleName = value;
-        //}
-        if (_fromCol == 1
-            && _toCol
-                == ExcelPackage.MaxColumns) //FullRow
-        {
-          var rows = new CellsStoreEnumerator<object>(
-              _worksheet._values,
-              1,
-              0,
-              ExcelPackage.MaxRows,
-              0);
-          rows.Next();
-          while (rows.Value != null) {
-            _worksheet._styles.SetValue(rows.Row, 0, _styleID);
-            if (!rows.Next()) {
-              break;
-            }
-          }
-        }
-      } else if (_fromCol == 1
-          && _toCol
-              == ExcelPackage.MaxColumns) //FullRow
-      {
-        for (int r = _fromRow; r <= _toRow; r++) {
-          _worksheet.Row(r)._styleName = value;
-          _worksheet.Row(r).StyleID = _styleID;
-        }
-      }
-
-      if (!((_fromRow == 1 && _toRow == ExcelPackage.MaxRows)
-                  || (_fromCol == 1
-                          && _toCol
-                              == ExcelPackage.MaxColumns))) //Cell specific
-      {
-        for (int c = _fromCol; c <= _toCol; c++) {
-          for (int r = _fromRow; r <= _toRow; r++) {
-            _worksheet._styles.SetValue(r, c, _styleID);
-          }
-        }
-      } else //Only set name on created cells. (uncreated cells is set on full row or full column).
-      {
-        var cells = new CellsStoreEnumerator<object>(
-            _worksheet._values,
-            _fromRow,
-            _fromCol,
-            _toRow,
-            _toCol);
-        while (cells.Next()) {
-          _worksheet._styles.SetValue(cells.Row, cells.Column, _styleID);
-        }
-      }
-      //_changePropMethod(Set_StyleName, value);
-    }
-  }
-
-  private int GetColumnStyle(int col) {
-    object c = null;
-    if (_worksheet._values.Exists(0, col, ref c)) {
-      return (c as ExcelColumn).StyleID;
-    }
-    int row = 0;
-    if (_worksheet._values.PrevCell(ref row, ref col)) {
-      var column = _worksheet._values.GetValue(row, col) as ExcelColumn;
-      if (column.ColumnMax >= col) {
-        return _worksheet._styles.GetValue(row, col);
-      }
-    }
-    return 0;
-  }
-
-  /// <summary>
-  /// The style ID.
-  /// It is not recomended to use this one. Use Named styles as an alternative.
-  /// If you do, make sure that you use the Style.UpdateXml() method to update any new styles added to the workbook.
-  /// </summary>
-  public int StyleID {
-    get {
-      int s = 0;
-      if (!_worksheet._styles.Exists(_fromRow, _fromCol, ref s)) {
-        if (!_worksheet._styles.Exists(_fromRow, 0, ref s)) {
-          s = _worksheet._styles.GetValue(0, _fromCol);
-        }
-      }
-      return s;
-    }
-    set => _changePropMethod(Set_StyleID, value);
-  }
-
-  /// <summary>
-  /// Set the range to a specific value
-  /// </summary>
-  public object Value {
-    get {
-      if (IsName) {
-        if (_worksheet == null) {
-          return _workbook._names[_address].NameValue;
-        }
-        return _worksheet.Names[_address].NameValue;
-      }
-      if (_fromRow == _toRow && _fromCol == _toCol) {
-        return _worksheet.GetValue(_fromRow, _fromCol);
-      }
-      return GetValueArray();
-    }
-    set {
-      if (IsName) {
-        if (_worksheet == null) {
-          _workbook._names[_address].NameValue = value;
-        } else {
-          _worksheet.Names[_address].NameValue = value;
-        }
-      } else {
-        _changePropMethod(Set_Value, value);
-      }
-    }
-  }
-
-  private object GetValueArray() {
-    ExcelAddressBase addr;
-    if (_fromRow == 1
-        && _fromCol == 1
-        && _toRow == ExcelPackage.MaxRows
-        && _toCol == ExcelPackage.MaxColumns) {
-      addr = _worksheet.Dimension;
-      if (addr == null) {
-        return null;
-      }
-    } else {
-      addr = this;
-    }
-    object[,] v = new object[addr._toRow - addr._fromRow + 1, addr._toCol - addr._fromCol + 1];
-
-    for (int col = addr._fromCol; col <= addr._toCol; col++) {
-      for (int row = addr._fromRow; row <= addr._toRow; row++) {
-        if (_worksheet._values.Exists(row, col)) {
-          if (_worksheet._flags.GetFlagValue(row, col, CellFlags.RichText)) {
-            v[row - addr._fromRow, col - addr._fromCol] = GetRichText(row, col).Text;
-          } else {
-            v[row - addr._fromRow, col - addr._fromCol] = _worksheet._values.GetValue(row, col);
-          }
-        }
-      }
-    }
-    return v;
-  }
-
-  /// <summary>
-  /// Returns the formatted value.
-  /// </summary>
-  public string Text => GetFormattedText(false);
-
-  private string GetFormattedText(bool forWidthCalc) {
-    object v = Value;
-    if (v == null) {
-      return "";
-    }
-    var styles = Worksheet.Workbook.Styles;
-    var nfId = styles.CellXfs[StyleID].NumberFormatId;
-    ExcelNumberFormatXml.ExcelFormatTranslator nf = null;
-    for (int i = 0; i < styles.NumberFormats.Count; i++) {
-      if (nfId == styles.NumberFormats[i].NumFmtId) {
-        nf = styles.NumberFormats[i].FormatTranslator;
-        break;
-      }
-    }
-
-    string format,
-        textFormat;
-    if (forWidthCalc) {
-      format = nf.NetFormatForWidth;
-      textFormat = nf.NetTextFormatForWidth;
-    } else {
-      format = nf.NetFormat;
-      textFormat = nf.NetTextFormat;
-    }
-
-    return FormatValue(v, nf, format, textFormat);
-  }
-
-  internal static string FormatValue(
-      object v,
-      ExcelNumberFormatXml.ExcelFormatTranslator nf,
-      string format,
-      string textFormat) {
-    if (v is decimal || v.GetType().IsPrimitive) {
-      double d;
-      try {
-        d = Convert.ToDouble(v);
-      } catch {
-        return "";
-      }
-
-      if (nf.DataType == ExcelNumberFormatXml.eFormatType.Number) {
-        if (string.IsNullOrEmpty(nf.FractionFormat)) {
-          return d.ToString(format, nf.Culture);
-        }
-        return nf.FormatFraction(d);
-      }
-      if (nf.DataType == ExcelNumberFormatXml.eFormatType.DateTime) {
-        var date = DateTime.FromOADate(d);
-        return date.ToString(format, nf.Culture);
-      }
-    } else if (v is DateTime time) {
-      if (nf.DataType == ExcelNumberFormatXml.eFormatType.DateTime) {
-        return time.ToString(format, nf.Culture);
-      }
-      double d = time.ToOADate();
-      if (string.IsNullOrEmpty(nf.FractionFormat)) {
-        return d.ToString(format, nf.Culture);
-      }
-      return nf.FormatFraction(d);
-    } else if (v is TimeSpan span) {
-      if (nf.DataType == ExcelNumberFormatXml.eFormatType.DateTime) {
-        return new DateTime(span.Ticks).ToString(format, nf.Culture);
-      }
-      double d = (new DateTime(span.Ticks)).ToOADate();
-      if (string.IsNullOrEmpty(nf.FractionFormat)) {
-        return d.ToString(format, nf.Culture);
-      }
-      return nf.FormatFraction(d);
-    } else {
-      if (textFormat == "") {
-        return v.ToString();
-      }
-      return string.Format(textFormat, v);
-    }
-    return v.ToString();
-  }
-
-  /// <summary>
-  /// Gets or sets a formula for a range.
-  /// </summary>
-  public string Formula {
-    get {
-      if (IsName) {
-        if (_worksheet == null) {
-          return _workbook._names[_address].NameFormula;
-        }
-        return _worksheet.Names[_address].NameFormula;
-      }
-      return _worksheet.GetFormula(_fromRow, _fromCol);
-    }
-    set {
-      if (IsName) {
-        if (_worksheet == null) {
-          _workbook._names[_address].NameFormula = value;
-        } else {
-          _worksheet.Names[_address].NameFormula = value;
-        }
-      } else {
-        if (value == null || value.Trim() == "") {
-          //Set the cells to null
-          Value = null;
-        } else if (_fromRow == _toRow && _fromCol == _toCol) {
-          Set_Formula(value, _fromRow, _fromCol);
-        } else {
-          Set_SharedFormula(value, this, false);
-          if (Addresses != null) {
-            foreach (var address in Addresses) {
-              Set_SharedFormula(value, address, false);
-            }
-          }
-        }
-      }
-    }
-  }
-
-  /// <summary>
-  /// Gets or Set a formula in R1C1 format.
-  /// </summary>
-  public string FormulaR1C1 {
-    get {
-      IsRangeValid("FormulaR1C1");
-      return _worksheet.GetFormulaR1C1(_fromRow, _fromCol);
-    }
-    set {
-      IsRangeValid("FormulaR1C1");
-      if (value.Length > 0 && value[0] == '=') {
-        value = value.Substring(1, value.Length - 1); // remove any starting equalsign.
-      }
-
-      if (value == null || value.Trim() == "") {
-        //Set the cells to null
-        _worksheet.Cells[TranslateFromR1C1(value, _fromRow, _fromCol)].Value = null;
-      } else if (Addresses == null) {
-        Set_SharedFormula(TranslateFromR1C1(value, _fromRow, _fromCol), this, false);
-      } else {
-        Set_SharedFormula(
-            TranslateFromR1C1(value, _fromRow, _fromCol),
-            new(WorkSheet, FirstAddress),
-            false);
-        foreach (var address in Addresses) {
-          Set_SharedFormula(
-              TranslateFromR1C1(value, address.Start.Row, address.Start.Column),
-              address,
-              false);
-        }
-      }
-    }
-  }
-
-  /// <summary>
-  /// Gets or Set a formula in R1C1 format.
-  ///
-  public string FormulaR1C1_V1 {
-    get {
-      IsRangeValid("FormulaR1C1");
-      return _worksheet.GetFormulaR1C1_V1(_fromRow, _fromCol);
-    }
-  }
-
-  public string ArrayFormulaAddress {
-    get {
-      IsRangeValid("FormulaR1C1");
-      return _worksheet.GetArrayFormulaAddress(_fromRow, _fromCol);
-    }
-  }
-
-  /// <summary>
-  /// Set the hyperlink property for a range of cells
-  /// </summary>
-  public Uri Hyperlink {
-    get {
-      IsRangeValid("formulaR1C1");
-      return _worksheet._hyperLinks.GetValue(_fromRow, _fromCol);
-    }
-    set => _changePropMethod(Set_HyperLink, value);
-  }
-
-  /// <summary>
-  /// If the cells in the range are merged.
-  /// </summary>
-  public bool Merge {
-    get {
-      IsRangeValid("merging");
-      for (int col = _fromCol; col <= _toCol; col++) {
-        for (int row = _fromRow; row <= _toRow; row++) {
-          if (_worksheet.MergedCells[row, col] == null) {
-            return false;
-          }
-          //if (!_worksheet._flags.GetFlagValue(row, col, CellFlags.Merged))
-          //{
-          //    return false;
-          //}
-        }
-      }
-      return true;
-    }
-    set {
-      IsRangeValid("merging");
-      //SetMerge(value, FirstAddress);
-      if (value) {
-        _worksheet.MergedCells.Add(new(FirstAddress), true);
-        if (Addresses != null) {
-          foreach (var address in Addresses) {
-            _worksheet.MergedCells.Add(address, true);
-            //SetMerge(value, address._address);
-          }
-        }
-      } else {
-        _worksheet.MergedCells.Clear(this);
-        if (Addresses != null) {
-          foreach (var address in Addresses) {
-            _worksheet.MergedCells.Clear(address);
-            ;
-          }
-        }
-      }
-    }
-  }
-
-  //private void SetMerge(bool value, string address)
-  //{
-  //    if (!value)
-  //    {
-  //        if (_worksheet.MergedCells.List.Contains(address))
-  //        {
-  //            SetCellMerge(false, address);
-  //            _worksheet.MergedCells.List.Remove(address);
-  //        }
-  //        else if (!CheckMergeDiff(false, address))
-  //        {
-  //            throw (new Exception("Range is not fully merged.Specify the exact range"));
-  //        }
-  //    }
-  //    else
-  //    {
-  //        if (CheckMergeDiff(false, address))
-  //        {
-  //            SetCellMerge(true, address);
-  //            _worksheet.MergedCells.List.Add(address);
-  //        }
-  //        else
-  //        {
-  //            if (!_worksheet.MergedCells.List.Contains(address))
-  //            {
-  //                throw (new Exception("Cells are already merged"));
-  //            }
-  //        }
-  //    }
-  //}
-  /// <summary>
-  /// Set an autofilter for the range
-  /// </summary>
-  public bool AutoFilter {
-    get {
-      IsRangeValid("autofilter");
-      ExcelAddressBase address = _worksheet.AutoFilterAddress;
-      if (address == null) {
-        return false;
-      }
-      if (_fromRow >= address.Start.Row
-          && _toRow <= address.End.Row
-          && _fromCol >= address.Start.Column
-          && _toCol <= address.End.Column) {
-        return true;
-      }
-      return false;
-    }
-    set {
-      IsRangeValid("autofilter");
-      _worksheet.AutoFilterAddress = this;
-      if (_worksheet.Names.ContainsKey("_xlnm._FilterDatabase")) {
-        _worksheet.Names.Remove("_xlnm._FilterDatabase");
-      }
-      var result = _worksheet.Names.Add("_xlnm._FilterDatabase", this);
-      result.IsNameHidden = true;
-    }
-  }
-
-  /// <summary>
-  /// If the value is in richtext format.
-  /// </summary>
-  public bool IsRichText {
-    get {
-      IsRangeValid("richtext");
-      return _worksheet._flags.GetFlagValue(_fromRow, _fromCol, CellFlags.RichText);
-    }
-    set => _changePropMethod(Set_IsRichText, value);
-  }
-
-  /// <summary>
-  /// Is the range a part of an Arrayformula
-  /// </summary>
-  public bool IsArrayFormula {
-    get {
-      IsRangeValid("arrayformulas");
-      return _worksheet._flags.GetFlagValue(_fromRow, _fromCol, CellFlags.ArrayFormula);
-    }
-    set => _changePropMethod(Set_IsArrayFormula, value);
-  }
-
-  private ExcelRichTextCollection _rtc;
-
-  /// <summary>
-  /// Cell value is richtext formatted.
-  /// Richtext-property only apply to the left-top cell of the range.
-  /// </summary>
-  public ExcelRichTextCollection RichText {
-    get {
-      IsRangeValid("richtext");
-      if (_rtc == null) {
-        _rtc = GetRichText(_fromRow, _fromCol);
-      }
-      return _rtc;
-    }
-  }
-
-  private ExcelRichTextCollection GetRichText(int row, int col) {
-    XmlDocument xml = new XmlDocument();
-    var v = _worksheet._values.GetValue(row, col);
-    var isRt = _worksheet._flags.GetFlagValue(row, col, CellFlags.RichText);
-    if (v != null) {
-      if (isRt) {
-        XmlHelper.LoadXmlSafe(
-            xml,
-            "<d:si xmlns:d=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" >"
-                + v
-                + "</d:si>",
-            Encoding.UTF8);
-      } else {
-        xml.LoadXml(
-            "<d:si xmlns:d=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" ><d:r><d:t>"
-                + SecurityElement.Escape(v.ToString())
-                + "</d:t></d:r></d:si>");
-      }
-    } else {
-      xml.LoadXml("<d:si xmlns:d=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" />");
-    }
-    var rtc = new ExcelRichTextCollection(
-        _worksheet.NameSpaceManager,
-        xml.SelectSingleNode("d:si", _worksheet.NameSpaceManager),
-        this);
-    return rtc;
-  }
-
-  /// <summary>
-  /// returns the comment object of the first cell in the range
-  /// </summary>
-  public ExcelComment Comment {
-    get {
-      IsRangeValid("comments");
-      ulong cellId = GetCellId(_worksheet.SheetID, _fromRow, _fromCol);
-      if (_worksheet.Comments._comments.ContainsKey(cellId)) {
-        return _worksheet._comments._comments[cellId] as ExcelComment;
-      }
-      return null;
-    }
-  }
-
-  /// <summary>
-  /// WorkSheet object
-  /// </summary>
-  public ExcelWorksheet Worksheet => _worksheet;
-
-  /// <summary>
-  /// Address including sheetname
-  /// </summary>
-  public string FullAddress {
-    get {
-      string fullAddress = GetFullAddress(_worksheet.Name, _address);
-      if (Addresses != null) {
-        foreach (var a in Addresses) {
-          fullAddress += "," + GetFullAddress(_worksheet.Name, a.Address);
-          ;
-        }
-      }
-      return fullAddress;
-    }
-  }
-
-  /// <summary>
-  /// Address including sheetname
-  /// </summary>
-  public string FullAddressAbsolute {
-    get {
-      string wbwsRef = string.IsNullOrEmpty(_wb) ? _ws : "[" + _wb.Replace("'", "''") + "]" + _ws;
-      string fullAddress = GetFullAddress(
-          wbwsRef,
-          GetAddress(_fromRow, _fromCol, _toRow, _toCol, true));
-      if (Addresses != null) {
-        foreach (var a in Addresses) {
-          fullAddress +=
-              ","
-                  + GetFullAddress(
-                      wbwsRef,
-                      GetAddress(a.Start.Row, a.Start.Column, a.End.Row, a.End.Column, true));
-          ;
-        }
-      }
-      return fullAddress;
-    }
-  }
-
-  /// <summary>
-  /// Address including sheetname
-  /// </summary>
-  internal string FullAddressAbsoluteNoFullRowCol {
-    get {
-      string wbwsRef = string.IsNullOrEmpty(_wb) ? _ws : "[" + _wb.Replace("'", "''") + "]" + _ws;
-      string fullAddress = GetFullAddress(
-          wbwsRef,
-          GetAddress(_fromRow, _fromCol, _toRow, _toCol, true),
-          false);
-      if (Addresses != null) {
-        foreach (var a in Addresses) {
-          fullAddress +=
-              ","
-                  + GetFullAddress(
-                      wbwsRef,
-                      GetAddress(a.Start.Row, a.Start.Column, a.End.Row, a.End.Column, true),
-                      false);
-          ;
-        }
-      }
-      return fullAddress;
-    }
-  }
-
-  /// <summary>
-  /// Set the value without altering the richtext property
-  /// </summary>
-  /// <param name="value">the value</param>
-  internal void SetValueRichText(object value) {
-    if (_fromRow == 1
-        && _fromCol == 1
-        && _toRow == ExcelPackage.MaxRows
-        && _toCol
-            == ExcelPackage.MaxColumns) //Full sheet (ex ws.Cells.Value=0). Set value for A1 only to avoid hanging
-    {
-      //_worksheet.Cell(1, 1).SetValueRichText(value);
-      SetValue(value, 1, 1);
-    } else {
-      //for (int col = _fromCol; col <= _toCol; col++)
-      //{
-      //    for (int row = _fromRow; row <= _toRow; row++)
-      //    {
-      //_worksheet.Cell(row, col).SetValueRichText(value);
-      SetValue(value, _fromRow, _fromCol);
-      //}
-      //}
-    }
-  }
-
-  private void SetValue(object value, int row, int col) {
-    _worksheet.SetValue(row, col, value);
-    // if (value is string) _worksheet._types.SetValue(row, col, "S"); else _worksheet._types.SetValue(row, col, "");
-    _worksheet._formulas.SetValue(row, col, "");
-  }
-
-  internal void SetSharedFormulaId(int id) {
-    for (int col = _fromCol; col <= _toCol; col++) {
-      for (int row = _fromRow; row <= _toRow; row++) {
-        _worksheet._formulas.SetValue(row, col, id);
-      }
-    }
-  }
-
-  private void CheckAndSplitSharedFormula(ExcelAddressBase address) {
-    for (int col = address._fromCol; col <= address._toCol; col++) {
-      for (int row = address._fromRow; row <= address._toRow; row++) {
-        var f = _worksheet._formulas.GetValue(row, col);
-        if (f is int i && i >= 0) {
-          SplitFormulas(address);
-          return;
-        }
-      }
-    }
-  }
-
-  private void SplitFormulas(ExcelAddressBase address) {
-    List<int> formulas = new List<int>();
-    for (int col = address._fromCol; col <= address._toCol; col++) {
-      for (int row = address._fromRow; row <= address._toRow; row++) {
-        var f = _worksheet._formulas.GetValue(row, col);
-        if (f is int id) {
-          if (id >= 0 && !formulas.Contains(id)) {
-            if (_worksheet._sharedFormulas[id].IsArray
-                && Collide(_worksheet.Cells[_worksheet._sharedFormulas[id].Address])
-                    == eAddressCollition.Partly) // If the formula is an array formula and its on the inside the overwriting range throw an exception
-            {
-              throw (new InvalidOperationException("Can not overwrite a part of an array-formula"));
-            }
-            formulas.Add(id);
-          }
-        }
-      }
-    }
-
-    foreach (int ix in formulas) {
-      SplitFormula(address, ix);
-    }
-
-    ////Clear any formula references inside the refered range
-    //_worksheet._formulas.Clear(address._fromRow, address._toRow, address._toRow - address._fromRow + 1, address._toCol - address.column + 1);
-  }
-
-  private void SplitFormula(ExcelAddressBase address, int ix) {
-    var f = _worksheet._sharedFormulas[ix];
-    var fRange = _worksheet.Cells[f.Address];
-    var collide = address.Collide(fRange);
-
-    //The formula is inside the currenct range, remove it
-    if (collide == eAddressCollition.Equal || collide == eAddressCollition.Inside) {
-      _worksheet._sharedFormulas.Remove(ix);
-      return;
-      //fRange.SetSharedFormulaID(int.MinValue);
-    }
-    var firstCellCollide = address.Collide(
-        new(fRange._fromRow, fRange._fromCol, fRange._fromRow, fRange._fromCol));
-    if (collide == eAddressCollition.Partly
-        && (firstCellCollide == eAddressCollition.Inside
-                || firstCellCollide
-                    == eAddressCollition.Equal)) //Do we need to split? Only if the functions first row is inside the new range.
-    {
-      //The formula partly collides with the current range
-      bool fIsSet = false;
-      string formulaR1C1 = fRange.FormulaR1C1;
-      //Top Range
-      if (fRange._fromRow < _fromRow) {
-        f.Address = GetAddress(fRange._fromRow, fRange._fromCol, _fromRow - 1, fRange._toCol);
-        fIsSet = true;
-      }
-      //Left Range
-      if (fRange._fromCol < address._fromCol) {
-        if (fIsSet) {
-          f = new(SourceCodeTokenizer.Default);
-          f.Index = _worksheet.GetMaxShareFunctionIndex(false);
-          f.StartCol = fRange._fromCol;
-          f.IsArray = false;
-          _worksheet._sharedFormulas.Add(f.Index, f);
-        } else {
-          fIsSet = true;
-        }
-        if (fRange._fromRow < address._fromRow) {
-          f.StartRow = address._fromRow;
-        } else {
-          f.StartRow = fRange._fromRow;
-        }
-        if (fRange._toRow < address._toRow) {
-          f.Address = GetAddress(f.StartRow, f.StartCol, fRange._toRow, address._fromCol - 1);
-        } else {
-          f.Address = GetAddress(f.StartRow, f.StartCol, address._toRow, address._fromCol - 1);
-        }
-        f.Formula = TranslateFromR1C1(formulaR1C1, f.StartRow, f.StartCol);
-        _worksheet.Cells[f.Address].SetSharedFormulaId(f.Index);
-      }
-      //Right Range
-      if (fRange._toCol > address._toCol) {
-        if (fIsSet) {
-          f = new(SourceCodeTokenizer.Default);
-          f.Index = _worksheet.GetMaxShareFunctionIndex(false);
-          f.IsArray = false;
-          _worksheet._sharedFormulas.Add(f.Index, f);
-        } else {
-          fIsSet = true;
-        }
-        f.StartCol = address._toCol + 1;
-        if (address._fromRow < fRange._fromRow) {
-          f.StartRow = fRange._fromRow;
-        } else {
-          f.StartRow = address._fromRow;
-        }
-
-        if (fRange._toRow < address._toRow) {
-          f.Address = GetAddress(f.StartRow, f.StartCol, fRange._toRow, fRange._toCol);
-        } else {
-          f.Address = GetAddress(f.StartRow, f.StartCol, address._toRow, fRange._toCol);
-        }
-        f.Formula = TranslateFromR1C1(formulaR1C1, f.StartRow, f.StartCol);
-        _worksheet.Cells[f.Address].SetSharedFormulaId(f.Index);
-      }
-      //Bottom Range
-      if (fRange._toRow > address._toRow) {
-        if (fIsSet) {
-          f = new(SourceCodeTokenizer.Default);
-          f.Index = _worksheet.GetMaxShareFunctionIndex(false);
-          f.IsArray = false;
-          _worksheet._sharedFormulas.Add(f.Index, f);
-        }
-
-        f.StartCol = fRange._fromCol;
-        f.StartRow = _toRow + 1;
-
-        f.Formula = TranslateFromR1C1(formulaR1C1, f.StartRow, f.StartCol);
-
-        f.Address = GetAddress(f.StartRow, f.StartCol, fRange._toRow, fRange._toCol);
-        _worksheet.Cells[f.Address].SetSharedFormulaId(f.Index);
-      }
-    }
-  }
-
-  private object ConvertData(ExcelTextFormat format, string v, int col, bool isText) {
-    if (isText && (format.DataTypes == null || format.DataTypes.Length < col)) {
-      return v;
-    }
-
-    double d;
-    DateTime dt;
-    if (format.DataTypes == null
-        || format.DataTypes.Length <= col
-        || format.DataTypes[col] == eDataTypes.Unknown) {
-      string v2 = v.EndsWith("%") ? v.Substring(0, v.Length - 1) : v;
-      if (double.TryParse(v2, NumberStyles.Any, format.Culture, out d)) {
-        if (v2 == v) {
-          return d;
-        }
-        return d / 100;
-      }
-      if (DateTime.TryParse(v, format.Culture, DateTimeStyles.None, out dt)) {
-        return dt;
-      }
-      return v;
-    }
-    switch (format.DataTypes[col]) {
-      case eDataTypes.Number:
-        if (double.TryParse(v, NumberStyles.Any, format.Culture, out d)) {
-          return d;
-        }
-        return v;
-      case eDataTypes.DateTime:
-        if (DateTime.TryParse(v, format.Culture, DateTimeStyles.None, out dt)) {
-          return dt;
-        }
-        return v;
-      case eDataTypes.Percent:
-        string v2 = v.EndsWith("%") ? v.Substring(0, v.Length - 1) : v;
-        if (double.TryParse(v2, NumberStyles.Any, format.Culture, out d)) {
-          return d / 100;
-        }
-        return v;
-
-      default:
-        return v;
-    }
-  }
-
-  /// <summary>
-  /// Conditional Formatting for this range.
-  /// </summary>
-  public IRangeConditionalFormatting ConditionalFormatting =>
-    new RangeConditionalFormatting(_worksheet, new(Address));
-
-  /// <summary>
-  /// Data validation for this range.
-  /// </summary>
-  public IRangeDataValidation DataValidation => new RangeDataValidation(_worksheet, Address);
-
-  /// <summary>
-  /// Get the strongly typed value of the cell.
-  /// </summary>
-  /// <typeparam name="T">The type</typeparam>
-  /// <returns>The value. If the value can't be converted to the specified type, the default value will be returned</returns>
-  public T GetValue<T>() {
-    return _worksheet.GetTypedValue<T>(Value);
-  }
-
-  /// <summary>
-  /// Get a range with an offset from the top left cell.
-  /// The new range has the same dimensions as the current range
-  /// </summary>
-  /// <param name="rowOffset">Row Offset</param>
-  /// <param name="columnOffset">Column Offset</param>
-  /// <returns></returns>
-  public ExcelRangeBase Offset(int rowOffset, int columnOffset) {
-    if (_fromRow + rowOffset < 1
-        || _fromCol + columnOffset < 1
-        || _fromRow + rowOffset > ExcelPackage.MaxRows
-        || _fromCol + columnOffset > ExcelPackage.MaxColumns) {
-      throw (new ArgumentOutOfRangeException("Offset value out of range"));
-    }
-    string address = GetAddress(
-        _fromRow + rowOffset,
-        _fromCol + columnOffset,
-        _toRow + rowOffset,
-        _toCol + columnOffset);
-    return new(_worksheet, address);
-  }
-
-  /// <summary>
-  /// Get a range with an offset from the top left cell.
-  /// </summary>
-  /// <param name="rowOffset">Row Offset</param>
-  /// <param name="columnOffset">Column Offset</param>
-  /// <param name="numberOfRows">Number of rows. Minimum 1</param>
-  /// <param name="numberOfColumns">Number of colums. Minimum 1</param>
-  /// <returns></returns>
-  public ExcelRangeBase Offset(
-      int rowOffset,
-      int columnOffset,
-      int numberOfRows,
-      int numberOfColumns) {
-    if (numberOfRows < 1 || numberOfColumns < 1) {
-      throw (new("Number of rows/columns must be greater than 0"));
-    }
-    numberOfRows--;
-    numberOfColumns--;
-    if (_fromRow + rowOffset < 1
-        || _fromCol + columnOffset < 1
-        || _fromRow + rowOffset > ExcelPackage.MaxRows
-        || _fromCol + columnOffset > ExcelPackage.MaxColumns
-        || _fromRow + rowOffset + numberOfRows < 1
-        || _fromCol + columnOffset + numberOfColumns < 1
-        || _fromRow + rowOffset + numberOfRows > ExcelPackage.MaxRows
-        || _fromCol + columnOffset + numberOfColumns > ExcelPackage.MaxColumns) {
-      throw (new ArgumentOutOfRangeException("Offset value out of range"));
-    }
-    string address = GetAddress(
-        _fromRow + rowOffset,
-        _fromCol + columnOffset,
-        _fromRow + rowOffset + numberOfRows,
-        _fromCol + columnOffset + numberOfColumns);
-    return new(_worksheet, address);
-  }
-
-  /// <summary>
-  /// Clear all cells
-  /// </summary>
-  public void Clear() {
-    Delete(this, false);
-  }
-
-  /// <summary>
-  /// Creates an array-formula.
-  /// </summary>
-  /// <param name="arrayFormula">The formula</param>
-  public void CreateArrayFormula(string arrayFormula) {
-    if (Addresses != null) {
-      throw (new("An Arrayformula can not have more than one address"));
-    }
-    Set_SharedFormula(arrayFormula, this, true);
-  }
-
-  //private void Clear(ExcelAddressBase Range)
-  //{
-  //    Clear(Range, true);
-  //}
-  internal void Delete(ExcelAddressBase range, bool shift) {
-    //DeleteCheckMergedCells(Range);
-    _worksheet.MergedCells.Clear(range);
-    //First find the start cell
-    int fromRow,
-        fromCol;
-    var d = Worksheet.Dimension;
-    if (d != null
-        && range._fromRow <= d._fromRow
-        && range._toRow
-            >= d._toRow) //EntireRow?
-    {
-      fromRow = 0;
-    } else {
-      fromRow = range._fromRow;
-    }
-    if (d != null
-        && range._fromCol <= d._fromCol
-        && range._toCol
-            >= d._toCol) //EntireRow?
-    {
-      fromCol = 0;
-    } else {
-      fromCol = range._fromCol;
-    }
-
-    var rows = range._toRow - fromRow + 1;
-    var cols = range._toCol - fromCol + 1;
-
-    _worksheet._values.Delete(fromRow, fromCol, rows, cols, shift);
-    _worksheet._types.Delete(fromRow, fromCol, rows, cols, shift);
-    _worksheet._styles.Delete(fromRow, fromCol, rows, cols, shift);
-    _worksheet._formulas.Delete(fromRow, fromCol, rows, cols, shift);
-    _worksheet._hyperLinks.Delete(fromRow, fromCol, rows, cols, shift);
-    _worksheet._flags.Delete(fromRow, fromCol, rows, cols, shift);
-    _worksheet._commentsStore.Delete(fromRow, fromCol, rows, cols, shift);
-
-    //if(shift)
-    //{
-    //    _worksheet.AdjustFormulasRow(fromRow, rows);
-    //}
-
-    //Clear multi addresses as well
-    if (Addresses != null) {
-      foreach (var sub in Addresses) {
-        Delete(sub, shift);
-      }
-    }
-  }
-
-  public void Dispose() {}
-
-  //int _index;
-  //ulong _toCellId;
-  //int _enumAddressIx;
-  private CellsStoreEnumerator<object> cellEnum;
-
-  public IEnumerator<ExcelRangeBase> GetEnumerator() {
-    Reset();
-    return this;
-  }
-
-  IEnumerator IEnumerable.GetEnumerator() {
-    Reset();
-    return this;
-  }
-
-  /// <summary>
-  /// The current range when enumerating
-  /// </summary>
-  public ExcelRangeBase Current => new(_worksheet, GetAddress(cellEnum.Row, cellEnum.Column));
-
-  /// <summary>
-  /// The current range when enumerating
-  /// </summary>
-  object IEnumerator.Current =>
-    new ExcelRangeBase(_worksheet, GetAddress(cellEnum.Row, cellEnum.Column));
-
-  private int _enumAddressIx = -1;
-
-  public bool MoveNext() {
-    if (cellEnum.Next()) {
-      return true;
-    }
-    if (_addresses != null) {
-      _enumAddressIx++;
-      if (_enumAddressIx < _addresses.Count) {
-        cellEnum = new(
-            _worksheet._values,
-            _addresses[_enumAddressIx]._fromRow,
-            _addresses[_enumAddressIx]._fromCol,
-            _addresses[_enumAddressIx]._toRow,
-            _addresses[_enumAddressIx]._toCol);
-        return MoveNext();
-      }
-      return false;
-    }
-    return false;
-  }
-
-  public void Reset() {
-    _enumAddressIx = -1;
-    cellEnum = new(_worksheet._values, _fromRow, _fromCol, _toRow, _toCol);
-  }
-
-  //private void GetNextIndexEnum(int fromRow, int fromCol, int toRow, int toCol)
-  //{
-  //    if (_index >= _worksheet._cells.Count) return;
-  //    ExcelCell cell = _worksheet._cells[_index] as ExcelCell;
-  //    while (cell.Column > toCol || cell.Column < fromCol)
-  //    {
-  //        if (cell.Column < fromCol)
-  //        {
-  //            _index = _worksheet._cells.IndexOf(ExcelAddress.GetCellID(_worksheet.SheetID, cell.Row, fromCol));
-  //        }
-  //        else
-  //        {
-  //            _index = _worksheet._cells.IndexOf(ExcelAddress.GetCellID(_worksheet.SheetID, cell.Row + 1, fromCol));
-  //        }
-
-  //        if (_index < 0)
-  //        {
-  //            _index = ~_index;
-  //        }
-  //        if (_index >= _worksheet._cells.Count || _worksheet._cells[_index].RangeID > _toCellId)
-  //        {
-  //            break;
-  //        }
-  //        cell = _worksheet._cells[_index] as ExcelCell;
-  //    }
-  //}
-
-  //private void GetStartIndexEnum(int fromRow, int fromCol, int toRow, int toCol)
-  //{
-  //    _index = _worksheet._cells.IndexOf(ExcelCellBase.GetCellID(_worksheet.SheetID, fromRow, fromCol));
-  //    _toCellId = ExcelCellBase.GetCellID(_worksheet.SheetID, toRow, toCol);
-  //    if (_index < 0)
-  //    {
-  //        _index = ~_index;
-  //    }
-  //    _index--;
-  //}
-}
diff --git a/EPPlus/ExcelRangeCopyOptionFlags.cs b/EPPlus/ExcelRangeCopyOptionFlags.cs
deleted file mode 100644
index 684a49c..0000000
--- a/EPPlus/ExcelRangeCopyOptionFlags.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// Flag enum, specify all flags that you want to exclude from the copy.
-/// </summary>
-[Flags]
-public enum ExcelRangeCopyOptionFlags {
-  /// <summary>
-  /// Exclude formulas from being copied
-  /// </summary>
-  ExcludeFormulas = 0x1,
-}
diff --git a/EPPlus/ExcelRow.cs b/EPPlus/ExcelRow.cs
deleted file mode 100644
index f4336c7..0000000
--- a/EPPlus/ExcelRow.cs
+++ /dev/null
@@ -1,258 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan K�llman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan K�llman		    Initial Release		        2009-10-01
- * Jan K�llman		    License changed GPL-->LGPL 2011-12-27
- *******************************************************************************/
-
-using System;
-using System.Xml;
-using OfficeOpenXml.Style;
-
-namespace OfficeOpenXml;
-
-internal class RowInternal {
-  internal double Height = -1;
-  internal bool Hidden;
-  internal bool Collapsed;
-  internal short OutlineLevel;
-  internal bool PageBreak;
-  internal bool Phonetic;
-  internal bool CustomHeight;
-}
-
-/// <summary>
-/// Represents an individual row in the spreadsheet.
-/// </summary>
-public class ExcelRow : IRangeId {
-  private readonly ExcelWorksheet _worksheet;
-  private readonly XmlElement _rowElement = null;
-
-  /// <summary>
-  /// Internal RowID.
-  /// </summary>
-  [Obsolete]
-  public ulong RowID => GetRowId(_worksheet.SheetID, Row);
-
-  /// <summary>
-  /// Creates a new instance of the ExcelRow class.
-  /// For internal use only!
-  /// </summary>
-  /// <param name="worksheet">The parent worksheet</param>
-  /// <param name="row">The row number</param>
-  internal ExcelRow(ExcelWorksheet worksheet, int row) {
-    _worksheet = worksheet;
-    Row = row;
-  }
-
-  /// <summary>
-  /// Provides access to the node representing the row.
-  /// </summary>
-  internal XmlNode Node => (_rowElement);
-
-  /// <summary>
-  /// Allows the row to be hidden in the worksheet
-  /// </summary>
-  public bool Hidden {
-    get {
-      var r = (RowInternal)_worksheet._values.GetValue(Row, 0);
-      if (r == null) {
-        return false;
-      }
-      return r.Hidden;
-    }
-    set {
-      var r = GetRowInternal();
-      r.Hidden = value;
-    }
-  }
-
-  /// <summary>
-  /// Sets the height of the row
-  /// </summary>
-  public double Height {
-    get {
-      var r = (RowInternal)_worksheet._values.GetValue(Row, 0);
-      if (r == null || r.Height < 0) {
-        return _worksheet.DefaultRowHeight;
-      }
-      return r.Height;
-    }
-    set {
-      var r = GetRowInternal();
-      r.Height = value;
-
-      if (r.Hidden && value != 0) {
-        Hidden = false;
-      }
-      r.CustomHeight = (value != _worksheet.DefaultRowHeight);
-    }
-  }
-
-  /// <summary>
-  /// Set to true if You don't want the row to Autosize
-  /// </summary>
-  public bool CustomHeight {
-    get {
-      var r = (RowInternal)_worksheet._values.GetValue(Row, 0);
-      if (r == null) {
-        return false;
-      }
-      return r.CustomHeight;
-    }
-    set {
-      var r = GetRowInternal();
-      r.CustomHeight = value;
-    }
-  }
-
-  internal string _styleName = "";
-
-  /// <summary>
-  /// Sets the style for the entire column using a style name.
-  /// </summary>
-  public string StyleName {
-    get => _styleName;
-    set {
-      StyleID = _worksheet.Workbook.Styles.GetStyleIdFromName(value);
-      _styleName = value;
-    }
-  }
-
-  /// <summary>
-  /// Sets the style for the entire row using the style ID.
-  /// </summary>
-  public int StyleID {
-    get => _worksheet._styles.GetValue(Row, 0);
-    set => _worksheet._styles.SetValue(Row, 0, value);
-  }
-
-  /// <summary>
-  /// Rownumber
-  /// </summary>
-  public int Row { get; set; }
-
-  /// <summary>
-  /// If outline level is set this tells that the row is collapsed
-  /// </summary>
-  public bool Collapsed {
-    get {
-      var r = (RowInternal)_worksheet._values.GetValue(Row, 0);
-      if (r == null) {
-        return false;
-      }
-      return r.Collapsed;
-    }
-    set {
-      var r = GetRowInternal();
-      r.Collapsed = value;
-    }
-  }
-
-  /// <summary>
-  /// Outline level.
-  /// </summary>
-  public int OutlineLevel {
-    get {
-      var r = (RowInternal)_worksheet._values.GetValue(Row, 0);
-      if (r == null) {
-        return 0;
-      }
-      return r.OutlineLevel;
-    }
-    set {
-      var r = GetRowInternal();
-      r.OutlineLevel = (short)value;
-    }
-  }
-
-  private RowInternal GetRowInternal() {
-    var r = (RowInternal)_worksheet._values.GetValue(Row, 0);
-    if (r == null) {
-      r = new();
-      _worksheet._values.SetValue(Row, 0, r);
-    }
-    return r;
-  }
-
-  /// <summary>
-  /// Show phonetic Information
-  /// </summary>
-  public bool Phonetic {
-    get {
-      var r = (RowInternal)_worksheet._values.GetValue(Row, 0);
-      if (r == null) {
-        return false;
-      }
-      return r.Phonetic;
-    }
-    set {
-      var r = GetRowInternal();
-      r.Phonetic = value;
-    }
-  }
-
-  /// <summary>
-  /// The Style applied to the whole row. Only effekt cells with no individual style set.
-  /// Use ExcelRange object if you want to set specific styles.
-  /// </summary>
-  public ExcelStyle Style =>
-    _worksheet.Workbook.Styles.GetStyleObject(StyleID, _worksheet.PositionID, Row + ":" + Row);
-
-  /// <summary>
-  /// Adds a manual page break after the row.
-  /// </summary>
-  public bool PageBreak {
-    get {
-      var r = (RowInternal)_worksheet._values.GetValue(Row, 0);
-      if (r == null) {
-        return false;
-      }
-      return r.PageBreak;
-    }
-    set {
-      var r = GetRowInternal();
-      r.PageBreak = value;
-    }
-  }
-
-  public bool Merged {
-    get => _worksheet.MergedCells[Row, 0] != null;
-    set => _worksheet.MergedCells.Add(new(Row, 1, Row, ExcelPackage.MaxColumns), true);
-  }
-
-  internal static ulong GetRowId(int sheetId, int row) {
-    return ((ulong)sheetId) + (((ulong)row) << 29);
-  }
-
-  [Obsolete]
-  ulong IRangeId.RangeID {
-    get => RowID;
-    set => Row = ((int)(value >> 29));
-  }
-}
diff --git a/EPPlus/ExcelSheetProtection.cs b/EPPlus/ExcelSheetProtection.cs
deleted file mode 100644
index 0b2cb09..0000000
--- a/EPPlus/ExcelSheetProtection.cs
+++ /dev/null
@@ -1,217 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		    Initial Release		        2010-03-14
- * Jan Källman		    License changed GPL-->LGPL 2011-12-27
- *******************************************************************************/
-
-using System.Collections.Immutable;
-using System.Xml;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// Sheet protection
-///<seealso cref="ExcelEncryption"/>
-///<seealso cref="ExcelProtection"/>
-/// </summary>
-public sealed class ExcelSheetProtection : XmlHelper {
-  protected override ImmutableArray<string> SchemaNodeOrder =>
-    ExcelWorksheet.WorksheetSchemaNodeOrder;
-
-  internal ExcelSheetProtection(XmlNamespaceManager nsm, XmlNode topNode)
-      : base(nsm, topNode) {}
-
-  private const string _isProtectedPath = "d:sheetProtection/@sheet";
-
-  /// <summary>
-  /// If the worksheet is protected.
-  /// </summary>
-  public bool IsProtected {
-    get => GetXmlNodeBool(_isProtectedPath, false);
-    set {
-      SetXmlNodeBool(_isProtectedPath, value, false);
-      if (value) {
-        AllowEditObject = true;
-        AllowEditScenarios = true;
-      } else {
-        DeleteAllNode(_isProtectedPath); //delete the whole sheetprotection node
-      }
-    }
-  }
-
-  private const string _allowSelectLockedCellsPath = "d:sheetProtection/@selectLockedCells";
-
-  /// <summary>
-  /// Allow users to select locked cells
-  /// </summary>
-  public bool AllowSelectLockedCells {
-    get => !GetXmlNodeBool(_allowSelectLockedCellsPath, false);
-    set => SetXmlNodeBool(_allowSelectLockedCellsPath, !value, false);
-  }
-
-  private const string _allowSelectUnlockedCellsPath = "d:sheetProtection/@selectUnlockedCells";
-
-  /// <summary>
-  /// Allow users to select unlocked cells
-  /// </summary>
-  public bool AllowSelectUnlockedCells {
-    get => !GetXmlNodeBool(_allowSelectUnlockedCellsPath, false);
-    set => SetXmlNodeBool(_allowSelectUnlockedCellsPath, !value, false);
-  }
-
-  private const string _allowObjectPath = "d:sheetProtection/@objects";
-
-  /// <summary>
-  /// Allow users to edit objects
-  /// </summary>
-  public bool AllowEditObject {
-    get => !GetXmlNodeBool(_allowObjectPath, false);
-    set => SetXmlNodeBool(_allowObjectPath, !value, false);
-  }
-
-  private const string _allowScenariosPath = "d:sheetProtection/@scenarios";
-
-  /// <summary>
-  /// Allow users to edit senarios
-  /// </summary>
-  public bool AllowEditScenarios {
-    get => !GetXmlNodeBool(_allowScenariosPath, false);
-    set => SetXmlNodeBool(_allowScenariosPath, !value, false);
-  }
-
-  private const string _allowFormatCellsPath = "d:sheetProtection/@formatCells";
-
-  /// <summary>
-  /// Allow users to format cells
-  /// </summary>
-  public bool AllowFormatCells {
-    get => !GetXmlNodeBool(_allowFormatCellsPath, true);
-    set => SetXmlNodeBool(_allowFormatCellsPath, !value, true);
-  }
-
-  private const string _allowFormatColumnsPath = "d:sheetProtection/@formatColumns";
-
-  /// <summary>
-  /// Allow users to Format columns
-  /// </summary>
-  public bool AllowFormatColumns {
-    get => !GetXmlNodeBool(_allowFormatColumnsPath, true);
-    set => SetXmlNodeBool(_allowFormatColumnsPath, !value, true);
-  }
-
-  private const string _allowFormatRowsPath = "d:sheetProtection/@formatRows";
-
-  /// <summary>
-  /// Allow users to Format rows
-  /// </summary>
-  public bool AllowFormatRows {
-    get => !GetXmlNodeBool(_allowFormatRowsPath, true);
-    set => SetXmlNodeBool(_allowFormatRowsPath, !value, true);
-  }
-
-  private const string _allowInsertColumnsPath = "d:sheetProtection/@insertColumns";
-
-  /// <summary>
-  /// Allow users to insert columns
-  /// </summary>
-  public bool AllowInsertColumns {
-    get => !GetXmlNodeBool(_allowInsertColumnsPath, true);
-    set => SetXmlNodeBool(_allowInsertColumnsPath, !value, true);
-  }
-
-  private const string _allowInsertRowsPath = "d:sheetProtection/@insertRows";
-
-  /// <summary>
-  /// Allow users to Format rows
-  /// </summary>
-  public bool AllowInsertRows {
-    get => !GetXmlNodeBool(_allowInsertRowsPath, true);
-    set => SetXmlNodeBool(_allowInsertRowsPath, !value, true);
-  }
-
-  private const string _allowInsertHyperlinksPath = "d:sheetProtection/@insertHyperlinks";
-
-  /// <summary>
-  /// Allow users to insert hyperlinks
-  /// </summary>
-  public bool AllowInsertHyperlinks {
-    get => !GetXmlNodeBool(_allowInsertHyperlinksPath, true);
-    set => SetXmlNodeBool(_allowInsertHyperlinksPath, !value, true);
-  }
-
-  private const string _allowDeleteColumns = "d:sheetProtection/@deleteColumns";
-
-  /// <summary>
-  /// Allow users to delete columns
-  /// </summary>
-  public bool AllowDeleteColumns {
-    get => !GetXmlNodeBool(_allowDeleteColumns, true);
-    set => SetXmlNodeBool(_allowDeleteColumns, !value, true);
-  }
-
-  private const string _allowDeleteRowsPath = "d:sheetProtection/@deleteRows";
-
-  /// <summary>
-  /// Allow users to delete rows
-  /// </summary>
-  public bool AllowDeleteRows {
-    get => !GetXmlNodeBool(_allowDeleteRowsPath, true);
-    set => SetXmlNodeBool(_allowDeleteRowsPath, !value, true);
-  }
-
-  private const string _allowSortPath = "d:sheetProtection/@sort";
-
-  /// <summary>
-  /// Allow users to sort a range
-  /// </summary>
-  public bool AllowSort {
-    get => !GetXmlNodeBool(_allowSortPath, true);
-    set => SetXmlNodeBool(_allowSortPath, !value, true);
-  }
-
-  private const string _allowAutoFilterPath = "d:sheetProtection/@autoFilter";
-
-  /// <summary>
-  /// Allow users to use autofilters
-  /// </summary>
-  public bool AllowAutoFilter {
-    get => !GetXmlNodeBool(_allowAutoFilterPath, true);
-    set => SetXmlNodeBool(_allowAutoFilterPath, !value, true);
-  }
-
-  private const string _allowPivotTablesPath = "d:sheetProtection/@pivotTables";
-
-  /// <summary>
-  /// Allow users to use pivottables
-  /// </summary>
-  public bool AllowPivotTables {
-    get => !GetXmlNodeBool(_allowPivotTablesPath, true);
-    set => SetXmlNodeBool(_allowPivotTablesPath, !value, true);
-  }
-}
diff --git a/EPPlus/ExcelStyleCollection.cs b/EPPlus/ExcelStyleCollection.cs
deleted file mode 100644
index b544547..0000000
--- a/EPPlus/ExcelStyleCollection.cs
+++ /dev/null
@@ -1,124 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		    Initial Release		        2009-10-01
- * Jan Källman		    License changed GPL-->LGPL 2011-12-27
- *******************************************************************************/
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Xml;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// Base collection class for styles.
-/// </summary>
-/// <typeparam name="T">The style type</typeparam>
-public class ExcelStyleCollection<T> : IEnumerable<T> {
-  public ExcelStyleCollection() {
-    _setNextIdManual = false;
-  }
-
-  private readonly bool _setNextIdManual;
-
-  public ExcelStyleCollection(bool setNextIdManual) {
-    _setNextIdManual = setNextIdManual;
-  }
-
-  public XmlNode TopNode { get; set; }
-
-  internal List<T> _list = new();
-  private readonly Dictionary<string, int> _dic = new(StringComparer.InvariantCultureIgnoreCase);
-  internal int NextId;
-
-  public IEnumerator<T> GetEnumerator() {
-    return _list.GetEnumerator();
-  }
-
-  IEnumerator IEnumerable.GetEnumerator() {
-    return _list.GetEnumerator();
-  }
-
-  public T this[int positionId] => _list[positionId];
-
-  public int Count => _list.Count;
-
-  //internal int Add(T item)
-  //{
-  //    _list.Add(item);
-  //    if (_setNextIdManual) NextId++;
-  //    return _list.Count-1;
-  //}
-  internal int Add(string key, T item) {
-    _list.Add(item);
-    if (!_dic.ContainsKey(key.ToLower(CultureInfo.InvariantCulture))) {
-      _dic.Add(key.ToLower(CultureInfo.InvariantCulture), _list.Count - 1);
-    }
-    if (_setNextIdManual) {
-      NextId++;
-    }
-    return _list.Count - 1;
-  }
-
-  /// <summary>
-  /// Finds the key
-  /// </summary>
-  /// <param name="key">the key to be found</param>
-  /// <param name="obj">The found object.</param>
-  /// <returns>True if found</returns>
-  internal bool FindById(string key, ref T obj) {
-    if (_dic.ContainsKey(key)) {
-      obj = _list[_dic[key.ToLower(CultureInfo.InvariantCulture)]];
-      return true;
-    }
-    return false;
-  }
-
-  /// <summary>
-  /// Find Index
-  /// </summary>
-  /// <param name="key"></param>
-  /// <returns></returns>
-  internal int FindIndexById(string key) {
-    if (_dic.ContainsKey(key)) {
-      return _dic[key];
-    }
-    return int.MinValue;
-  }
-
-  internal bool ExistsKey(string key) {
-    return _dic.ContainsKey(key);
-  }
-
-  internal void Sort(Comparison<T> c) {
-    _list.Sort(c);
-  }
-}
diff --git a/EPPlus/ExcelStyles.cs b/EPPlus/ExcelStyles.cs
deleted file mode 100644
index 6bb75ff..0000000
--- a/EPPlus/ExcelStyles.cs
+++ /dev/null
@@ -1,874 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan K�llman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan K�llman		    Initial Release		        2009-10-01
- * Jan K�llman		    License changed GPL-->LGPL 2011-12-27
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Linq;
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting;
-using OfficeOpenXml.Style;
-using OfficeOpenXml.Style.Dxf;
-using OfficeOpenXml.Style.XmlAccess;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// Containts all shared cell styles for a workbook
-/// </summary>
-public sealed class ExcelStyles : XmlHelper {
-  private const string _numberFormatsPath = "d:styleSheet/d:numFmts";
-  private const string _fontsPath = "d:styleSheet/d:fonts";
-  private const string _fillsPath = "d:styleSheet/d:fills";
-  private const string _bordersPath = "d:styleSheet/d:borders";
-  private const string _cellStyleXfsPath = "d:styleSheet/d:cellStyleXfs";
-  private const string _cellXfsPath = "d:styleSheet/d:cellXfs";
-  private const string _cellStylesPath = "d:styleSheet/d:cellStyles";
-  private const string _dxfsPath = "d:styleSheet/d:dxfs";
-
-  //internal Dictionary<int, ExcelXfs> Styles = new Dictionary<int, ExcelXfs>();
-  private readonly XmlDocument _styleXml;
-  private readonly ExcelWorkbook _wb;
-  private readonly XmlNamespaceManager _nameSpaceManager;
-  internal int _nextDfxNumFmtID = 164;
-
-  protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
-    "numFmts",
-    "fonts",
-    "fills",
-    "borders",
-    "cellStyleXfs",
-    "cellXfs",
-    "cellStyles",
-    "dxfs",
-  ];
-
-  internal ExcelStyles(XmlNamespaceManager nameSpaceManager, XmlDocument xml, ExcelWorkbook wb)
-      : base(nameSpaceManager, xml) {
-    _styleXml = xml;
-    _wb = wb;
-    _nameSpaceManager = nameSpaceManager;
-    LoadFromDocument();
-  }
-
-  /// <summary>
-  /// Loads the style XML to memory
-  /// </summary>
-  private void LoadFromDocument() {
-    //NumberFormats
-    ExcelNumberFormatXml.AddBuildIn(NameSpaceManager, NumberFormats);
-    XmlNode numNode = _styleXml.SelectSingleNode(_numberFormatsPath, _nameSpaceManager);
-    if (numNode != null) {
-      foreach (XmlNode n in numNode) {
-        ExcelNumberFormatXml nf = new ExcelNumberFormatXml(_nameSpaceManager, n);
-        NumberFormats.Add(nf.Id, nf);
-        if (nf.NumFmtId >= NumberFormats.NextId) {
-          NumberFormats.NextId = nf.NumFmtId + 1;
-        }
-      }
-    }
-
-    //Fonts
-    XmlNode fontNode = _styleXml.SelectSingleNode(_fontsPath, _nameSpaceManager);
-    foreach (XmlNode n in fontNode) {
-      ExcelFontXml f = new ExcelFontXml(_nameSpaceManager, n);
-      Fonts.Add(f.Id, f);
-    }
-
-    //Fills
-    XmlNode fillNode = _styleXml.SelectSingleNode(_fillsPath, _nameSpaceManager);
-    foreach (XmlNode n in fillNode) {
-      ExcelFillXml f;
-      if (n.FirstChild != null && n.FirstChild.LocalName == "gradientFill") {
-        f = new ExcelGradientFillXml(_nameSpaceManager, n);
-      } else {
-        f = new(_nameSpaceManager, n);
-      }
-      Fills.Add(f.Id, f);
-    }
-
-    //Borders
-    XmlNode borderNode = _styleXml.SelectSingleNode(_bordersPath, _nameSpaceManager);
-    foreach (XmlNode n in borderNode) {
-      ExcelBorderXml b = new ExcelBorderXml(_nameSpaceManager, n);
-      Borders.Add(b.Id, b);
-    }
-
-    //cellStyleXfs
-    XmlNode styleXfsNode = _styleXml.SelectSingleNode(_cellStyleXfsPath, _nameSpaceManager);
-    if (styleXfsNode != null) {
-      foreach (XmlNode n in styleXfsNode) {
-        ExcelXfs item = new ExcelXfs(_nameSpaceManager, n, this);
-        CellStyleXfs.Add(item.Id, item);
-      }
-    }
-
-    XmlNode styleNode = _styleXml.SelectSingleNode(_cellXfsPath, _nameSpaceManager);
-    for (int i = 0; i < styleNode.ChildNodes.Count; i++) {
-      XmlNode n = styleNode.ChildNodes[i];
-      ExcelXfs item = new ExcelXfs(_nameSpaceManager, n, this);
-      CellXfs.Add(item.Id, item);
-    }
-
-    //cellStyle
-    XmlNode namedStyleNode = _styleXml.SelectSingleNode(_cellStylesPath, _nameSpaceManager);
-    if (namedStyleNode != null) {
-      foreach (XmlNode n in namedStyleNode) {
-        ExcelNamedStyleXml item = new ExcelNamedStyleXml(_nameSpaceManager, n, this);
-        NamedStyles.Add(item.Name, item);
-      }
-    }
-
-    //dxfsPath
-    XmlNode dxfsNode = _styleXml.SelectSingleNode(_dxfsPath, _nameSpaceManager);
-    if (dxfsNode != null) {
-      foreach (XmlNode x in dxfsNode) {
-        ExcelDxfStyleConditionalFormatting item = new ExcelDxfStyleConditionalFormatting(
-            _nameSpaceManager,
-            x,
-            this);
-        Dxfs.Add(item.Id, item);
-      }
-    }
-  }
-
-  internal ExcelStyle GetStyleObject(int id, int positionId, string address) {
-    if (id < 0) {
-      id = 0;
-    }
-    return new(this, PropertyChange, positionId, address, id);
-  }
-
-  /// <summary>
-  /// Handels changes of properties on the style objects
-  /// </summary>
-  /// <param name="sender"></param>
-  /// <param name="e"></param>
-  /// <returns></returns>
-  internal int PropertyChange(StyleBase sender, StyleChangeEventArgs e) {
-    var address = new ExcelAddressBase(e.Address);
-    var ws = _wb.Worksheets[e.PositionID];
-    Dictionary<int, int> styleCashe = new Dictionary<int, int>();
-    //Set single address
-    SetStyleAddress(sender, e, address, ws, ref styleCashe);
-    if (address.Addresses != null) {
-      //Handle multiaddresses
-      foreach (var innerAddress in address.Addresses) {
-        SetStyleAddress(sender, e, innerAddress, ws, ref styleCashe);
-      }
-    }
-    return 0;
-  }
-
-  private void SetStyleAddress(
-      StyleBase sender,
-      StyleChangeEventArgs e,
-      ExcelAddressBase address,
-      ExcelWorksheet ws,
-      ref Dictionary<int, int> styleCashe) {
-    if (address.Start.Column == 0 || address.Start.Row == 0) {
-      throw (new("error address"));
-    }
-    //Columns
-    if (address.Start.Row == 1 && address.End.Row == ExcelPackage.MaxRows) {
-      ExcelColumn column;
-      int col = address.Start.Column,
-          row = 0;
-      //Get the startcolumn
-      if (!ws._values.Exists(0, address.Start.Column)) {
-        column = ws.Column(address.Start.Column);
-      } else {
-        column = (ExcelColumn)ws._values.GetValue(0, address.Start.Column);
-      }
-
-      while (column.ColumnMin <= address.End.Column) {
-        if (column.ColumnMax > address.End.Column) {
-          var newCol = ws.CopyColumn(column, address.End.Column + 1, column.ColumnMax);
-          column.ColumnMax = address.End.Column;
-        }
-        var s = ws._styles.GetValue(0, column.ColumnMin);
-        if (styleCashe.ContainsKey(s)) {
-          ws.SetStyle(0, column.ColumnMin, styleCashe[s]);
-        } else {
-          ExcelXfs st = CellXfs[s];
-          int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
-          styleCashe.Add(s, newId);
-          ws.SetStyle(0, column.ColumnMin, newId);
-        }
-
-        //index++;
-
-        if (!ws._values.NextCell(ref row, ref col) || row > 0) {
-          column._columnMax = address.End.Column;
-          break;
-        }
-        column = (ws._values.GetValue(0, col) as ExcelColumn);
-      }
-
-      if (column._columnMax < address.End.Column) {
-        var newCol = ws.Column(column._columnMax + 1);
-        newCol._columnMax = address.End.Column;
-
-        var s = ws._styles.GetValue(0, column.ColumnMin);
-        if (styleCashe.ContainsKey(s)) {
-          ws.SetStyle(0, column.ColumnMin, styleCashe[s]);
-        } else {
-          ExcelXfs st = CellXfs[s];
-          int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
-          styleCashe.Add(s, newId);
-          ws.SetStyle(0, column.ColumnMin, newId);
-        }
-
-        column._columnMax = address.End.Column;
-      }
-
-      //Set for individual cells in the span. We loop all cells here since the cells are sorted with columns first.
-      var cse = new CellsStoreEnumerator<int>(
-          ws._styles,
-          1,
-          address._fromCol,
-          address._toRow,
-          address._toCol);
-      while (cse.Next()) {
-        if (cse.Column >= address.Start.Column && cse.Column <= address.End.Column) {
-          if (styleCashe.ContainsKey(cse.Value)) {
-            ws.SetStyle(cse.Row, cse.Column, styleCashe[cse.Value]);
-          } else {
-            ExcelXfs st = CellXfs[cse.Value];
-            int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
-            styleCashe.Add(cse.Value, newId);
-            cse.Value = newId;
-            //ws.SetStyle(cse.Row, cse.Column, newId);
-          }
-        }
-      }
-
-      //Update cells with styled columns
-      cse = new(ws._styles, 1, 0, address._toRow, 0);
-      while (cse.Next()) {
-        for (int c = address._fromRow; c <= address._toCol; c++) {
-          if (!ws._styles.Exists(cse.Row, c)) {
-            if (styleCashe.ContainsKey(cse.Value)) {
-              ws.SetStyle(cse.Row, c, styleCashe[cse.Value]);
-            } else {
-              ExcelXfs st = CellXfs[cse.Value];
-              int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
-              styleCashe.Add(cse.Value, newId);
-              ws.SetStyle(cse.Row, c, newId);
-            }
-          }
-        }
-      }
-    }
-    //Rows
-    else if (address.Start.Column == 1 && address.End.Column == ExcelPackage.MaxColumns) {
-      for (int rowNum = address.Start.Row; rowNum <= address.End.Row; rowNum++) {
-        var s = ws._styles.GetValue(rowNum, 0);
-        if (s == 0) {
-          //iterate all columns and set the row to the style of the last column
-          var cse = new CellsStoreEnumerator<int>(ws._styles, 0, 1, 0, ExcelPackage.MaxColumns);
-          while (cse.Next()) {
-            s = cse.Value;
-            var c = ws._values.GetValue(cse.Row, cse.Column) as ExcelColumn;
-            if (c != null && c.ColumnMax < ExcelPackage.MaxColumns) {
-              for (int col = c.ColumnMin; col < c.ColumnMax; col++) {
-                if (!ws._styles.Exists(rowNum, col)) {
-                  ws._styles.SetValue(rowNum, col, s);
-                }
-              }
-            }
-          }
-          ws.SetStyle(rowNum, 0, s);
-        }
-        if (styleCashe.ContainsKey(s)) {
-          ws.SetStyle(rowNum, 0, styleCashe[s]);
-        } else {
-          ExcelXfs st = CellXfs[s];
-          int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
-          styleCashe.Add(s, newId);
-          ws._styles.SetValue(rowNum, 0, newId);
-          ws.SetStyle(rowNum, 0, newId);
-        }
-      }
-
-      //Update individual cells
-      var cse2 = new CellsStoreEnumerator<int>(
-          ws._styles,
-          address._fromRow,
-          address._fromCol,
-          address._toRow,
-          address._toCol);
-      while (cse2.Next()) {
-        var s = cse2.Value;
-        if (styleCashe.ContainsKey(s)) {
-          ws.SetStyle(cse2.Row, cse2.Column, styleCashe[s]);
-        } else {
-          ExcelXfs st = CellXfs[s];
-          int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
-          styleCashe.Add(s, newId);
-          cse2.Value = newId;
-        }
-      }
-
-      //Update cells with styled rows
-      cse2 = new(ws._styles, 0, 1, 0, address._toCol);
-      while (cse2.Next()) {
-        for (int r = address._fromRow; r <= address._toRow; r++) {
-          if (!ws._styles.Exists(r, cse2.Column)) {
-            var s = cse2.Value;
-            if (styleCashe.ContainsKey(s)) {
-              ws.SetStyle(r, cse2.Column, styleCashe[s]);
-            } else {
-              ExcelXfs st = CellXfs[s];
-              int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
-              styleCashe.Add(s, newId);
-              ws.SetStyle(r, cse2.Column, newId);
-            }
-          }
-        }
-      }
-    } else //Cellrange
-    {
-      for (int col = address.Start.Column; col <= address.End.Column; col++) {
-        for (int row = address.Start.Row; row <= address.End.Row; row++) {
-          var s = GetStyleId(ws, row, col);
-          if (styleCashe.ContainsKey(s)) {
-            ws.SetStyle(row, col, styleCashe[s]);
-          } else {
-            ExcelXfs st = CellXfs[s];
-            int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
-            styleCashe.Add(s, newId);
-            ws.SetStyle(row, col, newId);
-          }
-        }
-      }
-    }
-  }
-
-  internal int GetStyleId(ExcelWorksheet ws, int row, int col) {
-    int v = 0;
-    if (ws._styles.Exists(row, col, ref v)) {
-      return v;
-    }
-    if (ws._styles.Exists(
-        row,
-        0,
-        ref v)) //First Row
-    {
-      return v;
-    } // then column
-    if (ws._styles.Exists(0, col, ref v)) {
-      return v;
-    }
-    int r = 0,
-        c = col;
-    if (ws._values.PrevCell(ref r, ref c)) {
-      var column = ws._values.GetValue(0, c) as ExcelColumn;
-      if (column != null
-          && column.ColumnMax
-              >= col) //Fixes issue 15174
-      {
-        return ws._styles.GetValue(0, c);
-      }
-      return 0;
-    }
-    return 0;
-  }
-
-  /// <summary>
-  /// Handles property changes on Named styles.
-  /// </summary>
-  /// <param name="sender"></param>
-  /// <param name="e"></param>
-  /// <returns></returns>
-  internal int NamedStylePropertyChange(StyleBase sender, StyleChangeEventArgs e) {
-    int index = NamedStyles.FindIndexById(e.Address);
-    if (index >= 0) {
-      int newId = CellStyleXfs[NamedStyles[index].StyleXfId]
-          .GetNewId(CellStyleXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
-      int prevIx = NamedStyles[index].StyleXfId;
-      NamedStyles[index].StyleXfId = newId;
-      NamedStyles[index].Style.Index = newId;
-
-      NamedStyles[index].XfId = int.MinValue;
-      foreach (var style in CellXfs) {
-        if (style.XfId == prevIx) {
-          style.XfId = newId;
-        }
-      }
-    }
-    return 0;
-  }
-
-  public ExcelStyleCollection<ExcelNumberFormatXml> NumberFormats = new();
-  public ExcelStyleCollection<ExcelFontXml> Fonts = new();
-  public ExcelStyleCollection<ExcelFillXml> Fills = new();
-  public ExcelStyleCollection<ExcelBorderXml> Borders = new();
-  public ExcelStyleCollection<ExcelXfs> CellStyleXfs = new();
-  public ExcelStyleCollection<ExcelXfs> CellXfs = new();
-  public ExcelStyleCollection<ExcelNamedStyleXml> NamedStyles = new();
-  public ExcelStyleCollection<ExcelDxfStyleConditionalFormatting> Dxfs = new();
-
-  internal string Id => "";
-
-  public ExcelNamedStyleXml CreateNamedStyle(string name) {
-    return CreateNamedStyle(name, null);
-  }
-
-  public ExcelNamedStyleXml CreateNamedStyle(string name, ExcelStyle template) {
-    if (_wb.Styles.NamedStyles.ExistsKey(name)) {
-      throw new(string.Format("Key {0} already exists in collection", name));
-    }
-
-    ExcelNamedStyleXml style;
-    style = new(NameSpaceManager, this);
-    int xfIdCopy,
-        positionId;
-    ExcelStyles styles;
-    if (template == null) {
-      //                style.Style = new ExcelStyle(this, NamedStylePropertyChange, -1, name, 0);
-      xfIdCopy = 0;
-      positionId = -1;
-      styles = this;
-    } else {
-      if (template.PositionID < 0 && template.Styles == this) {
-        xfIdCopy = template.Index;
-        positionId = template.PositionID;
-        styles = this;
-        //style.Style = new ExcelStyle(this, NamedStylePropertyChange, Template.PositionID, name, Template.Index);
-        //style.StyleXfId = Template.Index;
-      } else {
-        xfIdCopy = template.XfId;
-        positionId = -1;
-        styles = template.Styles;
-      }
-    }
-    //Clone namedstyle
-    int styleXfId = CloneStyle(styles, xfIdCopy, true);
-    //Close cells style
-    CellStyleXfs[styleXfId].XfId = CellStyleXfs.Count - 1;
-    int xfid = CloneStyle(styles, xfIdCopy, false, true); //Always add a new style (We create a new named style here)
-    CellXfs[xfid].XfId = styleXfId;
-    style.Style = new(this, NamedStylePropertyChange, positionId, name, styleXfId);
-    style.StyleXfId = styleXfId;
-
-    style.Name = name;
-    int ix = _wb.Styles.NamedStyles.Add(style.Name, style);
-    style.Style.SetIndex(ix);
-    //style.Style.XfId = ix;
-    return style;
-  }
-
-  public void UpdateXml() {
-    RemoveUnusedStyles();
-
-    //NumberFormat
-    XmlNode nfNode = _styleXml.SelectSingleNode(_numberFormatsPath, _nameSpaceManager);
-    if (nfNode == null) {
-      CreateNode(_numberFormatsPath, true);
-      nfNode = _styleXml.SelectSingleNode(_numberFormatsPath, _nameSpaceManager);
-    } else {
-      nfNode.RemoveAll();
-    }
-
-    int count = 0;
-    int normalIx = NamedStyles.FindIndexById("Normal");
-    if (NamedStyles.Count > 0
-        && normalIx >= 0
-        && NamedStyles[normalIx].Style.Numberformat.NumFmtID >= 164) {
-      ExcelNumberFormatXml nf = NumberFormats[NumberFormats.FindIndexById(
-            NamedStyles[normalIx].Style.Numberformat.Id)];
-      nfNode.AppendChild(
-          nf.CreateXmlNode(_styleXml.CreateElement("numFmt", ExcelPackage._schemaMain)));
-      nf.newID = count++;
-    }
-    foreach (ExcelNumberFormatXml nf in NumberFormats) {
-      if (!nf.BuildIn /*&& nf.newID<0*/) //Buildin formats are not updated.
-      {
-        nfNode.AppendChild(
-            nf.CreateXmlNode(_styleXml.CreateElement("numFmt", ExcelPackage._schemaMain)));
-        nf.newID = count;
-        count++;
-      }
-    }
-    (nfNode as XmlElement).SetAttribute("count", count.ToString());
-
-    //Font
-    count = 0;
-    XmlNode fntNode = _styleXml.SelectSingleNode(_fontsPath, _nameSpaceManager);
-    fntNode.RemoveAll();
-
-    //Normal should be first in the collection
-    if (NamedStyles.Count > 0 && normalIx >= 0 && NamedStyles[normalIx].Style.Font.Index > 0) {
-      ExcelFontXml fnt = Fonts[NamedStyles[normalIx].Style.Font.Index];
-      fntNode.AppendChild(
-          fnt.CreateXmlNode(_styleXml.CreateElement("font", ExcelPackage._schemaMain)));
-      fnt.newID = count++;
-    }
-
-    foreach (ExcelFontXml fnt in Fonts) {
-      if (fnt.useCnt
-          > 0 /* && fnt.newID<0*/) {
-        fntNode.AppendChild(
-            fnt.CreateXmlNode(_styleXml.CreateElement("font", ExcelPackage._schemaMain)));
-        fnt.newID = count;
-        count++;
-      }
-    }
-    (fntNode as XmlElement).SetAttribute("count", count.ToString());
-
-    //Fills
-    count = 0;
-    XmlNode fillsNode = _styleXml.SelectSingleNode(_fillsPath, _nameSpaceManager);
-    fillsNode.RemoveAll();
-    Fills[0].useCnt = 1; //Must exist (none);
-    Fills[1].useCnt = 1; //Must exist (gray125);
-    foreach (ExcelFillXml fill in Fills) {
-      if (fill.useCnt > 0) {
-        fillsNode.AppendChild(
-            fill.CreateXmlNode(_styleXml.CreateElement("fill", ExcelPackage._schemaMain)));
-        fill.newID = count;
-        count++;
-      }
-    }
-
-    (fillsNode as XmlElement).SetAttribute("count", count.ToString());
-
-    //Borders
-    count = 0;
-    XmlNode bordersNode = _styleXml.SelectSingleNode(_bordersPath, _nameSpaceManager);
-    bordersNode.RemoveAll();
-    Borders[0].useCnt = 1; //Must exist blank;
-    foreach (ExcelBorderXml border in Borders) {
-      if (border.useCnt > 0) {
-        bordersNode.AppendChild(
-            border.CreateXmlNode(_styleXml.CreateElement("border", ExcelPackage._schemaMain)));
-        border.newID = count;
-        count++;
-      }
-    }
-    (bordersNode as XmlElement).SetAttribute("count", count.ToString());
-
-    XmlNode styleXfsNode = _styleXml.SelectSingleNode(_cellStyleXfsPath, _nameSpaceManager);
-    if (styleXfsNode == null && NamedStyles.Count > 0) {
-      CreateNode(_cellStyleXfsPath);
-      styleXfsNode = _styleXml.SelectSingleNode(_cellStyleXfsPath, _nameSpaceManager);
-    }
-    if (NamedStyles.Count > 0) {
-      styleXfsNode.RemoveAll();
-    }
-    //NamedStyles
-    count = normalIx > -1 ? 1 : 0; //If we have a normal style, we make sure it's added first.
-
-    XmlNode cellStyleNode = _styleXml.SelectSingleNode(_cellStylesPath, _nameSpaceManager);
-    if (cellStyleNode != null) {
-      cellStyleNode.RemoveAll();
-    }
-    XmlNode cellXfsNode = _styleXml.SelectSingleNode(_cellXfsPath, _nameSpaceManager);
-    cellXfsNode.RemoveAll();
-
-    if (NamedStyles.Count > 0 && normalIx >= 0) {
-      NamedStyles[normalIx].newID = 0;
-      AddNamedStyle(0, styleXfsNode, cellXfsNode, NamedStyles[normalIx]);
-    }
-    foreach (ExcelNamedStyleXml style in NamedStyles) {
-      if (!style.Name.Equals("normal", StringComparison.InvariantCultureIgnoreCase)) {
-        AddNamedStyle(count++, styleXfsNode, cellXfsNode, style);
-      } else {
-        style.newID = 0;
-      }
-      cellStyleNode.AppendChild(
-          style.CreateXmlNode(_styleXml.CreateElement("cellStyle", ExcelPackage._schemaMain)));
-    }
-    if (cellStyleNode != null) {
-      (cellStyleNode as XmlElement).SetAttribute("count", count.ToString());
-    }
-    if (styleXfsNode != null) {
-      (styleXfsNode as XmlElement).SetAttribute("count", count.ToString());
-    }
-
-    //CellStyle
-    int xfix = 0;
-    foreach (ExcelXfs xf in CellXfs) {
-      if (xf.useCnt > 0 && !(normalIx >= 0 && NamedStyles[normalIx].XfId == xfix)) {
-        cellXfsNode.AppendChild(
-            xf.CreateXmlNode(_styleXml.CreateElement("xf", ExcelPackage._schemaMain)));
-        xf.newID = count;
-        count++;
-      }
-      xfix++;
-    }
-    (cellXfsNode as XmlElement).SetAttribute("count", count.ToString());
-
-    //Set dxf styling for conditional Formatting
-    XmlNode dxfsNode = _styleXml.SelectSingleNode(_dxfsPath, _nameSpaceManager);
-    foreach (var ws in _wb.Worksheets) {
-      if (ws is ExcelChartsheet) {
-        continue;
-      }
-      foreach (var cf in ws.ConditionalFormatting) {
-        if (cf.Style.HasValue) {
-          int ix = Dxfs.FindIndexById(cf.Style.Id);
-          if (ix < 0) {
-            ((ExcelConditionalFormattingRule)cf).DxfId = Dxfs.Count;
-            Dxfs.Add(cf.Style.Id, cf.Style);
-            var elem = ((XmlDocument)TopNode).CreateElement("d", "dxf", ExcelPackage._schemaMain);
-            cf.Style.CreateNodes(new XmlHelperInstance(NameSpaceManager, elem), "");
-            dxfsNode.AppendChild(elem);
-          } else {
-            ((ExcelConditionalFormattingRule)cf).DxfId = ix;
-          }
-        }
-      }
-    }
-    if (dxfsNode != null) {
-      (dxfsNode as XmlElement).SetAttribute("count", Dxfs.Count.ToString());
-    }
-  }
-
-  private void AddNamedStyle(
-      int id,
-      XmlNode styleXfsNode,
-      XmlNode cellXfsNode,
-      ExcelNamedStyleXml style) {
-    var styleXfs = CellStyleXfs[style.StyleXfId];
-    styleXfsNode.AppendChild(
-        styleXfs.CreateXmlNode(_styleXml.CreateElement("xf", ExcelPackage._schemaMain), true));
-    styleXfs.newID = id;
-    styleXfs.XfId = style.StyleXfId;
-
-    var ix = CellXfs.FindIndexById(styleXfs.Id);
-    if (ix < 0) {
-      cellXfsNode.AppendChild(
-          styleXfs.CreateXmlNode(_styleXml.CreateElement("xf", ExcelPackage._schemaMain)));
-    } else {
-      if (id < 0) {
-        CellXfs[ix].XfId = id;
-      }
-      cellXfsNode.AppendChild(
-          CellXfs[ix].CreateXmlNode(_styleXml.CreateElement("xf", ExcelPackage._schemaMain)));
-      CellXfs[ix].useCnt = 0;
-      CellXfs[ix].newID = id;
-    }
-
-    if (style.XfId >= 0) {
-      style.XfId = CellXfs[style.XfId].newID;
-    } else {
-      style.XfId = 0;
-    }
-  }
-
-  private void RemoveUnusedStyles() {
-    CellXfs[0].useCnt = 1; //First item is allways used.
-    foreach (ExcelWorksheet sheet in _wb.Worksheets) {
-      var cse = new CellsStoreEnumerator<int>(sheet._styles);
-      while (cse.Next()) {
-        var v = cse.Value;
-        if (v >= 0) {
-          CellXfs[v].useCnt++;
-        }
-      }
-    }
-    foreach (ExcelNamedStyleXml ns in NamedStyles) {
-      CellStyleXfs[ns.StyleXfId].useCnt++;
-    }
-
-    foreach (ExcelXfs xf in CellXfs) {
-      if (xf.useCnt > 0) {
-        if (xf.FontId >= 0) {
-          Fonts[xf.FontId].useCnt++;
-        }
-        if (xf.FillId >= 0) {
-          Fills[xf.FillId].useCnt++;
-        }
-        if (xf.BorderId >= 0) {
-          Borders[xf.BorderId].useCnt++;
-        }
-      }
-    }
-    foreach (ExcelXfs xf in CellStyleXfs) {
-      if (xf.useCnt > 0) {
-        if (xf.FontId >= 0) {
-          Fonts[xf.FontId].useCnt++;
-        }
-        if (xf.FillId >= 0) {
-          Fills[xf.FillId].useCnt++;
-        }
-        if (xf.BorderId >= 0) {
-          Borders[xf.BorderId].useCnt++;
-        }
-      }
-    }
-  }
-
-  internal int GetStyleIdFromName(string name) {
-    int i = NamedStyles.FindIndexById(name);
-    if (i >= 0) {
-      int id = NamedStyles[i].XfId;
-      if (id < 0) {
-        int styleXfId = NamedStyles[i].StyleXfId;
-        ExcelXfs newStyle = CellStyleXfs[styleXfId].Copy();
-        newStyle.XfId = styleXfId;
-        id = CellXfs.FindIndexById(newStyle.Id);
-        if (id < 0) {
-          id = CellXfs.Add(newStyle.Id, newStyle);
-        }
-        NamedStyles[i].XfId = id;
-      }
-      return id;
-    }
-    return 0;
-    //throw(new Exception("Named style does not exist"));
-  }
-
-  private string GetXmlNode(XmlNode node) {
-    if (node == null) {
-      return "";
-    }
-    if (node.Value != null) {
-      return node.Value;
-    }
-    return "";
-  }
-
-  internal int CloneStyle(ExcelStyles style, int styleId) {
-    return CloneStyle(style, styleId, false, false);
-  }
-
-  internal int CloneStyle(ExcelStyles style, int styleId, bool isNamedStyle) {
-    return CloneStyle(style, styleId, isNamedStyle, false);
-  }
-
-  internal int CloneStyle(ExcelStyles style, int styleId, bool isNamedStyle, bool allwaysAdd) {
-    var xfs = isNamedStyle ? style.CellStyleXfs[styleId] : style.CellXfs[styleId];
-    ExcelXfs newXfs = xfs.Copy(this);
-    //Numberformat
-    if (xfs.NumberFormatId > 0) {
-      //rake36: Two problems here...
-      //rake36:  1. the first time through when format stays equal to String.Empty, it adds a string.empty to the list of Number Formats
-      //rake36:  2. when adding a second sheet, if the numberformatid == 164, it finds the 164 added by previous sheets but was using the array index
-      //rake36:      for the numberformatid
-
-      string format = string.Empty;
-      foreach (var fmt in style.NumberFormats) {
-        if (fmt.NumFmtId == xfs.NumberFormatId) {
-          format = fmt.Format;
-          break;
-        }
-      }
-      //rake36: Don't add another format if it's blank
-      if (!String.IsNullOrEmpty(format)) {
-        int ix = NumberFormats.FindIndexById(format);
-        if (ix < 0) {
-          var item = new ExcelNumberFormatXml(NameSpaceManager) {
-            Format = format,
-            NumFmtId = NumberFormats.NextId++,
-          };
-          NumberFormats.Add(format, item);
-          //rake36: Use the just added format id
-          newXfs.NumberFormatId = item.NumFmtId;
-        } else {
-          //rake36: Use the format id defined by the index... not the index itself
-          newXfs.NumberFormatId = NumberFormats[ix].NumFmtId;
-        }
-      }
-    }
-
-    //Font
-    if (xfs.FontId > -1) {
-      int ix = Fonts.FindIndexById(xfs.Font.Id);
-      if (ix < 0) {
-        ExcelFontXml item = style.Fonts[xfs.FontId].Copy();
-        ix = Fonts.Add(xfs.Font.Id, item);
-      }
-      newXfs.FontId = ix;
-    }
-
-    //Border
-    if (xfs.BorderId > -1) {
-      int ix = Borders.FindIndexById(xfs.Border.Id);
-      if (ix < 0) {
-        ExcelBorderXml item = style.Borders[xfs.BorderId].Copy();
-        ix = Borders.Add(xfs.Border.Id, item);
-      }
-      newXfs.BorderId = ix;
-    }
-
-    //Fill
-    if (xfs.FillId > -1) {
-      int ix = Fills.FindIndexById(xfs.Fill.Id);
-      if (ix < 0) {
-        var item = style.Fills[xfs.FillId].Copy();
-        ix = Fills.Add(xfs.Fill.Id, item);
-      }
-      newXfs.FillId = ix;
-    }
-
-    //Named style reference
-    if (xfs.XfId > 0) {
-      var id = style.CellStyleXfs[xfs.XfId].Id;
-      var newId = CellStyleXfs.FindIndexById(id);
-      if (newId >= 0) {
-        newXfs.XfId = newId;
-      } else if (style._wb != _wb
-          && allwaysAdd
-              == false) //Not the same workbook, copy the namedstyle to the workbook or match the id
-      {
-        var nsFind = style.NamedStyles.ToDictionary(d => (d.StyleXfId));
-        if (nsFind.ContainsKey(xfs.XfId)) {
-          var st = nsFind[xfs.XfId];
-          if (NamedStyles.ExistsKey(st.Name)) {
-            newXfs.XfId = NamedStyles.FindIndexById(st.Name);
-          } else {
-            var ns = CreateNamedStyle(st.Name, st.Style);
-            newXfs.XfId = NamedStyles.Count - 1;
-          }
-        }
-      }
-    }
-
-    int index;
-    if (isNamedStyle) {
-      index = CellStyleXfs.Add(newXfs.Id, newXfs);
-    } else {
-      if (allwaysAdd) {
-        index = CellXfs.Add(newXfs.Id, newXfs);
-      } else {
-        index = CellXfs.FindIndexById(newXfs.Id);
-        if (index < 0) {
-          index = CellXfs.Add(newXfs.Id, newXfs);
-        }
-      }
-    }
-    return index;
-  }
-}
diff --git a/EPPlus/ExcelTextFormat.cs b/EPPlus/ExcelTextFormat.cs
deleted file mode 100644
index 8029447..0000000
--- a/EPPlus/ExcelTextFormat.cs
+++ /dev/null
@@ -1,130 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		    Initial Release		        2011-01-01
- * Jan Källman		    License changed GPL-->LGPL 2011-12-27
- *******************************************************************************/
-
-using System.Globalization;
-using System.Text;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// Discribes a column when reading a text using the ExcelRangeBase.LoadFromText method
-/// </summary>
-public enum eDataTypes {
-  /// <summary>
-  /// Let the the import decide.
-  /// </summary>
-  Unknown,
-
-  /// <summary>
-  /// Always a string.
-  /// </summary>
-  String,
-
-  /// <summary>
-  /// Try to convert it to a number. If it fails then add it as a string.
-  /// </summary>
-  Number,
-
-  /// <summary>
-  /// Try to convert it to a date. If it fails then add it as a string.
-  /// </summary>
-  DateTime,
-
-  /// <summary>
-  /// Try to convert it to a number and divide with 100.
-  /// Removes any tailing percent sign (%). If it fails then add it as a string.
-  /// </summary>
-  Percent,
-}
-
-/// <summary>
-/// Describes how to split a CSV text. Used by the ExcelRange.LoadFromText method
-/// </summary>
-public class ExcelTextFormat {
-  /// <summary>
-  /// Describes how to split a CSV text
-  ///
-  /// Default values
-  /// <list>
-  /// <listheader><term>Property</term><description>Value</description></listheader>
-  /// <item><term>Delimiter</term><description>,</description></item>
-  /// <item><term>TextQualifier</term><description>None (\0)</description></item>
-  /// <item><term>EOL</term><description>CRLF</description></item>
-  /// <item><term>Culture</term><description>CultureInfo.InvariantCulture</description></item>
-  /// <item><term>DataTypes</term><description>End of line default CRLF</description></item>
-  /// <item><term>SkipLinesBeginning</term><description>0</description></item>
-  /// <item><term>SkipLinesEnd</term><description>0</description></item>
-  /// <item><term>Encoding</term><description>Encoding.ASCII</description></item>
-  /// </list>
-  /// </summary>
-  public ExcelTextFormat() {}
-
-  /// <summary>
-  /// Delimiter character
-  /// </summary>
-  public char Delimiter { get; set; } = ',';
-
-  /// <summary>
-  /// Text qualifier character
-  /// </summary>
-  public char TextQualifier { get; set; } = '\0';
-
-  /// <summary>
-  /// End of line characters. Default CRLF
-  /// </summary>
-  public string EOL { get; set; } = "\r\n";
-
-  /// <summary>
-  /// Datatypes list for each column (if column is not present Unknown is assumed)
-  /// </summary>
-  public eDataTypes[] DataTypes { get; set; } = null;
-
-  /// <summary>
-  /// Culture used when parsing. Default CultureInfo.InvariantCulture
-  /// </summary>
-  public CultureInfo Culture { get; set; } = CultureInfo.InvariantCulture;
-
-  /// <summary>
-  /// Number of lines skiped in the begining of the file. Default 0.
-  /// </summary>
-  public int SkipLinesBeginning { get; set; } = 0;
-
-  /// <summary>
-  /// Number of lines skiped at the end of the file. Default 0.
-  /// </summary>
-  public int SkipLinesEnd { get; set; } = 0;
-
-  /// <summary>
-  /// Only used when reading files from disk using a FileInfo object. Default AscII
-  /// </summary>
-  public Encoding Encoding { get; set; } = Encoding.ASCII;
-}
diff --git a/EPPlus/ExcelWorkbook.cs b/EPPlus/ExcelWorkbook.cs
deleted file mode 100644
index c581319..0000000
--- a/EPPlus/ExcelWorkbook.cs
+++ /dev/null
@@ -1,785 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		    Initial Release		       2011-01-01
- * Jan Källman		    License changed GPL-->LGPL 2011-12-27
- * Richard Tallent		Fix escaping of quotes					2012-10-31
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Globalization;
-using System.IO;
-using System.Text;
-using System.Xml;
-using OfficeOpenXml.FormulaParsing;
-using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-using OfficeOpenXml.Packaging;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// How the application should calculate formulas in the workbook
-/// </summary>
-public enum ExcelCalcMode {
-  /// <summary>
-  /// Indicates that calculations in the workbook are performed automatically when cell values change.
-  /// The application recalculates those cells that are dependent on other cells that contain changed values.
-  /// This mode of calculation helps to avoid unnecessary calculations.
-  /// </summary>
-  Automatic,
-
-  /// <summary>
-  /// Indicates tables be excluded during automatic calculation
-  /// </summary>
-  AutomaticNoTable,
-
-  /// <summary>
-  /// Indicates that calculations in the workbook be triggered manually by the user.
-  /// </summary>
-  Manual,
-}
-
-/// <summary>
-/// Represents the Excel workbook and provides access to all the
-/// document properties and worksheets within the workbook.
-/// </summary>
-public sealed class ExcelWorkbook : XmlHelper {
-  internal class SharedStringItem {
-    internal int pos;
-    internal string Text;
-    internal bool isRichText;
-  }
-
-  private readonly ExcelPackage _package;
-  private ExcelWorksheets _worksheets;
-  private OfficeProperties _properties;
-
-  private ExcelStyles _styles;
-
-  internal static ImmutableArray<string> WorkbookSchemaNodeOrder = [
-    "fileVersion",
-    "fileSharing",
-    "workbookPr",
-    "workbookProtection",
-    "bookViews",
-    "sheets",
-    "functionGroups",
-    "functionPrototypes",
-    "externalReferences",
-    "definedNames",
-    "calcPr",
-    "oleSize",
-    "customWorkbookViews",
-    "pivotCaches",
-    "smartTagPr",
-    "smartTagTypes",
-    "webPublishing",
-    "fileRecoveryPr",
-  ];
-
-  protected override ImmutableArray<string> SchemaNodeOrder => WorkbookSchemaNodeOrder;
-
-  internal ExcelWorkbook(ExcelPackage package, XmlNamespaceManager namespaceManager)
-      : base(namespaceManager) {
-    _package = package;
-    _names = new(this);
-    _namespaceManager = namespaceManager;
-
-    WorkbookXml = package.GetOrCreateXmlDocument(
-        WorkbookUri,
-        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
-        ExcelPackage._schemaRelationships + "/officeDocument",
-        () => CreateEmptyWorkbookXml(namespaceManager));
-    _stylesXml = package.GetOrCreateXmlDocument(
-        StylesUri,
-        "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
-        ExcelPackage._schemaRelationships + "/styles",
-        CreateEmptyStylesXml);
-
-    TopNode = WorkbookXml.DocumentElement;
-    FullCalcOnLoad = true; //Full calculation on load by default, for both new workbooks and templates.
-
-    GetSharedStrings();
-    GetExternalReferences();
-    GetDefinedNames();
-  }
-
-  private static XmlDocument CreateEmptyWorkbookXml(XmlNamespaceManager namespaceManager) {
-    var result = new XmlDocument(namespaceManager.NameTable);
-    var wbElem = result.CreateElement("workbook", ExcelPackage._schemaMain);
-
-    // Add the relationships namespace
-    wbElem.SetAttribute("xmlns:r", ExcelPackage._schemaRelationships);
-    result.AppendChild(wbElem);
-
-    // Create the bookViews and workbooks element
-    var bookViews = result.CreateElement("bookViews", ExcelPackage._schemaMain);
-    wbElem.AppendChild(bookViews);
-    var workbookView = result.CreateElement("workbookView", ExcelPackage._schemaMain);
-    bookViews.AppendChild(workbookView);
-
-    return result;
-  }
-
-  private static XmlDocument CreateEmptyStylesXml() {
-    StringBuilder xml = new StringBuilder(
-        "<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">");
-    xml.Append("<numFmts />");
-    xml.Append("<fonts count=\"1\"><font><sz val=\"11\" /><name val=\"Calibri\" /></font></fonts>");
-    xml.Append(
-        "<fills><fill><patternFill patternType=\"none\" /></fill><fill><patternFill patternType=\"gray125\" /></fill></fills>");
-    xml.Append(
-        "<borders><border><left /><right /><top /><bottom /><diagonal /></border></borders>");
-    xml.Append("<cellStyleXfs count=\"1\"><xf numFmtId=\"0\" fontId=\"0\" /></cellStyleXfs>");
-    xml.Append("<cellXfs count=\"1\"><xf numFmtId=\"0\" fontId=\"0\" xfId=\"0\" /></cellXfs>");
-    xml.Append("<cellStyles><cellStyle name=\"Normal\" xfId=\"0\" builtinId=\"0\" /></cellStyles>");
-    xml.Append("<dxfs count=\"0\" />");
-    xml.Append("</styleSheet>");
-
-    var result = new XmlDocument();
-    result.LoadXml(xml.ToString());
-    return result;
-  }
-
-  internal readonly Dictionary<string, SharedStringItem> _sharedStrings = new(); //Used when reading cells.
-  internal List<SharedStringItem> _sharedStringsList = new(); //Used when reading cells.
-  internal ExcelNamedRangeCollection _names;
-  internal int _nextTableID = int.MinValue;
-  internal int _nextPivotTableID = int.MinValue;
-  private readonly XmlNamespaceManager _namespaceManager;
-  private FormulaParser _formulaParser;
-  private FormulaParserManager _parserManager;
-  internal CellStore<List<Token>> _formulaTokens;
-
-  /// <summary>
-  /// Read shared strings to list
-  /// </summary>
-  private void GetSharedStrings() {
-    if (_package.Package.PartExists(SharedStringsUri)) {
-      var xml = _package.GetXmlDocument(SharedStringsUri);
-      XmlNodeList nl = xml.SelectNodes("//d:sst/d:si", NameSpaceManager);
-      _sharedStringsList = new();
-      if (nl != null) {
-        foreach (XmlNode node in nl) {
-          XmlNode n = node.SelectSingleNode("d:t", NameSpaceManager);
-          if (n != null) {
-            _sharedStringsList.Add(
-                new() {
-                  Text = ConvertUtil.ExcelDecodeString(n.InnerText),
-                });
-          } else {
-            _sharedStringsList.Add(
-                new() {
-                  Text = node.InnerXml,
-                  isRichText = true,
-                });
-          }
-        }
-      }
-      //Delete the shared string part, it will be recreated when the package is saved.
-      foreach (var rel in Part.GetRelationships()) {
-        if (rel.TargetUri.OriginalString.EndsWith(
-            "sharedstrings.xml",
-            StringComparison.InvariantCultureIgnoreCase)) {
-          Part.DeleteRelationship(rel.Id);
-          break;
-        }
-      }
-      _package.Package.DeletePart(SharedStringsUri); //Remove the part, it is recreated when saved.
-    }
-  }
-
-  internal void GetDefinedNames() {
-    XmlNodeList nl = WorkbookXml.SelectNodes("//d:definedNames/d:definedName", NameSpaceManager);
-    if (nl != null) {
-      foreach (XmlElement elem in nl) {
-        string fullAddress = elem.InnerText;
-
-        ExcelWorksheet nameWorksheet;
-        if (!int.TryParse(elem.GetAttribute("localSheetId"), out var localSheetId)) {
-          localSheetId = -1;
-          nameWorksheet = null;
-        } else {
-          nameWorksheet = Worksheets[localSheetId + 1];
-        }
-        var addressType = ExcelAddressBase.IsValid(fullAddress);
-        ExcelRangeBase range;
-        ExcelNamedRange namedRange;
-
-        if (fullAddress.IndexOf("[") == 0) {
-          int start = fullAddress.IndexOf("[");
-          int end = fullAddress.IndexOf("]", start);
-          if (start >= 0 && end >= 0) {
-            string externalIndex = fullAddress.Substring(start + 1, end - start - 1);
-            if (int.TryParse(externalIndex, out var index)) {
-              if (index > 0 && index <= _externalReferences.Count) {
-                fullAddress =
-                    fullAddress.Substring(0, start)
-                        + "["
-                        + _externalReferences[index - 1]
-                        + "]"
-                        + fullAddress.Substring(end + 1);
-              }
-            }
-          }
-        }
-
-        if (addressType == ExcelAddressBase.AddressType.Invalid
-            || addressType == ExcelAddressBase.AddressType.InternalName
-            || addressType == ExcelAddressBase.AddressType.ExternalName
-            || addressType == ExcelAddressBase.AddressType.Formula
-            || addressType
-                == ExcelAddressBase
-                    .AddressType
-                    .ExternalAddress) //A value or a formula
-        {
-          range = new(this, nameWorksheet, elem.GetAttribute("name"), true);
-          if (nameWorksheet == null) {
-            namedRange = _names.Add(elem.GetAttribute("name"), range);
-          } else {
-            namedRange = nameWorksheet.Names.Add(elem.GetAttribute("name"), range);
-          }
-
-          if (fullAddress.StartsWith(
-              "\"")) //String value
-          {
-            namedRange.NameValue = fullAddress.Substring(1, fullAddress.Length - 2);
-          } else if (double.TryParse(
-              fullAddress,
-              NumberStyles.Any,
-              CultureInfo.InvariantCulture,
-              out var value)) {
-            namedRange.NameValue = value;
-          } else {
-            //if (addressType == ExcelAddressBase.AddressType.ExternalAddress || addressType == ExcelAddressBase.AddressType.ExternalName)
-            //{
-            //    var r = new ExcelAddress(fullAddress);
-            //    namedRange.NameFormula = '\'[' + r._wb
-            //}
-            //else
-            //{
-            namedRange.NameFormula = fullAddress;
-            //}
-          }
-        } else {
-          ExcelAddress addr = new ExcelAddress(fullAddress, this, null);
-          if (localSheetId > -1) {
-            if (string.IsNullOrEmpty(addr._ws)) {
-              namedRange = Worksheets[localSheetId + 1].Names.Add(
-                  elem.GetAttribute("name"),
-                  new(this, Worksheets[localSheetId + 1], fullAddress, false));
-            } else {
-              namedRange = Worksheets[localSheetId + 1].Names.Add(
-                  elem.GetAttribute("name"),
-                  new(this, Worksheets[addr._ws], fullAddress, false));
-            }
-          } else {
-            var ws = Worksheets[addr._ws];
-            namedRange = _names.Add(elem.GetAttribute("name"), new(this, ws, fullAddress, false));
-          }
-        }
-        if (elem.GetAttribute("hidden") == "1" && namedRange != null) {
-          namedRange.IsNameHidden = true;
-        }
-        if (!string.IsNullOrEmpty(elem.GetAttribute("comment"))) {
-          namedRange.NameComment = elem.GetAttribute("comment");
-        }
-      }
-    }
-  }
-
-  /// <summary>
-  /// Provides access to all the worksheets in the workbook.
-  /// </summary>
-  public ExcelWorksheets Worksheets {
-    get {
-      if (_worksheets == null) {
-        var sheetsNode = WorkbookXml.DocumentElement.SelectSingleNode(
-            "d:sheets",
-            _namespaceManager);
-        if (sheetsNode == null) {
-          sheetsNode = CreateNode("d:sheets");
-        }
-
-        _worksheets = new(_package, this, _namespaceManager, sheetsNode);
-      }
-      return (_worksheets);
-    }
-  }
-
-  /// <summary>
-  /// Provides access to named ranges
-  /// </summary>
-  public ExcelNamedRangeCollection Names => _names;
-
-  internal FormulaParser FormulaParser {
-    get {
-      if (_formulaParser == null) {
-        _formulaParser = new(new EpplusExcelDataProvider(this));
-      }
-      return _formulaParser;
-    }
-  }
-
-  public FormulaParserManager FormulaParserManager {
-    get {
-      if (_parserManager == null) {
-        _parserManager = new(FormulaParser);
-      }
-      return _parserManager;
-    }
-  }
-
-  private ExcelProtection _protection;
-
-  /// <summary>
-  /// Access properties to protect or unprotect a workbook
-  /// </summary>
-  public ExcelProtection Protection => _protection ??= new(NameSpaceManager, TopNode);
-
-  private ExcelWorkbookView _view;
-
-  /// <summary>
-  /// Access to workbook view properties
-  /// </summary>
-  public ExcelWorkbookView View {
-    get {
-      if (_view == null) {
-        _view = new(NameSpaceManager, TopNode, this);
-      }
-      return _view;
-    }
-  }
-
-  /// <summary>
-  /// URI to the workbook inside the package
-  /// </summary>
-  internal static Uri WorkbookUri { get; } = new("/xl/workbook.xml", UriKind.Relative);
-
-  /// <summary>
-  /// URI to the styles inside the package
-  /// </summary>
-  private static Uri StylesUri { get; } = new("/xl/styles.xml", UriKind.Relative);
-
-  /// <summary>
-  /// URI to the shared strings inside the package
-  /// </summary>
-  private static Uri SharedStringsUri { get; } = new("/xl/sharedStrings.xml", UriKind.Relative);
-
-  /// <summary>
-  /// Returns a reference to the workbook's part within the package
-  /// </summary>
-  internal ZipPackagePart Part => (_package.Package.GetPart(WorkbookUri));
-
-  /// <summary>
-  /// Provides access to the XML data representing the workbook in the package.
-  /// </summary>
-  internal XmlDocument WorkbookXml { get; }
-
-  private const string _codeModuleNamePath = "d:workbookPr/@codeName";
-
-  internal string CodeModuleName {
-    get => GetXmlNodeString(_codeModuleNamePath);
-    set => SetXmlNodeString(_codeModuleNamePath, value);
-  }
-
-  internal void CodeNameChange(string value) {
-    CodeModuleName = value;
-  }
-
-  private const string _date1904Path = "d:workbookPr/@date1904";
-  internal const double _date1904Offset = 365.5 * 4; // offset to fix 1900 and 1904 differences, 4 OLE years
-
-  /// <summary>
-  /// The date systems used by Microsoft Excel can be based on one of two different dates. By default, a serial number of 1 in Microsoft Excel represents January 1, 1900.
-  /// The default for the serial number 1 can be changed to represent January 2, 1904.
-  /// This option was included in Microsoft Excel for Windows to make it compatible with Excel for the Macintosh, which defaults to January 2, 1904.
-  /// </summary>
-  public bool Date1904 {
-    get => GetXmlNodeBool(_date1904Path, false);
-    set {
-      if (Date1904 != value) {
-        // Like Excel when the option it's changed update it all cells with Date format
-        foreach (var item in Worksheets) {
-          item.UpdateCellsWithDate1904Setting();
-        }
-      }
-
-      SetXmlNodeBool(_date1904Path, value, false);
-    }
-  }
-
-  private readonly XmlDocument _stylesXml;
-
-  /// <summary>
-  /// Package styles collection. Used internally to access style data.
-  /// </summary>
-  public ExcelStyles Styles {
-    get {
-      if (_styles == null) {
-        _styles = new(NameSpaceManager, _stylesXml, this);
-      }
-      return _styles;
-    }
-  }
-
-  /// <summary>
-  /// The office document properties
-  /// </summary>
-  public OfficeProperties Properties {
-    get {
-      if (_properties == null) {
-        //  Create a NamespaceManager to handle the default namespace,
-        //  and create a prefix for the default namespace:
-        _properties = new(_package, NameSpaceManager);
-      }
-      return _properties;
-    }
-  }
-
-  private readonly string _calcModePath = "d:calcPr/@calcMode";
-
-  /// <summary>
-  /// Calculation mode for the workbook.
-  /// </summary>
-  public ExcelCalcMode CalcMode {
-    get {
-      string calcMode = GetXmlNodeString(_calcModePath);
-      switch (calcMode) {
-        case "autoNoTable":
-          return ExcelCalcMode.AutomaticNoTable;
-        case "manual":
-          return ExcelCalcMode.Manual;
-        default:
-          return ExcelCalcMode.Automatic;
-      }
-    }
-    set {
-      switch (value) {
-        case ExcelCalcMode.AutomaticNoTable:
-          SetXmlNodeString(_calcModePath, "autoNoTable");
-          break;
-        case ExcelCalcMode.Manual:
-          SetXmlNodeString(_calcModePath, "manual");
-          break;
-        default:
-          SetXmlNodeString(_calcModePath, "auto");
-          break;
-      }
-    }
-  }
-
-  private const string _fullCalcOnLoadPath = "d:calcPr/@fullCalcOnLoad";
-
-  /// <summary>
-  /// Should Excel do a full calculation after the workbook has been loaded?
-  /// <remarks>This property is always true for both new workbooks and loaded templates(on load). If this is not the wanted behavior set this property to false.</remarks>
-  /// </summary>
-  public bool FullCalcOnLoad {
-    get => GetXmlNodeBool(_fullCalcOnLoadPath);
-    set => SetXmlNodeBool(_fullCalcOnLoadPath, value);
-  }
-
-  internal void Save() {
-    if (Worksheets.Count == 0) {
-      throw new InvalidOperationException("The workbook must contain at least one worksheet");
-    }
-
-    DeleteCalcChain();
-    UpdateDefinedNamesXml();
-
-    // save the style sheet
-    Styles.UpdateXml();
-
-    // save all the open worksheets
-    var isProtected = Protection.LockWindows || Protection.LockStructure;
-    foreach (ExcelWorksheet worksheet in Worksheets) {
-      if (isProtected && Protection.LockWindows) {
-        worksheet.View.WindowProtection = true;
-      }
-      worksheet.Save();
-    }
-
-    _package.Package.CreatePart(
-        SharedStringsUri,
-        ExcelPackage._contentTypeSharedString,
-        SaveSharedStringHandler);
-    Part.CreateRelationship(
-        UriHelper.GetRelativeUri(WorkbookUri, SharedStringsUri),
-        TargetMode.Internal,
-        ExcelPackage._schemaRelationships + "/sharedStrings");
-
-    // Data validation
-    ValidateDataValidations();
-  }
-
-  private void DeleteCalcChain() {
-    //Remove the calc chain if it exists.
-    Uri uriCalcChain = new Uri("/xl/calcChain.xml", UriKind.Relative);
-    if (_package.Package.PartExists(uriCalcChain)) {
-      Uri calcChain = new Uri("calcChain.xml", UriKind.Relative);
-      foreach (var relationship in Part.GetRelationships()) {
-        if (relationship.TargetUri == calcChain) {
-          Part.DeleteRelationship(relationship.Id);
-          break;
-        }
-      }
-      // delete the calcChain part
-      _package.Package.DeletePart(uriCalcChain);
-    }
-  }
-
-  private void ValidateDataValidations() {
-    foreach (var sheet in Worksheets) {
-      if (!(sheet is ExcelChartsheet)) {
-        sheet.DataValidations.ValidateAll();
-      }
-    }
-  }
-
-  private void SaveSharedStringHandler(StreamWriter sw) {
-    var cache = new StringBuilder();
-    cache.AppendFormat(
-        "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><sst xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" count=\"{0}\" uniqueCount=\"{0}\">",
-        _sharedStrings.Count);
-    foreach (string t in _sharedStrings.Keys) {
-      SharedStringItem ssi = _sharedStrings[t];
-      if (ssi.isRichText) {
-        cache.Append("<si>");
-        ConvertUtil.ExcelEncodeString(cache, t);
-        cache.Append("</si>");
-      } else {
-        if (t.Length > 0
-            && (t[0] == ' '
-                    || t[t.Length - 1] == ' '
-                    || t.Contains("  ")
-                    || t.Contains("\t")
-                    || t.Contains("\n")
-                    || t.Contains(
-                        "\n"))) //Fixes issue 14849
-        {
-          cache.Append("<si><t xml:space=\"preserve\">");
-        } else {
-          cache.Append("<si><t>");
-        }
-        ConvertUtil.ExcelEncodeString(cache, ConvertUtil.ExcelEscapeString(t));
-        cache.Append("</t></si>");
-      }
-      if (cache.Length > 0x600000) {
-        sw.Write(cache.ToString());
-        cache = new();
-      }
-    }
-    cache.Append("</sst>");
-    sw.Write(cache.ToString());
-    sw.Flush();
-    Part.CreateRelationship(
-        UriHelper.GetRelativeUri(WorkbookUri, SharedStringsUri),
-        TargetMode.Internal,
-        ExcelPackage._schemaRelationships + "/sharedStrings");
-  }
-
-  private void UpdateDefinedNamesXml() {
-    try {
-      XmlNode top = WorkbookXml.SelectSingleNode("//d:definedNames", NameSpaceManager);
-      if (!ExistsNames()) {
-        if (top != null) {
-          TopNode.RemoveChild(top);
-        }
-        return;
-      }
-      if (top == null) {
-        CreateNode("d:definedNames");
-        top = WorkbookXml.SelectSingleNode("//d:definedNames", NameSpaceManager);
-      } else {
-        top.RemoveAll();
-      }
-      foreach (ExcelNamedRange name in _names) {
-        XmlElement elem = WorkbookXml.CreateElement("definedName", ExcelPackage._schemaMain);
-        top.AppendChild(elem);
-        elem.SetAttribute("name", name.Name);
-        if (name.IsNameHidden) {
-          elem.SetAttribute("hidden", "1");
-        }
-        if (!string.IsNullOrEmpty(name.NameComment)) {
-          elem.SetAttribute("comment", name.NameComment);
-        }
-        SetNameElement(name, elem);
-      }
-      foreach (ExcelWorksheet ws in _worksheets) {
-        if (!(ws is ExcelChartsheet)) {
-          foreach (ExcelNamedRange name in ws.Names) {
-            XmlElement elem = WorkbookXml.CreateElement("definedName", ExcelPackage._schemaMain);
-            top.AppendChild(elem);
-            elem.SetAttribute("name", name.Name);
-            elem.SetAttribute("localSheetId", name.LocalSheetId.ToString());
-            if (name.IsNameHidden) {
-              elem.SetAttribute("hidden", "1");
-            }
-            if (!string.IsNullOrEmpty(name.NameComment)) {
-              elem.SetAttribute("comment", name.NameComment);
-            }
-            SetNameElement(name, elem);
-          }
-        }
-      }
-    } catch (Exception ex) {
-      throw new("Internal error updating named ranges ", ex);
-    }
-  }
-
-  private void SetNameElement(ExcelNamedRange name, XmlElement elem) {
-    if (name.IsName) {
-      if (string.IsNullOrEmpty(name.NameFormula)) {
-        if ((name.NameValue.GetType().IsPrimitive
-                    || name.NameValue is double
-                    || name.NameValue is decimal)) {
-          elem.InnerText = Convert
-              .ToDouble(name.NameValue, CultureInfo.InvariantCulture)
-              .ToString("R15", CultureInfo.InvariantCulture);
-        } else if (name.NameValue is DateTime time) {
-          elem.InnerText = time.ToOADate().ToString(CultureInfo.InvariantCulture);
-        } else {
-          elem.InnerText = "\"" + name.NameValue + "\"";
-        }
-      } else {
-        elem.InnerText = name.NameFormula;
-      }
-    } else {
-      elem.InnerText = name.FullAddressAbsolute;
-    }
-  }
-
-  /// <summary>
-  /// Is their any names in the workbook or in the sheets.
-  /// </summary>
-  /// <returns>?</returns>
-  private bool ExistsNames() {
-    if (_names.Count == 0) {
-      foreach (ExcelWorksheet ws in Worksheets) {
-        if (ws is ExcelChartsheet) {
-          continue;
-        }
-        if (ws.Names.Count > 0) {
-          return true;
-        }
-      }
-    } else {
-      return true;
-    }
-    return false;
-  }
-
-  internal bool ExistsTableName(string name) {
-    foreach (var ws in Worksheets) {
-      if (ws.Tables._tableNames.ContainsKey(name)) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  internal bool ExistsPivotTableName(string name) {
-    foreach (var ws in Worksheets) {
-      if (ws.PivotTables._pivotTableNames.ContainsKey(name)) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  internal void AddPivotTable(string cacheId, Uri defUri) {
-    CreateNode("d:pivotCaches");
-
-    XmlElement item = WorkbookXml.CreateElement("pivotCache", ExcelPackage._schemaMain);
-    item.SetAttribute("cacheId", cacheId);
-    var rel = Part.CreateRelationship(
-        UriHelper.ResolvePartUri(WorkbookUri, defUri),
-        TargetMode.Internal,
-        ExcelPackage._schemaRelationships + "/pivotCacheDefinition");
-    item.SetAttribute("id", ExcelPackage._schemaRelationships, rel.Id);
-
-    var pivotCaches = WorkbookXml.SelectSingleNode("//d:pivotCaches", NameSpaceManager);
-    pivotCaches.AppendChild(item);
-  }
-
-  internal List<string> _externalReferences = new();
-
-  //internal bool _isCalculated=false;
-  internal void GetExternalReferences() {
-    XmlNodeList nl = WorkbookXml.SelectNodes(
-        "//d:externalReferences/d:externalReference",
-        NameSpaceManager);
-    if (nl != null) {
-      foreach (XmlElement elem in nl) {
-        string rId = elem.GetAttribute("r:id");
-        var rel = Part.GetRelationship(rId);
-        var part = _package.Package.GetPart(UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri));
-        XmlDocument xmlExtRef = new XmlDocument();
-        LoadXmlSafe(xmlExtRef, part.GetStream());
-
-        XmlElement book =
-            xmlExtRef.SelectSingleNode("//d:externalBook", NameSpaceManager) as XmlElement;
-        if (book != null) {
-          string rIdExtRef = book.GetAttribute("r:id");
-          var relExtRef = part.GetRelationship(rIdExtRef);
-          if (relExtRef != null) {
-            _externalReferences.Add(relExtRef.TargetUri.OriginalString);
-          }
-        }
-      }
-    }
-  }
-
-  internal void ReadAllTables() {
-    if (_nextTableID > 0) {
-      return;
-    }
-    _nextTableID = 1;
-    _nextPivotTableID = 1;
-    foreach (var ws in Worksheets) {
-      if (!(ws
-                  is ExcelChartsheet)) //Fixes 15273. Chartsheets should be ignored.
-      {
-        foreach (var tbl in ws.Tables) {
-          if (tbl.Id >= _nextTableID) {
-            _nextTableID = tbl.Id + 1;
-          }
-        }
-        foreach (var pt in ws.PivotTables) {
-          if (pt.CacheID >= _nextPivotTableID) {
-            _nextPivotTableID = pt.CacheID + 1;
-          }
-        }
-      }
-    }
-  }
-}
diff --git a/EPPlus/ExcelWorkbookView.cs b/EPPlus/ExcelWorkbookView.cs
deleted file mode 100644
index 26a2430..0000000
--- a/EPPlus/ExcelWorkbookView.cs
+++ /dev/null
@@ -1,162 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		    Initial Release		       2011-11-02
- * Jan Källman		    License changed GPL-->LGPL 2011-12-27
- *******************************************************************************/
-
-using System.Collections.Immutable;
-using System.Globalization;
-using System.Xml;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// Access to workbook view properties
-/// </summary>
-public class ExcelWorkbookView : XmlHelper {
-  protected override ImmutableArray<string> SchemaNodeOrder =>
-    ExcelWorkbook.WorkbookSchemaNodeOrder;
-
-  /// <summary>
-  /// Creates a new ExcelWorkbookView which provides access to all the
-  /// view states of the worksheet.
-  /// </summary>
-  /// <param name="ns"></param>
-  /// <param name="node"></param>
-  /// <param name="wb"></param>
-  internal ExcelWorkbookView(XmlNamespaceManager ns, XmlNode node, ExcelWorkbook wb)
-      : base(ns, node) {}
-
-  private const string _leftPath = "d:bookViews/d:workbookView/@xWindow";
-
-  /// <summary>
-  /// Position of the upper left corner of the workbook window. In twips.
-  /// </summary>
-  public int Left {
-    get => GetXmlNodeInt(_leftPath);
-    internal set => SetXmlNodeString(_leftPath, value.ToString());
-  }
-
-  private const string _topPath = "d:bookViews/d:workbookView/@yWindow";
-
-  /// <summary>
-  /// Position of the upper left corner of the workbook window. In twips.
-  /// </summary>
-  public int Top {
-    get => GetXmlNodeInt(_topPath);
-    internal set => SetXmlNodeString(_topPath, value.ToString());
-  }
-
-  private const string _widthPath = "d:bookViews/d:workbookView/@windowWidth";
-
-  /// <summary>
-  /// Width of the workbook window. In twips.
-  /// </summary>
-  public int Width {
-    get => GetXmlNodeInt(_widthPath);
-    internal set => SetXmlNodeString(_widthPath, value.ToString());
-  }
-
-  private const string _heightPath = "d:bookViews/d:workbookView/@windowHeight";
-
-  /// <summary>
-  /// Height of the workbook window. In twips.
-  /// </summary>
-  public int Height {
-    get => GetXmlNodeInt(_heightPath);
-    internal set => SetXmlNodeString(_heightPath, value.ToString());
-  }
-
-  private const string _minimizedPath = "d:bookViews/d:workbookView/@minimized";
-
-  /// <summary>
-  /// If true the the workbook window is minimized.
-  /// </summary>
-  public bool Minimized {
-    get => GetXmlNodeBool(_minimizedPath);
-    set => SetXmlNodeString(_minimizedPath, value.ToString());
-  }
-
-  private const string _showverticalscrollPath = "d:bookViews/d:workbookView/@showVerticalScroll";
-
-  /// <summary>
-  /// Show the vertical scrollbar
-  /// </summary>
-  public bool ShowVerticalScrollBar {
-    get => GetXmlNodeBool(_showverticalscrollPath, true);
-    set => SetXmlNodeBool(_showverticalscrollPath, value, true);
-  }
-
-  private const string _showhorizontalscrPath = "d:bookViews/d:workbookView/@showHorizontalScroll";
-
-  /// <summary>
-  /// Show the horizontal scrollbar
-  /// </summary>
-  public bool ShowHorizontalScrollBar {
-    get => GetXmlNodeBool(_showhorizontalscrPath, true);
-    set => SetXmlNodeBool(_showhorizontalscrPath, value, true);
-  }
-
-  private const string _showsheettabsPath = "d:bookViews/d:workbookView/@showSheetTabs";
-
-  /// <summary>
-  /// Show the sheet tabs
-  /// </summary>
-  public bool ShowSheetTabs {
-    get => GetXmlNodeBool(_showsheettabsPath, true);
-    set => SetXmlNodeBool(_showsheettabsPath, value, true);
-  }
-
-  /// <summary>
-  /// Set the window position in twips
-  /// </summary>
-  /// <param name="left"></param>
-  /// <param name="top"></param>
-  /// <param name="width"></param>
-  /// <param name="height"></param>
-  public void SetWindowSize(int left, int top, int width, int height) {
-    Left = left;
-    Top = top;
-    Width = width;
-    Height = height;
-  }
-
-  private const string _activetabPath = "d:bookViews/d:workbookView/@activeTab";
-
-  public int ActiveTab {
-    get {
-      var v = GetXmlNodeInt(_activetabPath);
-      if (v < 0) {
-        return 0;
-      }
-      return v;
-    }
-    set => SetXmlNodeString(_activetabPath, value.ToString(CultureInfo.InvariantCulture));
-  }
-}
diff --git a/EPPlus/ExcelWorksheet.cs b/EPPlus/ExcelWorksheet.cs
deleted file mode 100644
index 02fe010..0000000
--- a/EPPlus/ExcelWorksheet.cs
+++ /dev/null
@@ -1,3236 +0,0 @@
-/*******************************************************************************
-* You may amend and distribute as you like, but don't remove this header!
-*
-* EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
-* See http://www.codeplex.com/EPPlus for details.
-*
-* Copyright (C) 2011  Jan Källman
-*
-* This library is free software; you can redistribute it and/or
-* modify it under the terms of the GNU Lesser General Public
-* License as published by the Free Software Foundation; either
-* version 2.1 of the License, or (at your option) any later version.
-
-* This library is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-* See the GNU Lesser General Public License for more details.
-*
-* The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
-* If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
-*
-* All code and executables are provided "as is" with no warranty either express or implied.
-* The author accepts no liability for any damage or loss of business that this product may cause.
-*
-* Code change notes:
-*
-* Author							Change						Date
-* ******************************************************************************
-* Jan Källman		    Initial Release		        2011-11-02
-* Jan Källman          Total rewrite               2010-03-01
-* Jan Källman		    License changed GPL-->LGPL  2011-12-27
-*******************************************************************************/
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.ComponentModel;
-using System.Globalization;
-using System.IO;
-using System.Security;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Xml;
-using OfficeOpenXml.ConditionalFormatting;
-using OfficeOpenXml.DataValidation;
-using OfficeOpenXml.Drawing.Vml;
-using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-using OfficeOpenXml.Packaging;
-using OfficeOpenXml.Style.XmlAccess;
-using OfficeOpenXml.Table;
-using OfficeOpenXml.Table.PivotTable;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// Worksheet hidden enumeration
-/// </summary>
-public enum eWorkSheetHidden {
-  /// <summary>
-  /// The worksheet is visible
-  /// </summary>
-  Visible,
-
-  /// <summary>
-  /// The worksheet is hidden but can be shown by the user via the user interface
-  /// </summary>
-  Hidden,
-
-  /// <summary>
-  /// The worksheet is hidden and cannot be shown by the user via the user interface
-  /// </summary>
-  VeryHidden,
-}
-
-[Flags]
-internal enum CellFlags {
-  //Merged = 0x1,
-  RichText = 0x2,
-  SharedFormula = 0x4,
-  ArrayFormula = 0x8,
-}
-
-/// <summary>
-/// Represents an Excel Chartsheet and provides access to its properties and methods
-/// </summary>
-public class ExcelChartsheet : ExcelWorksheet {
-  public ExcelChartsheet(
-      XmlNamespaceManager ns,
-      ExcelPackage pck,
-      ExcelWorkbook workbook,
-      Uri worksheetUri,
-      string name,
-      int sheetId,
-      int positionId,
-      eWorkSheetHidden hidden)
-      : base(ns, pck, workbook, worksheetUri, name, sheetId, positionId, hidden) {}
-}
-
-/// <summary>
-/// Represents an Excel worksheet and provides access to its properties and methods
-/// </summary>
-public class ExcelWorksheet : XmlHelper, IEqualityComparer<ExcelWorksheet> {
-  internal class Formulas {
-    public Formulas(ISourceCodeTokenizer tokenizer) {
-      _tokenizer = tokenizer;
-    }
-
-    public static string RemoveDummyFunction(string formula) {
-      const string dummyFunctionConcatenate = "\"&\"";
-      const string dummyFunctionPrefix = "IFERROR(__xludf.DUMMYFUNCTION(\"";
-      const string dummyFunctionSuffix = "\"),";
-
-      if (string.IsNullOrEmpty(formula)) {
-        return formula;
-      }
-
-      // Look for Prefix
-      if (!formula.StartsWith(dummyFunctionPrefix)) {
-        return formula;
-      }
-
-      // Look for Suffix
-      int index = formula.LastIndexOf(dummyFunctionSuffix);
-      if (index < 0) {
-        return formula;
-      }
-
-      // Trim Suffix
-      formula = formula.Substring(0, index);
-
-      // Trim Prefix
-      formula = formula.Replace(dummyFunctionPrefix, "");
-
-      // Remove string concatentations from long formulas.
-      // Google break the quoted string into 254 character segments which are concatenated.
-      if (formula.Length >= 254) {
-        formula = formula.Replace(dummyFunctionConcatenate, "");
-      }
-
-      // Replace doubled quotes with single quote
-      formula = formula.Replace("\"\"", "\"");
-
-      // Return formula
-      return formula;
-    }
-
-    private readonly ISourceCodeTokenizer _tokenizer;
-
-    internal int Index { get; set; }
-
-    internal string Address { get; set; }
-
-    internal bool IsArray { get; set; }
-
-    public string Formula { get; set; }
-
-    public int StartRow { get; set; }
-
-    public int StartCol { get; set; }
-
-    private IEnumerable<Token> Tokens { get; set; }
-
-    internal string GetFormula(int row, int column, string worksheet) {
-      if ((StartRow == row && StartCol == column) || IsArray) {
-        return RemoveDummyFunction(Formula);
-      }
-
-      if (Tokens == null) {
-        Tokens = _tokenizer.Tokenize(RemoveDummyFunction(Formula), worksheet);
-      }
-
-      string f = "";
-      foreach (var token in Tokens) {
-        if (token.TokenType == TokenType.ExcelAddress) {
-          var a = new ExcelFormulaAddress(token.Value);
-          f += a.GetOffset(row - StartRow, column - StartCol);
-        } else {
-          f += token.Value;
-        }
-      }
-      return f;
-    }
-  }
-
-  /// <summary>
-  /// Collection containing merged cell addresses
-  /// </summary>
-  public class MergeCellsCollection : IEnumerable<string> {
-    internal MergeCellsCollection() {}
-
-    internal readonly CellStore<int> _cells = new();
-    private readonly List<string> _list = new();
-
-    internal List<string> List => _list;
-
-    public string this[int row, int column] {
-      get {
-        int ix = -1;
-        if (_cells.Exists(row, column, ref ix)
-            && ix >= 0
-            && ix
-                < List.Count) //Fixes issue 15075
-        {
-          return List[ix];
-        }
-        return null;
-      }
-    }
-
-    public string this[int index] => _list[index];
-
-    internal void Add(ExcelAddressBase address, bool doValidate) {
-      //Validate
-      if (doValidate && Validate(address) == false) {
-        throw (new ArgumentException("Can't merge and already merged range"));
-      }
-      var ix = _list.Count;
-      _list.Add(address.Address);
-      SetIndex(address, ix);
-    }
-
-    private bool Validate(ExcelAddressBase address) {
-      int ix = 0;
-      if (_cells.Exists(address._fromRow, address._fromCol, ref ix)) {
-        if (ix >= 0 && ix < _list.Count && _list[ix] != null && address.Address == _list[ix]) {
-          return true;
-        }
-        return false;
-      }
-
-      var cse = new CellsStoreEnumerator<int>(
-          _cells,
-          address._fromRow,
-          address._fromCol,
-          address._toRow,
-          address._toCol);
-      //cells
-      while (cse.Next()) {
-        return false;
-      }
-      //Entire column
-      cse = new(_cells, 0, address._fromCol, 0, address._toCol);
-      while (cse.Next()) {
-        return false;
-      }
-      //Entire row
-      cse = new(_cells, address._fromRow, 0, address._toRow, 0);
-      while (cse.Next()) {
-        return false;
-      }
-      return true;
-    }
-
-    internal void SetIndex(ExcelAddressBase address, int ix) {
-      if (address._fromRow == 1
-          && address._toRow
-              == ExcelPackage.MaxRows) //Entire row
-      {
-        for (int col = address._fromCol; col <= address._toCol; col++) {
-          _cells.SetValue(0, col, ix);
-        }
-      } else if (address._fromCol == 1
-          && address._toCol
-              == ExcelPackage.MaxColumns) //Entire row
-      {
-        for (int row = address._fromRow; row <= address._toRow; row++) {
-          _cells.SetValue(row, 0, ix);
-        }
-      } else {
-        for (int col = address._fromCol; col <= address._toCol; col++) {
-          for (int row = address._fromRow; row <= address._toRow; row++) {
-            _cells.SetValue(row, col, ix);
-          }
-        }
-      }
-    }
-
-    public int Count => _list.Count;
-
-    internal void Remove(string item) {
-      _list.Remove(item);
-    }
-
-    public IEnumerator<string> GetEnumerator() {
-      return _list.GetEnumerator();
-    }
-
-    IEnumerator IEnumerable.GetEnumerator() {
-      return _list.GetEnumerator();
-    }
-
-    internal void Clear(ExcelAddressBase destination) {
-      var cse = new CellsStoreEnumerator<int>(
-          _cells,
-          destination._fromRow,
-          destination._fromCol,
-          destination._toRow,
-          destination._toCol);
-      var used = new HashSet<int>();
-      while (cse.Next()) {
-        var v = cse.Value;
-        if (!used.Contains(v) && _list[v] != null) {
-          var adr = new ExcelAddressBase(_list[v]);
-          if (!(destination.Collide(adr) == ExcelAddressBase.eAddressCollition.Inside
-                      || destination.Collide(adr) == ExcelAddressBase.eAddressCollition.Equal)) {
-            throw (new InvalidOperationException(
-                    string.Format(
-                        "Can't delete merged cells. A range is partly merged with the deleted range. {0}",
-                        adr._address)));
-          }
-          used.Add(v);
-        }
-      }
-
-      _cells.Clear(
-          destination._fromRow,
-          destination._fromCol,
-          destination._toRow - destination._fromRow + 1,
-          destination._toCol - destination._fromCol + 1);
-      foreach (var i in used) {
-        _list[i] = null;
-      }
-    }
-  }
-
-  internal readonly CellStore<object> _values = new();
-  internal readonly CellStore<string> _types = new();
-  internal readonly CellStore<int> _styles = new();
-  internal readonly CellStore<object> _formulas = new();
-  internal readonly FlagCellStore _flags = new();
-  internal CellStore<List<Token>> _formulaTokens;
-
-  internal readonly CellStore<Uri> _hyperLinks = new();
-  internal readonly CellStore<ExcelComment> _commentsStore = new();
-
-  internal readonly Dictionary<int, Formulas> _sharedFormulas = new();
-
-  internal readonly ExcelPackage _package;
-  private readonly ExcelWorkbook _workbook;
-  private ExcelWorksheetView _sheetView;
-
-  internal static ImmutableArray<string> WorksheetSchemaNodeOrder = [
-    "sheetPr",
-    "tabColor",
-    "outlinePr",
-    "pageSetUpPr",
-    "dimension",
-    "sheetViews",
-    "sheetFormatPr",
-    "cols",
-    "sheetData",
-    "sheetProtection",
-    "protectedRanges",
-    "scenarios",
-    "autoFilter",
-    "sortState",
-    "dataConsolidate",
-    "customSheetViews",
-    "customSheetViews",
-    "mergeCells",
-    "phoneticPr",
-    "conditionalFormatting",
-    "dataValidations",
-    "hyperlinks",
-    "printOptions",
-    "pageMargins",
-    "pageSetup",
-    "headerFooter",
-    "linePrint",
-    "rowBreaks",
-    "colBreaks",
-    "customProperties",
-    "cellWatches",
-    "ignoredErrors",
-    "smartTags",
-    "drawing",
-    "legacyDrawing",
-    "legacyDrawingHF",
-    "picture",
-    "oleObjects",
-    "activeXControls",
-    "webPublishItems",
-    "tableParts",
-    "extLst",
-  ];
-
-  protected override ImmutableArray<string> SchemaNodeOrder => WorksheetSchemaNodeOrder;
-
-  internal ExcelWorksheet(
-      XmlNamespaceManager ns,
-      ExcelPackage excelPackage,
-      ExcelWorkbook workbook,
-      Uri worksheetUri,
-      string name,
-      int sheetId,
-      int positionId,
-      eWorkSheetHidden hidden)
-      : base(ns, null) {
-    _workbook = workbook;
-    _package = excelPackage;
-    _names = new(Workbook, this);
-
-    Hidden = hidden;
-    Name = name;
-    PositionID = positionId;
-    SheetID = sheetId;
-
-    Part = _package.Package.GetPart(worksheetUri);
-    Part.SaveHandler = SaveHandler;
-
-    // First Columns, rows, cells, mergecells, hyperlinks and pagebreakes are loaded from an
-    // XmlTextReader to optimize speed.
-    using var stream = Part.GetStream();
-    var xr = new XmlTextReader(stream);
-    xr.ProhibitDtd = true;
-    xr.WhitespaceHandling = WhitespaceHandling.None;
-    LoadColumns(xr); //columnXml
-    long start = stream.Position;
-    LoadCells(xr);
-    var nextElementLength = GetAttributeLength(xr);
-    long end = stream.Position - nextElementLength;
-    LoadMergeCells(xr);
-    LoadHyperLinks(xr);
-    LoadRowPageBreakes(xr);
-    LoadColPageBreakes(xr);
-
-    // Then the rest of the XML is extracted and loaded into the WorksheetXml document.
-    stream.Seek(0, SeekOrigin.Begin);
-    var xml = GetWorkSheetXml(stream, start, end, out var encoding);
-
-    //first char is invalid sometimes??
-    if (xml[0] != '<') {
-      LoadXmlSafe(WorksheetXml, xml.Substring(1, xml.Length - 1), encoding);
-    } else {
-      LoadXmlSafe(WorksheetXml, xml, encoding);
-    }
-    ClearNodes();
-
-    TopNode = WorksheetXml.DocumentElement;
-  }
-
-  /// <summary>
-  /// The Zip.ZipPackagePart for the worksheet within the package
-  /// </summary>
-  internal ZipPackagePart Part { get; }
-
-  /// <summary>
-  /// The unique identifier for the worksheet.
-  /// </summary>
-  internal int SheetID { get; }
-
-  /// <summary>
-  /// The position of the worksheet.
-  /// </summary>
-  internal int PositionID { get; }
-
-  /// <summary>
-  /// Address for autofilter
-  /// <seealso cref="ExcelRangeBase.AutoFilter" />
-  /// </summary>
-  public ExcelAddressBase AutoFilterAddress {
-    get {
-      CheckSheetType();
-      string address = GetXmlNodeString("d:autoFilter/@ref");
-      if (address == "") {
-        return null;
-      }
-      return new(address);
-    }
-    internal set {
-      CheckSheetType();
-      SetXmlNodeString("d:autoFilter/@ref", value.Address);
-    }
-  }
-
-  internal void CheckSheetType() {
-    if (this is ExcelChartsheet) {
-      throw (new NotSupportedException(
-              "This property or method is not supported for a Chartsheet"));
-    }
-  }
-
-  /// <summary>
-  /// Returns a ExcelWorksheetView object that allows you to set the view state properties of the worksheet
-  /// </summary>
-  public ExcelWorksheetView View {
-    get {
-      if (_sheetView == null) {
-        XmlNode node = TopNode.SelectSingleNode("d:sheetViews/d:sheetView", NameSpaceManager);
-        if (node == null) {
-          CreateNode("d:sheetViews/d:sheetView"); //this one shouls always exist. but check anyway
-          node = TopNode.SelectSingleNode("d:sheetViews/d:sheetView", NameSpaceManager);
-        }
-        _sheetView = new(NameSpaceManager, node, this);
-      }
-      return (_sheetView);
-    }
-  }
-
-  /// <summary>
-  /// The worksheet's display name as it appears on the tab
-  /// </summary>
-  public string Name { get; }
-
-  private readonly ExcelNamedRangeCollection _names;
-
-  /// <summary>
-  /// Provides access to named ranges
-  /// </summary>
-  public ExcelNamedRangeCollection Names {
-    get {
-      CheckSheetType();
-      return _names;
-    }
-  }
-
-  /// <summary>
-  /// Indicates if the worksheet is hidden in the workbook
-  /// </summary>
-  public eWorkSheetHidden Hidden {
-    get {
-      string state = _workbook.GetXmlNodeString(
-          string.Format("d:sheets/d:sheet[@sheetId={0}]/@state", SheetID));
-      if (state == "hidden") {
-        return eWorkSheetHidden.Hidden;
-      }
-      if (state == "veryHidden") {
-        return eWorkSheetHidden.VeryHidden;
-      }
-      return eWorkSheetHidden.Visible;
-    }
-    set {
-      if (value == eWorkSheetHidden.Visible) {
-        _workbook.DeleteNode(string.Format("d:sheets/d:sheet[@sheetId={0}]/@state", SheetID));
-      } else {
-        string v;
-        v = value.ToString();
-        v = v.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + v.Substring(1);
-        _workbook.SetXmlNodeString(
-            string.Format("d:sheets/d:sheet[@sheetId={0}]/@state", SheetID),
-            v);
-      }
-    }
-  }
-
-  private double _defaultRowHeight = double.NaN;
-
-  /// <summary>
-  /// Get/set the default height of all rows in the worksheet
-  /// </summary>
-  public double DefaultRowHeight {
-    get {
-      CheckSheetType();
-      if (double.IsNaN(_defaultRowHeight)) {
-        _defaultRowHeight = GetXmlNodeDouble("d:sheetFormatPr/@defaultRowHeight");
-        if (double.IsNaN(_defaultRowHeight)) {
-          _defaultRowHeight = 15; // Excel default height
-        }
-      }
-      return _defaultRowHeight;
-    }
-    set {
-      CheckSheetType();
-      _defaultRowHeight = value;
-      SetXmlNodeString(
-          "d:sheetFormatPr/@defaultRowHeight",
-          value.ToString(CultureInfo.InvariantCulture));
-      SetXmlNodeBool("d:sheetFormatPr/@customHeight", value != 15);
-
-      if (double.IsNaN(GetXmlNodeDouble("d:sheetFormatPr/@defaultColWidth"))) {
-        DefaultColWidth = 9.140625;
-      }
-    }
-  }
-
-  /// <summary>
-  /// Get/set the default width of all rows in the worksheet
-  /// </summary>
-  public double DefaultColWidth {
-    get {
-      CheckSheetType();
-      double ret = GetXmlNodeDouble("d:sheetFormatPr/@defaultColWidth");
-      if (double.IsNaN(ret)) {
-        ret = 9.140625; // Excel's default width
-      }
-      return ret;
-    }
-    set {
-      CheckSheetType();
-      SetXmlNodeString(
-          "d:sheetFormatPr/@defaultColWidth",
-          value.ToString(CultureInfo.InvariantCulture));
-
-      if (double.IsNaN(GetXmlNodeDouble("d:sheetFormatPr/@defaultRowHeight"))) {
-        DefaultRowHeight = 15;
-      }
-    }
-  }
-
-  /** <outlinePr applyStyles="1" summaryBelow="0" summaryRight="0" /> **/
-  private const string _outLineSummaryBelowPath = "d:sheetPr/d:outlinePr/@summaryBelow";
-
-  /// <summary>
-  /// Summary rows below details
-  /// </summary>
-  public bool OutLineSummaryBelow {
-    get {
-      CheckSheetType();
-      return GetXmlNodeBool(_outLineSummaryBelowPath);
-    }
-    set {
-      CheckSheetType();
-      SetXmlNodeString(_outLineSummaryBelowPath, value ? "1" : "0");
-    }
-  }
-
-  private const string _outLineSummaryRightPath = "d:sheetPr/d:outlinePr/@summaryRight";
-
-  /// <summary>
-  /// Summary rows to right of details
-  /// </summary>
-  public bool OutLineSummaryRight {
-    get {
-      CheckSheetType();
-      return GetXmlNodeBool(_outLineSummaryRightPath);
-    }
-    set {
-      CheckSheetType();
-      SetXmlNodeString(_outLineSummaryRightPath, value ? "1" : "0");
-    }
-  }
-
-  private const string _outLineApplyStylePath = "d:sheetPr/d:outlinePr/@applyStyles";
-
-  /// <summary>
-  /// Automatic styles
-  /// </summary>
-  public bool OutLineApplyStyle {
-    get {
-      CheckSheetType();
-      return GetXmlNodeBool(_outLineApplyStylePath);
-    }
-    set {
-      CheckSheetType();
-      SetXmlNodeString(_outLineApplyStylePath, value ? "1" : "0");
-    }
-  }
-
-  private const string _codeModuleNamePath = "d:sheetPr/@codeName";
-
-  internal string CodeModuleName {
-    get => GetXmlNodeString(_codeModuleNamePath);
-    set => SetXmlNodeString(_codeModuleNamePath, value);
-  }
-
-  /// <summary>
-  /// The XML document holding the worksheet data.
-  /// All column, row, cell, pagebreak, merged cell and hyperlink-data are loaded into memory and removed from the document when loading the document.
-  /// </summary>
-  internal XmlDocument WorksheetXml { get; } = new();
-
-  internal ExcelVmlDrawingCommentCollection _vmlDrawings;
-
-  /// <summary>
-  /// Vml drawings. underlaying object for comments
-  /// </summary>
-  internal ExcelVmlDrawingCommentCollection VmlDrawingsComments {
-    get {
-      if (_vmlDrawings == null) {
-        CreateVmlCollection();
-      }
-      return _vmlDrawings;
-    }
-  }
-
-  internal ExcelCommentCollection _comments;
-
-  /// <summary>
-  /// Collection of comments
-  /// </summary>
-  public ExcelCommentCollection Comments {
-    get {
-      CheckSheetType();
-      if (_comments == null) {
-        CreateVmlCollection();
-        _comments = new(_package, this, NameSpaceManager);
-      }
-      return _comments;
-    }
-  }
-
-  private void CreateVmlCollection() {
-    var vmlNode = WorksheetXml.DocumentElement.SelectSingleNode(
-        "d:legacyDrawing/@r:id",
-        NameSpaceManager);
-    if (vmlNode == null) {
-      _vmlDrawings = new(_package, this, null);
-    } else {
-      if (Part.RelationshipExists(vmlNode.Value)) {
-        var rel = Part.GetRelationship(vmlNode.Value);
-        var vmlUri = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri);
-
-        _vmlDrawings = new(_package, this, vmlUri);
-        _vmlDrawings.RelId = rel.Id;
-      }
-    }
-  }
-
-  /// <summary>
-  /// Get the lenth of the attributes
-  /// Conditional formatting attributes can be extremly long som get length of the attributes to finetune position.
-  /// </summary>
-  /// <param name="xr"></param>
-  /// <returns></returns>
-  private int GetAttributeLength(XmlTextReader xr) {
-    if (xr.NodeType != XmlNodeType.Element) {
-      return 0;
-    }
-    var length = 0;
-
-    for (int i = 0; i < xr.AttributeCount; i++) {
-      var a = xr.GetAttribute(i);
-      length += string.IsNullOrEmpty(a) ? 0 : a.Length;
-    }
-    return length;
-  }
-
-  private void LoadRowPageBreakes(XmlTextReader xr) {
-    if (!ReadUntil(xr, "rowBreaks", "colBreaks")) {
-      return;
-    }
-    while (xr.Read()) {
-      if (xr.LocalName == "brk") {
-        if (xr.NodeType == XmlNodeType.Element) {
-          if (int.TryParse(xr.GetAttribute("id"), out var id)) {
-            Row(id).PageBreak = true;
-          }
-        }
-      } else {
-        break;
-      }
-    }
-  }
-
-  private void LoadColPageBreakes(XmlTextReader xr) {
-    if (!ReadUntil(xr, "colBreaks")) {
-      return;
-    }
-    while (xr.Read()) {
-      if (xr.LocalName == "brk") {
-        if (xr.NodeType == XmlNodeType.Element) {
-          if (int.TryParse(xr.GetAttribute("id"), out var id)) {
-            Column(id).PageBreak = true;
-          }
-        }
-      } else {
-        break;
-      }
-    }
-  }
-
-  private void ClearNodes() {
-    if (WorksheetXml.SelectSingleNode("//d:cols", NameSpaceManager) != null) {
-      WorksheetXml.SelectSingleNode("//d:cols", NameSpaceManager).RemoveAll();
-    }
-    if (WorksheetXml.SelectSingleNode("//d:mergeCells", NameSpaceManager) != null) {
-      WorksheetXml.SelectSingleNode("//d:mergeCells", NameSpaceManager).RemoveAll();
-    }
-    if (WorksheetXml.SelectSingleNode("//d:hyperlinks", NameSpaceManager) != null) {
-      WorksheetXml.SelectSingleNode("//d:hyperlinks", NameSpaceManager).RemoveAll();
-    }
-    if (WorksheetXml.SelectSingleNode("//d:rowBreaks", NameSpaceManager) != null) {
-      WorksheetXml.SelectSingleNode("//d:rowBreaks", NameSpaceManager).RemoveAll();
-    }
-    if (WorksheetXml.SelectSingleNode("//d:colBreaks", NameSpaceManager) != null) {
-      WorksheetXml.SelectSingleNode("//d:colBreaks", NameSpaceManager).RemoveAll();
-    }
-  }
-
-  private const int _blocksize = 8192;
-
-  private string GetWorkSheetXml(Stream stream, long start, long end, out Encoding encoding) {
-    StreamReader sr = new StreamReader(stream);
-    int length = 0;
-    char[] block;
-    int pos;
-    StringBuilder sb = new StringBuilder();
-    Match startmMatch,
-        endMatch;
-    do {
-      int size = stream.Length < _blocksize ? (int)stream.Length : _blocksize;
-      block = new char[size];
-      pos = sr.ReadBlock(block, 0, size);
-      sb.Append(block, 0, pos);
-      length += size;
-    } while (length < start + 20 && length < end);
-    startmMatch = Regex.Match(sb.ToString(), string.Format("(<[^>]*{0}[^>]*>)", "sheetData"));
-    if (!startmMatch.Success) //Not found
-    {
-      encoding = sr.CurrentEncoding;
-      return sb.ToString();
-    }
-    string s = sb.ToString();
-    string xml = s.Substring(0, startmMatch.Index);
-    if (startmMatch.Value.EndsWith("/>")) {
-      xml += s.Substring(startmMatch.Index, s.Length - startmMatch.Index);
-    } else {
-      if (sr.Peek() != -1) {
-        /**** Fixes issue 14788. Fix by Philip Garrett ****/
-        long endSeekStart = end;
-
-        while (endSeekStart >= 0) {
-          endSeekStart = Math.Max(endSeekStart - _blocksize, 0);
-          int size = (int)(end - endSeekStart);
-          stream.Seek(endSeekStart, SeekOrigin.Begin);
-          block = new char[size];
-          sr = new(stream);
-          pos = sr.ReadBlock(block, 0, size);
-          sb = new();
-          sb.Append(block, 0, pos);
-          s = sb.ToString();
-          endMatch = Regex.Match(s, string.Format("(</[^>]*{0}[^>]*>)", "sheetData"));
-          if (endMatch.Success) {
-            break;
-          }
-        }
-      }
-      endMatch = Regex.Match(s, string.Format("(</[^>]*{0}[^>]*>)", "sheetData"));
-      xml +=
-          "<sheetData/>"
-              + s.Substring(
-                  endMatch.Index + endMatch.Length,
-                  s.Length - (endMatch.Index + endMatch.Length));
-    }
-    if (sr.Peek() > -1) {
-      xml += sr.ReadToEnd();
-    }
-
-    encoding = sr.CurrentEncoding;
-    return xml;
-  }
-
-  private void GetBlockPos(string xml, string tag, ref int start, ref int end) {
-    Match startmMatch,
-        endMatch;
-    startmMatch = Regex.Match(xml.Substring(start), string.Format("(<[^>]*{0}[^>]*>)", tag)); //"<[a-zA-Z:]*" + tag + "[?]*>");
-
-    if (!startmMatch.Success) //Not found
-    {
-      start = -1;
-      end = -1;
-      return;
-    }
-    var startPos = startmMatch.Index + start;
-    if (startmMatch.Value.Substring(startmMatch.Value.Length - 2, 1) == "/") {
-      end = startPos + startmMatch.Length;
-    } else {
-      endMatch = Regex.Match(xml.Substring(start), string.Format("(</[^>]*{0}[^>]*>)", tag));
-      if (endMatch.Success) {
-        end = endMatch.Index + endMatch.Length + start;
-      }
-    }
-    start = startPos;
-  }
-
-  private bool ReadUntil(XmlTextReader xr, params string[] tagName) {
-    if (xr.EOF) {
-      return false;
-    }
-    while (!Array.Exists(tagName, tag => xr.LocalName.EndsWith(tag))) {
-      xr.Read();
-      if (xr.EOF) {
-        return false;
-      }
-    }
-    return (xr.LocalName.EndsWith(tagName[0]));
-  }
-
-  private void LoadColumns(
-      XmlTextReader xr) //(string xml)
-  {
-    var colList = new List<IRangeId>();
-    if (ReadUntil(xr, "cols", "sheetData")) {
-      //if (xml != "")
-      //{
-      //var xr=new XmlTextReader(new StringReader(xml));
-      while (xr.Read()) {
-        if (xr.NodeType == XmlNodeType.Whitespace) {
-          continue;
-        }
-        if (xr.LocalName != "col") {
-          break;
-        }
-        if (xr.NodeType == XmlNodeType.Element) {
-          int min = int.Parse(xr.GetAttribute("min"));
-
-          ExcelColumn col = new ExcelColumn(this, min);
-
-          col.ColumnMax = int.Parse(xr.GetAttribute("max"));
-          col.Width =
-              xr.GetAttribute("width") == null
-                  ? 0
-                  : double.Parse(xr.GetAttribute("width"), CultureInfo.InvariantCulture);
-          col.BestFit =
-              xr.GetAttribute("bestFit") != null && xr.GetAttribute("bestFit") == "1"
-                  ? true
-                  : false;
-          col.Collapsed =
-              xr.GetAttribute("collapsed") != null && xr.GetAttribute("collapsed") == "1"
-                  ? true
-                  : false;
-          col.Phonetic =
-              xr.GetAttribute("phonetic") != null && xr.GetAttribute("phonetic") == "1"
-                  ? true
-                  : false;
-          col.OutlineLevel = (short)(xr.GetAttribute("outlineLevel") == null
-              ? 0
-              : int.Parse(xr.GetAttribute("outlineLevel"), CultureInfo.InvariantCulture));
-          col.Hidden =
-              xr.GetAttribute("hidden") != null && xr.GetAttribute("hidden") == "1" ? true : false;
-          _values.SetValue(0, min, col);
-
-          if (!(xr.GetAttribute("style") == null
-                      || !int.TryParse(xr.GetAttribute("style"), out var style))) {
-            _styles.SetValue(0, min, style);
-          }
-        }
-      }
-    }
-  }
-
-  /// <summary>
-  /// Load Hyperlinks
-  /// </summary>
-  /// <param name="xr">The reader</param>
-  private void LoadHyperLinks(XmlTextReader xr) {
-    if (!ReadUntil(xr, "hyperlinks", "rowBreaks", "colBreaks")) {
-      return;
-    }
-    while (xr.Read()) {
-      if (xr.LocalName == "hyperlink") {
-        ExcelCellBase.GetRowColFromAddress(
-            xr.GetAttribute("ref"),
-            out var fromRow,
-            out var fromCol,
-            out int toRow,
-            out var toCol);
-        ExcelHyperLink hl = null;
-        if (xr.GetAttribute("id", ExcelPackage._schemaRelationships) != null) {
-          var rId = xr.GetAttribute("id", ExcelPackage._schemaRelationships);
-          var uri = Part.GetRelationship(rId).TargetUri;
-
-          // Get Location, if any.  EPPlus Bug 15517
-          var location = xr.GetAttribute("location");
-          location = (string.IsNullOrEmpty(location)) ? "" : "#" + location;
-
-          if (uri.IsAbsoluteUri) {
-            try {
-              hl = new(uri.AbsoluteUri + location);
-            } catch {
-              hl = new(uri.OriginalString + location, UriKind.Absolute);
-            }
-          } else {
-            hl = new(uri.OriginalString + location, UriKind.Relative);
-          }
-
-          hl.RId = rId;
-          Part.DeleteRelationship(rId); //Delete the relationship, it is recreated when we save the package.
-        } else if (xr.GetAttribute("location") != null) {
-          hl = new(xr.GetAttribute("location"), xr.GetAttribute("display"));
-          hl.RowSpann = toRow - fromRow;
-          hl.ColSpann = toCol - fromCol;
-        }
-
-        string tt = xr.GetAttribute("tooltip");
-        if (!string.IsNullOrEmpty(tt)) {
-          hl.ToolTip = tt;
-        }
-        _hyperLinks.SetValue(fromRow, fromCol, hl);
-      } else {
-        break;
-      }
-    }
-  }
-
-  /// <summary>
-  /// Load cells
-  /// </summary>
-  /// <param name="xr">The reader</param>
-  private void LoadCells(XmlTextReader xr) {
-    //var cellList=new List<IRangeID>();
-    //var rowList = new List<IRangeID>();
-    //var formulaList = new List<IRangeID>();
-    ReadUntil(xr, "sheetData", "mergeCells", "hyperlinks", "rowBreaks", "colBreaks");
-    ExcelAddressBase address = null;
-    string type = "";
-    int style = 0;
-    int row = 0;
-    int col = 0;
-    xr.Read();
-
-    while (!xr.EOF) {
-      while (xr.NodeType == XmlNodeType.EndElement) {
-        xr.Read();
-      }
-      if (xr.LocalName == "row") {
-        var r = xr.GetAttribute("r");
-        if (r == null) {
-          row++;
-        } else {
-          row = Convert.ToInt32(r);
-        }
-
-        if (DoAddRow(xr)) {
-          _values.SetValue(row, 0, AddRow(xr, row));
-          if (xr.GetAttribute("s") != null) {
-            _styles.SetValue(row, 0, int.Parse(xr.GetAttribute("s"), CultureInfo.InvariantCulture));
-          }
-        }
-        xr.Read();
-      } else if (xr.LocalName == "c") {
-        //if (cell != null) cellList.Add(cell);
-        //cell = new ExcelCell(this, xr.GetAttribute("r"));
-        var r = xr.GetAttribute("r");
-        if (r == null) {
-          //Handle cells with no reference
-          col++;
-          address = new(row, col, row, col);
-        } else {
-          address = new(r);
-          col = address._fromCol;
-        }
-
-        //Datetype
-        if (xr.GetAttribute("t") != null) {
-          type = xr.GetAttribute("t");
-          _types.SetValue(address._fromRow, address._fromCol, type);
-        } else {
-          type = "";
-        }
-        //Style
-        if (xr.GetAttribute("s") != null) {
-          style = int.Parse(xr.GetAttribute("s"));
-          _styles.SetValue(address._fromRow, address._fromCol, style);
-          _values.SetValue(address._fromRow, address._fromCol, null); //TODO:Better Performance ??
-        } else {
-          style = 0;
-        }
-        xr.Read();
-      } else if (xr.LocalName == "v") {
-        SetValueFromXml(xr, type, style, address._fromRow, address._fromCol);
-
-        xr.Read();
-      } else if (xr.LocalName == "f") {
-        string t = xr.GetAttribute("t");
-        if (t == null) {
-          _formulas.SetValue(address._fromRow, address._fromCol, xr.ReadElementContentAsString());
-          _values.SetValue(address._fromRow, address._fromCol, null);
-          //formulaList.Add(cell);
-        } else if (t == "shared") {
-          string si = xr.GetAttribute("si");
-          if (si != null) {
-            var sfIndex = int.Parse(si);
-            _formulas.SetValue(address._fromRow, address._fromCol, sfIndex);
-            _values.SetValue(address._fromRow, address._fromCol, null);
-            string fAddress = xr.GetAttribute("ref");
-            string formula = ConvertUtil.ExcelDecodeString(xr.ReadElementContentAsString());
-            if (formula != "") {
-              _sharedFormulas.Add(
-                  sfIndex,
-                  new(SourceCodeTokenizer.Default) {
-                    Index = sfIndex,
-                    Formula = formula,
-                    Address = fAddress,
-                    StartRow = address._fromRow,
-                    StartCol = address._fromCol,
-                  });
-            }
-          } else {
-            xr.Read(); //Something is wrong in the sheet, read next
-          }
-        } else if (t
-            == "array") //TODO: Array functions are not support yet. Read the formula for the start cell only.
-        {
-          string aAddress = xr.GetAttribute("ref");
-          ExcelRange addressRange = new ExcelRange(this, aAddress);
-          string formula = xr.ReadElementContentAsString();
-          bool isIndexMatchFormula =
-              Regex.IsMatch(formula, @"INDEX\(", RegexOptions.IgnoreCase)
-                  && Regex.IsMatch(formula, @"MATCH\(", RegexOptions.IgnoreCase)
-                  && !aAddress.Contains(":");
-          if (isIndexMatchFormula) {
-            addressRange.IsArrayFormula = false;
-            for (int colIndex = addressRange.Start.Column;
-                colIndex <= addressRange.End.Column;
-                colIndex++) {
-              for (int rowIndex = addressRange.Start.Row;
-                  rowIndex <= addressRange.End.Row;
-                  rowIndex++) {
-                var afIndex = GetMaxShareFunctionIndex(true);
-                _formulas.SetValue(rowIndex, colIndex, afIndex);
-                _values.SetValue(rowIndex, colIndex, null);
-                _sharedFormulas.Add(
-                    afIndex,
-                    new(SourceCodeTokenizer.Default) {
-                      Index = afIndex,
-                      Formula = formula,
-                      Address = aAddress,
-                      StartRow = address._fromRow,
-                      StartCol = address._fromCol,
-                      IsArray = false,
-                    });
-              }
-            }
-          } else {
-            addressRange.IsArrayFormula = true;
-            var afIndex = GetMaxShareFunctionIndex(true);
-            for (int colIndex = addressRange.Start.Column;
-                colIndex <= addressRange.End.Column;
-                colIndex++) {
-              for (int rowIndex = addressRange.Start.Row;
-                  rowIndex <= addressRange.End.Row;
-                  rowIndex++) {
-                _formulas.SetValue(rowIndex, colIndex, afIndex);
-                _values.SetValue(rowIndex, colIndex, null);
-              }
-            }
-            _sharedFormulas.Add(
-                afIndex,
-                new(SourceCodeTokenizer.Default) {
-                  Index = afIndex,
-                  Formula = formula,
-                  Address = aAddress,
-                  StartRow = address._fromRow,
-                  StartCol = address._fromCol,
-                  IsArray = true,
-                });
-          }
-        } else // ??? some other type
-        {
-          xr.Read(); //Something is wrong in the sheet, read next
-        }
-      } else if (xr.LocalName
-          == "is") //Inline string
-      {
-        xr.Read();
-        if (xr.LocalName == "t") {
-          _values.SetValue(
-              address._fromRow,
-              address._fromCol,
-              ConvertUtil.ExcelDecodeString(xr.ReadElementContentAsString()));
-          //cell._value = xr.ReadInnerXml();
-        } else {
-          _values.SetValue(address._fromRow, address._fromCol, xr.ReadOuterXml());
-          _types.SetValue(address._fromRow, address._fromCol, "rt");
-          _flags.SetFlagValue(address._fromRow, address._fromCol, true, CellFlags.RichText);
-          //cell.IsRichText = true;
-        }
-      } else {
-        break;
-      }
-    }
-  }
-
-  private bool DoAddRow(XmlTextReader xr) {
-    var c = xr.GetAttribute("r") == null ? 0 : 1;
-    if (xr.GetAttribute("spans") != null) {
-      c++;
-    }
-    return xr.AttributeCount > c;
-  }
-
-  /// <summary>
-  /// Load merged cells
-  /// </summary>
-  /// <param name="xr"></param>
-  private void LoadMergeCells(XmlTextReader xr) {
-    if (ReadUntil(xr, "mergeCells", "hyperlinks", "rowBreaks", "colBreaks") && !xr.EOF) {
-      while (xr.Read()) {
-        if (xr.LocalName != "mergeCell") {
-          break;
-        }
-        if (xr.NodeType == XmlNodeType.Element) {
-          string address = xr.GetAttribute("ref");
-          _mergedCells.Add(new ExcelAddress(address), false);
-        }
-      }
-    }
-  }
-
-  /// <summary>
-  /// Update merged cells
-  /// </summary>
-  /// <param name="sw">The writer</param>
-  private void UpdateMergedCells(StreamWriter sw) {
-    sw.Write("<mergeCells>");
-    foreach (string address in _mergedCells) {
-      sw.Write("<mergeCell ref=\"{0}\" />", address);
-    }
-    sw.Write("</mergeCells>");
-  }
-
-  /// <summary>
-  /// Reads a row from the XML reader
-  /// </summary>
-  /// <param name="xr">The reader</param>
-  /// <param name="row">The row number</param>
-  /// <returns></returns>
-  private RowInternal AddRow(XmlTextReader xr, int row) {
-    return new() {
-      Collapsed =
-          (xr.GetAttribute("collapsed") != null && xr.GetAttribute("collapsed") == "1"
-              ? true
-              : false),
-      OutlineLevel =
-          (xr.GetAttribute("outlineLevel") == null
-              ? (short)0
-              : short.Parse(xr.GetAttribute("outlineLevel"), CultureInfo.InvariantCulture)),
-      Height =
-          (xr.GetAttribute("ht") == null
-              ? -1
-              : double.Parse(xr.GetAttribute("ht"), CultureInfo.InvariantCulture)),
-      Hidden =
-          (xr.GetAttribute("hidden") != null && xr.GetAttribute("hidden") == "1" ? true : false),
-      Phonetic = xr.GetAttribute("ph") != null && xr.GetAttribute("ph") == "1" ? true : false,
-      CustomHeight =
-          xr.GetAttribute("customHeight") == null ? false : xr.GetAttribute("customHeight") == "1",
-    };
-  }
-
-  private static readonly DateTime _excelEpoch = new(1899, 12, 30);
-
-  public static DateTime IncorrectDurationFromOaDate(double value) {
-    // This behavior is wrong. Real OADate values have a discontinuity on 30 December 1899.
-    // For real OADate values, the negative sign applies only to the integer portion of
-    // the float, *not* to the decimal portion. For example, -0.5 and 0.5 both refer to the
-    // same date, and -1.5 is actually 1899-12-29 12:00 (1 day before 1899-12-30 00:00
-    // plus 0.5 days), *not* 1899-12-28 12:00 (1.5 days before 1899-12-30 00:00).
-    //
-    // Unfortunately, AppSheet's duration-handling code gets this very wrong, and treats the
-    // duration as the offset from 1899-12-30 00:00. This is correct for positive durations,
-    // but it's wrong for negative durations. This code tries to fix the bug that exists in
-    // AppSheet's duration-handling code here, and it succeeds in some cases and fails in
-    // others.
-    //
-    // This code also breaks date/time handling for dates before 1899-12-30 00:00 in some
-    // cases. Specifically, dates end up being offset by one day.
-    //
-    // Regardless, changing this behavior is risky, so this code simply replicates the
-    // existing behavior for
-    if (value >= 0) {
-      return DateTime.FromOADate(value);
-    }
-    // This looks like a very complicated way to call TimeSpan.FromDays(value), but
-    // TimeSpan.FromDays actually only guarantees millisecond precision, and critically
-    // rounding is different on .NET Core, resulting in values like (e.g.) 3:15:00 being
-    // incorrectly rounded.
-    var offset = DateTime.FromOADate(-value) - _excelEpoch;
-    return _excelEpoch - offset;
-  }
-
-  private void SetValueFromXml(XmlTextReader xr, string type, int styleId, int row, int col) {
-    //XmlNode vnode = colNode.SelectSingleNode("d:v", NameSpaceManager);
-    //if (vnode == null) return null;
-    if (type == "s") {
-      int ix = xr.ReadElementContentAsInt();
-
-      // Temporary debugging code to locate intermittent 'Index was out of range' exception.
-      if (ix < 0) {
-        throw new(
-            string.Format(
-                "ReadElementContentAsInt returned value '{0}' which is less than zero.",
-                ix));
-      }
-      if (ix >= _workbook._sharedStringsList.Count) {
-        throw new(
-            string.Format(
-                "ReadElementContentAsInt returned index value '{0}' which is greater than _sharedStringsList count of {1}.",
-                ix,
-                _workbook._sharedStringsList.Count));
-      }
-
-      _values.SetValue(row, col, _workbook._sharedStringsList[ix].Text);
-      if (_workbook._sharedStringsList[ix].isRichText) {
-        _flags.SetFlagValue(row, col, true, CellFlags.RichText);
-      }
-    } else if (type == "str") {
-      _values.SetValue(row, col, ConvertUtil.ExcelDecodeString(xr.ReadElementContentAsString()));
-    } else if (type == "b") {
-      _values.SetValue(row, col, (xr.ReadElementContentAsString() != "0"));
-    } else if (type == "e") {
-      _values.SetValue(row, col, GetErrorType(xr.ReadElementContentAsString()));
-    } else {
-      string v = xr.ReadElementContentAsString();
-      var nf = Workbook.Styles.CellXfs[styleId].NumberFormatId;
-      if ((nf >= 20 && nf <= 21)
-          || (nf >= 45
-                  && nf
-                      <= 47)) // Duration
-      {
-        if (double.TryParse(v, NumberStyles.Any, CultureInfo.InvariantCulture, out var res)) {
-          if (Workbook.Date1904) {
-            res += ExcelWorkbook._date1904Offset;
-          }
-          if (res >= -657435.0 && res < 2958465.9999999) {
-            // Get the Duration value expressed as a DateTime.
-            _values.SetValue(row, col, IncorrectDurationFromOaDate(res));
-          } else {
-            // Cope with Google Sheets export of cells having a formula.
-            // Rather than exporting the native value, they export the formatted value.
-            _values.SetValue(row, col, v);
-          }
-        } else {
-          // Cope with Google Sheets export of cells having a formula.
-          // Rather than exporting the native value, they export the formatted value.
-          _values.SetValue(row, col, v);
-        }
-      } else if ((nf >= 14 && nf <= 19)
-          || (nf
-                  == 22)) // DateTime
-      {
-        if (double.TryParse(v, NumberStyles.Any, CultureInfo.InvariantCulture, out var res)) {
-          if (Workbook.Date1904) {
-            res += ExcelWorkbook._date1904Offset;
-          }
-          if (res >= -657435.0 && res < 2958465.9999999) {
-            _values.SetValue(row, col, DateTime.FromOADate(res));
-          } else {
-            // Cope with Google Sheets export of cells having a formula.
-            // Rather than exporting the native value, they export the formatted value.
-            _values.SetValue(row, col, v);
-          }
-        } else {
-          // Cope with Google Sheets export of cells having a formula.
-          // Rather than exporting the native value, they export the formatted value.
-          _values.SetValue(row, col, v);
-        }
-      } else {
-        if (double.TryParse(v, NumberStyles.Any, CultureInfo.InvariantCulture, out var d)) {
-          _values.SetValue(row, col, d);
-        } else {
-          // Cope with Google Sheets export of cells having a formula.
-          // Rather than exporting the native value, they export the formatted value.
-          _values.SetValue(row, col, v);
-
-          //_values.SetValue(row, col, double.NaN);
-        }
-      }
-    }
-  }
-
-  private object GetErrorType(string v) {
-    return ExcelErrorValue.Parse(v.ToUpper(CultureInfo.InvariantCulture));
-    //switch(v.ToUpper())
-    //{
-    //    case "#DIV/0!":
-    //        return new ExcelErrorValue.cre(eErrorType.Div0);
-    //    case "#REF!":
-    //        return new ExcelErrorValue(eErrorType.Ref);
-    //    case "#N/A":
-    //        return new ExcelErrorValue(eErrorType.NA);
-    //    case "#NAME?":
-    //        return new ExcelErrorValue(eErrorType.Name);
-    //    case "#NULL!":
-    //        return new ExcelErrorValue(eErrorType.Null);
-    //    case "#NUM!":
-    //        return new ExcelErrorValue(eErrorType.Num);
-    //    default:
-    //        return new ExcelErrorValue(eErrorType.Value);
-    //}
-  }
-
-  ///// <summary>
-  ///// Provides access to an individual cell within the worksheet.
-  ///// </summary>
-  ///// <param name="row">The row number in the worksheet</param>
-  ///// <param name="col">The column number in the worksheet</param>
-  ///// <returns></returns>
-  //internal ExcelCell Cell(int row, int col)
-  //{
-  //    return new ExcelCell(_values, row, col);
-  //}
-  /// <summary>
-  /// Provides access to a range of cells
-  /// </summary>
-  public ExcelRange Cells {
-    get {
-      CheckSheetType();
-      return new(this, 1, 1, ExcelPackage.MaxRows, ExcelPackage.MaxColumns);
-    }
-  }
-
-  /// <summary>
-  /// Provides access to the selected range of cells
-  /// </summary>
-  public ExcelRange SelectedRange {
-    get {
-      CheckSheetType();
-      return new(this, View.SelectedRange);
-    }
-  }
-
-  private readonly MergeCellsCollection _mergedCells = new();
-
-  /// <summary>
-  /// Addresses to merged ranges
-  /// </summary>
-  public MergeCellsCollection MergedCells {
-    get {
-      CheckSheetType();
-      return _mergedCells;
-    }
-  }
-
-  /// <summary>
-  /// Provides access to an individual row within the worksheet so you can set its properties.
-  /// </summary>
-  /// <param name="row">The row number in the worksheet</param>
-  /// <returns></returns>
-  public ExcelRow Row(int row) {
-    //ExcelRow r;
-    //ulong id = ExcelRow.GetRowID(_sheetID, row);
-    //TODO: Fixa.
-    //var v = _values.GetValue(row, 0);
-    //if (v!=null)
-    //{
-    //    var ri=(RowInternal)v;
-    //    r = new ExcelRow(this, row)
-    //}
-    //else
-    //{
-    //r = new ExcelRow(this, row);
-    //_values.SetValue(row, 0, r);
-    //_rows.Add(r);
-    //}
-    CheckSheetType();
-    if (row < 1 || row > ExcelPackage.MaxRows) {
-      throw (new ArgumentException("Row number out of bounds"));
-    }
-    return new(this, row);
-    //return r;
-  }
-
-  /// <summary>
-  /// Provides access to an individual column within the worksheet so you can set its properties.
-  /// </summary>
-  /// <param name="col">The column number in the worksheet</param>
-  /// <returns></returns>
-  public ExcelColumn Column(int col) {
-    CheckSheetType();
-    if (col < 1 || col > ExcelPackage.MaxColumns) {
-      throw (new ArgumentException("Column number out of bounds"));
-    }
-    var column = _values.GetValue(0, col) as ExcelColumn;
-    if (column != null) {
-      if (column.ColumnMin != column.ColumnMax) {
-        int maxCol = column.ColumnMax;
-        column.ColumnMax = col;
-        ExcelColumn copy = CopyColumn(column, col + 1, maxCol);
-      }
-    } else {
-      int r = 0,
-          c = col;
-      if (_values.PrevCell(ref r, ref c)) {
-        column = _values.GetValue(0, c) as ExcelColumn;
-        int maxCol = column.ColumnMax;
-        if (maxCol >= col) {
-          column.ColumnMax = col - 1;
-          if (maxCol > col) {
-            ExcelColumn newC = CopyColumn(column, col + 1, maxCol);
-          }
-          return CopyColumn(column, col, col);
-        }
-      }
-      //foreach (ExcelColumn checkColumn in _columns)
-      //{
-      //    if (col > checkColumn.ColumnMin && col <= checkColumn.ColumnMax)
-      //    {
-      //        int maxCol = checkColumn.ColumnMax;
-      //        checkColumn.ColumnMax = col - 1;
-      //        if (maxCol > col)
-      //        {
-      //            ExcelColumn newC = CopyColumn(checkColumn, col + 1, maxCol);
-      //        }
-      //        return CopyColumn(checkColumn, col,col);
-      //    }
-      //}
-      column = new(this, col);
-      _values.SetValue(0, col, column);
-      //_columns.Add(column);
-    }
-    return column;
-  }
-
-  /// <summary>
-  /// Returns the name of the worksheet
-  /// </summary>
-  /// <returns>The name of the worksheet</returns>
-  public override string ToString() {
-    return Name;
-  }
-
-  internal ExcelColumn CopyColumn(ExcelColumn c, int col, int maxCol) {
-    ExcelColumn newC = new ExcelColumn(this, col);
-    newC.ColumnMax = maxCol < ExcelPackage.MaxColumns ? maxCol : ExcelPackage.MaxColumns;
-    if (c.StyleName != "") {
-      newC.StyleName = c.StyleName;
-    } else {
-      newC.StyleID = c.StyleID;
-    }
-
-    newC.OutlineLevel = c.OutlineLevel;
-    newC.Phonetic = c.Phonetic;
-    newC.BestFit = c.BestFit;
-    //_columns.Add(newC);
-    _values.SetValue(0, col, newC);
-    newC._width = c._width;
-    newC._hidden = c._hidden;
-    return newC;
-  }
-
-  /// <summary>
-  /// Make the current worksheet active.
-  /// </summary>
-  public void Select() {
-    View.TabSelected = true;
-    //Select(Address, true);
-  }
-
-  /// <summary>
-  /// Selects a range in the worksheet. The active cell is the topmost cell.
-  /// Make the current worksheet active.
-  /// </summary>
-  /// <param name="address">An address range</param>
-  public void Select(string address) {
-    Select(address, true);
-  }
-
-  /// <summary>
-  /// Selects a range in the worksheet. The actice cell is the topmost cell.
-  /// </summary>
-  /// <param name="address">A range of cells</param>
-  /// <param name="selectSheet">Make the sheet active</param>
-  public void Select(string address, bool selectSheet) {
-    CheckSheetType();
-    int toCol,
-        toRow;
-    //Get rows and columns and validate as well
-    ExcelCellBase.GetRowColFromAddress(
-        address,
-        out var fromRow,
-        out var fromCol,
-        out toRow,
-        out toCol);
-
-    if (selectSheet) {
-      View.TabSelected = true;
-    }
-    View.SelectedRange = address;
-    View.ActiveCell = ExcelCellBase.GetAddress(fromRow, fromCol);
-  }
-
-  /// <summary>
-  /// Selects a range in the worksheet. The active cell is the topmost cell of the first address.
-  /// Make the current worksheet active.
-  /// </summary>
-  /// <param name="address">An address range</param>
-  public void Select(ExcelAddress address) {
-    CheckSheetType();
-    Select(address, true);
-  }
-
-  /// <summary>
-  /// Selects a range in the worksheet. The active cell is the topmost cell of the first address.
-  /// </summary>
-  /// <param name="address">A range of cells</param>
-  /// <param name="selectSheet">Make the sheet active</param>
-  public void Select(ExcelAddress address, bool selectSheet) {
-    CheckSheetType();
-    if (selectSheet) {
-      View.TabSelected = true;
-    }
-    string selAddress =
-        ExcelCellBase.GetAddress(address.Start.Row, address.Start.Column)
-            + ":"
-            + ExcelCellBase.GetAddress(address.End.Row, address.End.Column);
-    if (address.Addresses != null) {
-      foreach (var a in address.Addresses) {
-        selAddress +=
-            " "
-                + ExcelCellBase.GetAddress(a.Start.Row, a.Start.Column)
-                + ":"
-                + ExcelCellBase.GetAddress(a.End.Row, a.End.Column);
-      }
-    }
-    View.SelectedRange = selAddress;
-    View.ActiveCell = ExcelCellBase.GetAddress(address.Start.Row, address.Start.Column);
-  }
-
-  /// <summary>
-  /// Inserts a new row into the spreadsheet.  Existing rows below the position are
-  /// shifted down.  All formula are updated to take account of the new row.
-  /// </summary>
-  /// <param name="rowFrom">The position of the new row</param>
-  /// <param name="rows">Number of rows to insert</param>
-  public void InsertRow(int rowFrom, int rows) {
-    InsertRow(rowFrom, rows, 0);
-  }
-
-  /// <summary>
-  /// Inserts a new row into the spreadsheet.  Existing rows below the position are
-  /// shifted down.  All formula are updated to take account of the new row.
-  /// </summary>
-  /// <param name="rowFrom">The position of the new row</param>
-  /// <param name="rows">Number of rows to insert.</param>
-  /// <param name="copyStylesFromRow">Copy Styles from this row. Applied to all inserted rows</param>
-  public void InsertRow(int rowFrom, int rows, int copyStylesFromRow) {
-    CheckSheetType();
-    var d = Dimension;
-
-    if (rowFrom < 1) {
-      throw (new ArgumentOutOfRangeException("rowFrom can't be lesser that 1"));
-    }
-
-    //Check that cells aren't shifted outside the boundries
-    if (d != null && d.End.Row > rowFrom && d.End.Row + rows > ExcelPackage.MaxRows) {
-      throw (new ArgumentOutOfRangeException(
-              "Can't insert. Rows will be shifted outside the boundries of the worksheet."));
-    }
-
-    _values.Insert(rowFrom, 0, rows, 0);
-    _formulas.Insert(rowFrom, 0, rows, 0);
-    _styles.Insert(rowFrom, 0, rows, 0);
-    _types.Insert(rowFrom, 0, rows, 0);
-    _commentsStore.Insert(rowFrom, 0, rows, 0);
-    _hyperLinks.Insert(rowFrom, 0, rows, 0);
-    _flags.Insert(rowFrom, 0, rows, 0);
-
-    foreach (var f in _sharedFormulas.Values) {
-      if (f.StartRow >= rowFrom) {
-        f.StartRow += rows;
-      }
-      var a = new ExcelAddressBase(f.Address);
-      if (a._fromRow >= rowFrom) {
-        a._fromRow += rows;
-        a._toRow += rows;
-      } else if (a._toRow >= rowFrom) {
-        a._toRow += rows;
-      }
-      f.Address = ExcelCellBase.GetAddress(a._fromRow, a._fromCol, a._toRow, a._toCol);
-      f.Formula = ExcelCellBase.UpdateFormulaReferences(f.Formula, rows, 0, rowFrom, 0);
-    }
-    var cse = new CellsStoreEnumerator<object>(_formulas);
-    while (cse.Next()) {
-      if (cse.Value is string) {
-        cse.Value = ExcelCellBase.UpdateFormulaReferences(
-            cse.Value.ToString(),
-            rows,
-            0,
-            rowFrom,
-            0);
-      }
-    }
-
-    FixMergedCellsRow(rowFrom, rows, false);
-    if (copyStylesFromRow > 0) {
-      var cseS = new CellsStoreEnumerator<int>(
-          _styles,
-          copyStylesFromRow,
-          0,
-          copyStylesFromRow,
-          ExcelPackage.MaxColumns); //Fixes issue 15068 , 15090
-      while (cseS.Next()) {
-        for (var r = 0; r < rows; r++) {
-          _styles.SetValue(rowFrom + r, cseS.Column, cseS.Value);
-        }
-      }
-    }
-    foreach (var tbl in Tables) {
-      tbl.Address = tbl.Address.AddRow(rowFrom, rows);
-    }
-  }
-
-  /// <summary>
-  /// Inserts a new column into the spreadsheet.  Existing columns below the position are
-  /// shifted down.  All formula are updated to take account of the new column.
-  /// </summary>
-  /// <param name="columnFrom">The position of the new column</param>
-  /// <param name="columns">Number of columns to insert</param>
-  public void InsertColumn(int columnFrom, int columns) {
-    InsertColumn(columnFrom, columns, 0);
-  }
-
-  ///<summary>
-  /// Inserts a new column into the spreadsheet.  Existing column to the left are
-  /// shifted.  All formula are updated to take account of the new column.
-  /// </summary>
-  /// <param name="columnFrom">The position of the new column</param>
-  /// <param name="columns">Number of columns to insert.</param>
-  /// <param name="copyStylesFromColumn">Copy Styles from this column. Applied to all inserted columns</param>
-  public void InsertColumn(int columnFrom, int columns, int copyStylesFromColumn) {
-    CheckSheetType();
-    var d = Dimension;
-
-    if (columnFrom < 1) {
-      throw (new ArgumentOutOfRangeException("columnFrom can't be lesser that 1"));
-    }
-    //Check that cells aren't shifted outside the boundries
-    if (d != null
-        && d.End.Column > columnFrom
-        && d.End.Column + columns > ExcelPackage.MaxColumns) {
-      throw (new ArgumentOutOfRangeException(
-              "Can't insert. Columns will be shifted outside the boundries of the worksheet."));
-    }
-
-    _values.Insert(0, columnFrom, 0, columns);
-    _formulas.Insert(0, columnFrom, 0, columns);
-    _styles.Insert(0, columnFrom, 0, columns);
-    _types.Insert(0, columnFrom, 0, columns);
-    _commentsStore.Insert(0, columnFrom, 0, columns);
-    _hyperLinks.Insert(0, columnFrom, 0, columns);
-    _flags.Insert(0, columnFrom, 0, columns);
-
-    foreach (var f in _sharedFormulas.Values) {
-      if (f.StartCol >= columnFrom) {
-        f.StartCol += columns;
-      }
-      var a = new ExcelAddressBase(f.Address);
-      if (a._fromCol >= columnFrom) {
-        a._fromCol += columns;
-        a._toCol += columns;
-      } else if (a._toCol >= columnFrom) {
-        a._toCol += columns;
-      }
-      f.Address = ExcelCellBase.GetAddress(a._fromRow, a._fromCol, a._toRow, a._toCol);
-      f.Formula = ExcelCellBase.UpdateFormulaReferences(f.Formula, 0, columns, 0, columnFrom);
-    }
-
-    var cse = new CellsStoreEnumerator<object>(_formulas);
-    while (cse.Next()) {
-      if (cse.Value is string) {
-        cse.Value = ExcelCellBase.UpdateFormulaReferences(
-            cse.Value.ToString(),
-            0,
-            columns,
-            0,
-            columnFrom);
-      }
-    }
-
-    FixMergedCellsColumn(columnFrom, columns, false);
-
-    var csec = new CellsStoreEnumerator<object>(_values, 0, 1, 0, ExcelPackage.MaxColumns);
-    var lst = new List<ExcelColumn>();
-    foreach (var col in csec) {
-      if (col is ExcelColumn column) {
-        lst.Add(column);
-      }
-    }
-
-    for (int i = lst.Count - 1; i >= 0; i--) {
-      var c = lst[i];
-      if (c._columnMin >= columnFrom) {
-        if (c._columnMin + columns <= ExcelPackage.MaxColumns) {
-          c._columnMin += columns;
-        } else {
-          c._columnMin = ExcelPackage.MaxColumns;
-        }
-
-        if (c._columnMax + columns <= ExcelPackage.MaxColumns) {
-          c._columnMax += columns;
-        } else {
-          c._columnMax = ExcelPackage.MaxColumns;
-        }
-      } else if (c._columnMax >= columnFrom) {
-        var cc = c._columnMax - columnFrom;
-        c._columnMax = columnFrom - 1;
-        CopyColumn(c, columnFrom + columns, columnFrom + columns + cc);
-      }
-    }
-
-    if (copyStylesFromColumn > 0) {
-      for (var c = 0; c < columns; c++) {
-        var col = Column(columnFrom + c);
-        col.StyleID = Column(copyStylesFromColumn).StyleID;
-      }
-    }
-    //Adjust tables
-    foreach (var tbl in Tables) {
-      if (columnFrom > tbl.Address.Start.Column && columnFrom <= tbl.Address.End.Column) {
-        InsertTableColumns(columnFrom, columns, tbl);
-      }
-
-      tbl.Address = tbl.Address.AddColumn(columnFrom, columns);
-    }
-  }
-
-  private static void InsertTableColumns(int columnFrom, int columns, ExcelTable tbl) {
-    var node = tbl.Columns[0].TopNode.ParentNode;
-    var ix = columnFrom - tbl.Address.Start.Column - 1;
-    var insPos = node.ChildNodes[ix];
-    ix += 2;
-    for (int i = 0; i < columns; i++) {
-      var name = tbl.Columns.GetUniqueName(
-          string.Format("Column{0}", (ix++).ToString(CultureInfo.InvariantCulture)));
-      XmlElement tableColumn = (XmlElement)
-        tbl.TableXml.CreateNode(XmlNodeType.Element, "tableColumn", ExcelPackage._schemaMain);
-      tableColumn.SetAttribute(
-          "id",
-          (tbl.Columns.Count + i + 1).ToString(CultureInfo.InvariantCulture));
-      tableColumn.SetAttribute("name", name);
-      insPos = node.InsertAfter(tableColumn, insPos);
-    } //Create tbl Column
-    tbl._cols = new(tbl);
-  }
-
-  /// <summary>
-  /// Adds a value to the row of merged cells to fix for inserts or deletes
-  /// </summary>
-  /// <param name="row"></param>
-  /// <param name="rows"></param>
-  /// <param name="delete"></param>
-  private void FixMergedCellsRow(int row, int rows, bool delete) {
-    if (delete) {
-      _mergedCells._cells.Delete(row, 0, rows, 0);
-    } else {
-      _mergedCells._cells.Insert(row, 0, rows, 0);
-    }
-
-    List<int> removeIndex = new List<int>();
-    for (int i = 0; i < _mergedCells.Count; i++) {
-      if (!string.IsNullOrEmpty(_mergedCells[i])) {
-        ExcelAddressBase addr = new(_mergedCells[i]),
-            newAddr;
-        if (delete) {
-          newAddr = addr.DeleteRow(row, rows);
-          if (newAddr == null) {
-            removeIndex.Add(i);
-            continue;
-          }
-        } else {
-          newAddr = addr.AddRow(row, rows);
-          if (newAddr.Address != addr.Address) {
-            //    _mergedCells._cells.Insert(row, 0, rows, 0);
-            _mergedCells.SetIndex(newAddr, i);
-          }
-        }
-
-        if (newAddr.Address != addr.Address) {
-          _mergedCells.List[i] = newAddr._address;
-        }
-      }
-    }
-    for (int i = removeIndex.Count - 1; i >= 0; i--) {
-      _mergedCells.List.RemoveAt(removeIndex[i]);
-    }
-  }
-
-  /// <summary>
-  /// Adds a value to the row of merged cells to fix for inserts or deletes
-  /// </summary>
-  /// <param name="column"></param>
-  /// <param name="columns"></param>
-  /// <param name="delete"></param>
-  private void FixMergedCellsColumn(int column, int columns, bool delete) {
-    if (delete) {
-      _mergedCells._cells.Delete(0, column, 0, columns);
-    } else {
-      _mergedCells._cells.Insert(0, column, 0, columns);
-    }
-    List<int> removeIndex = new List<int>();
-    for (int i = 0; i < _mergedCells.Count; i++) {
-      if (!string.IsNullOrEmpty(_mergedCells[i])) {
-        ExcelAddressBase addr = new(_mergedCells[i]),
-            newAddr;
-        if (delete) {
-          newAddr = addr.DeleteColumn(column, columns);
-          if (newAddr == null) {
-            removeIndex.Add(i);
-            continue;
-          }
-        } else {
-          newAddr = addr.AddColumn(column, columns);
-          if (newAddr.Address != addr.Address) {
-            _mergedCells.SetIndex(newAddr, i);
-          }
-        }
-
-        if (newAddr.Address != addr.Address) {
-          _mergedCells.List[i] = newAddr._address;
-        }
-      }
-    }
-    for (int i = removeIndex.Count - 1; i >= 0; i--) {
-      _mergedCells.List.RemoveAt(removeIndex[i]);
-    }
-  }
-
-  /// <summary>
-  /// Delete the specified row from the worksheet.
-  /// </summary>
-  /// <param name="row">A row to be deleted</param>
-  public void DeleteRow(int row) {
-    DeleteRow(row, 1);
-  }
-
-  /// <summary>
-  /// Delete the specified row from the worksheet.
-  /// </summary>
-  /// <param name="rowFrom">The start row</param>
-  /// <param name="rows">Number of rows to delete</param>
-  public void DeleteRow(int rowFrom, int rows) {
-    CheckSheetType();
-    if (rowFrom < 1 || rowFrom + rows > ExcelPackage.MaxRows) {
-      throw (new ArgumentException(
-              "Row out of range. Spans from 1 to "
-                  + ExcelPackage.MaxRows.ToString(CultureInfo.InvariantCulture)));
-    }
-    _values.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
-    _types.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
-    _formulas.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
-    _styles.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
-    _flags.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
-    _commentsStore.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
-    _hyperLinks.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
-
-    AdjustFormulasRow(rowFrom, rows);
-    FixMergedCellsRow(rowFrom, rows, true);
-
-    foreach (var tbl in Tables) {
-      tbl.Address = tbl.Address.DeleteRow(rowFrom, rows);
-    }
-  }
-
-  /// <summary>
-  /// Delete the specified column from the worksheet.
-  /// </summary>
-  /// <param name="column">The column to be deleted</param>
-  public void DeleteColumn(int column) {
-    DeleteColumn(column, 1);
-  }
-
-  /// <summary>
-  /// Delete the specified column from the worksheet.
-  /// </summary>
-  /// <param name="columnFrom">The start column</param>
-  /// <param name="columns">Number of columns to delete</param>
-  public void DeleteColumn(int columnFrom, int columns) {
-    if (columnFrom < 1 || columnFrom + columns > ExcelPackage.MaxColumns) {
-      throw (new ArgumentException(
-              "Column out of range. Spans from 1 to "
-                  + ExcelPackage.MaxColumns.ToString(CultureInfo.InvariantCulture)));
-    }
-    var col = _values.GetValue(0, columnFrom) as ExcelColumn;
-    if (col == null) {
-      var r = 0;
-      var c = columnFrom;
-      if (_values.PrevCell(ref r, ref c)) {
-        col = _values.GetValue(0, c) as ExcelColumn;
-        if (col._columnMax >= columnFrom) {
-          col.ColumnMax = columnFrom - 1;
-        }
-      }
-    }
-
-    _values.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
-    _types.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
-    _formulas.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
-    _styles.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
-    _flags.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
-    _commentsStore.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
-    _hyperLinks.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
-
-    AdjustFormulasColumn(columnFrom, columns);
-    FixMergedCellsColumn(columnFrom, columns, true);
-
-    var csec = new CellsStoreEnumerator<object>(_values, 0, columnFrom, 0, ExcelPackage.MaxColumns);
-    foreach (var column in csec) {
-      if (column is ExcelColumn excelColumn) {
-        if (excelColumn._columnMin >= columnFrom) {
-          excelColumn._columnMin -= columns;
-          excelColumn._columnMax -= columns;
-        }
-      }
-    }
-
-    foreach (var tbl in Tables) {
-      if (columnFrom >= tbl.Address.Start.Column && columnFrom <= tbl.Address.End.Column) {
-        var node = tbl.Columns[0].TopNode.ParentNode;
-        var ix = columnFrom - tbl.Address.Start.Column;
-        for (int i = 0; i < columns; i++) {
-          if (node.ChildNodes.Count > ix) {
-            node.RemoveChild(node.ChildNodes[ix]);
-          }
-        }
-        tbl._cols = new(tbl);
-      }
-
-      tbl.Address = tbl.Address.DeleteColumn(columnFrom, columns);
-    }
-  }
-
-  internal void AdjustFormulasRow(int rowFrom, int rows) {
-    var delSf = new List<int>();
-    foreach (var sf in _sharedFormulas.Values) {
-      var a = new ExcelAddress(sf.Address).DeleteRow(rowFrom, rows);
-      if (a == null) {
-        delSf.Add(sf.Index);
-      } else {
-        sf.Address = a.Address;
-        if (sf.StartRow > rowFrom) {
-          var r = Math.Min(sf.StartRow - rowFrom, rows);
-          sf.Formula = ExcelCellBase.UpdateFormulaReferences(sf.Formula, -r, 0, rowFrom, 0);
-          sf.StartRow -= r;
-        }
-      }
-    }
-    foreach (var ix in delSf) {
-      _sharedFormulas.Remove(ix);
-    }
-    var cse = new CellsStoreEnumerator<object>(
-        _formulas,
-        1,
-        1,
-        ExcelPackage.MaxRows,
-        ExcelPackage.MaxColumns);
-    while (cse.Next()) {
-      if (cse.Value is string) {
-        cse.Value = ExcelCellBase.UpdateFormulaReferences(
-            cse.Value.ToString(),
-            -rows,
-            0,
-            rowFrom,
-            0);
-      }
-    }
-  }
-
-  internal void AdjustFormulasColumn(int columnFrom, int columns) {
-    var delSf = new List<int>();
-    foreach (var sf in _sharedFormulas.Values) {
-      var a = new ExcelAddress(sf.Address).DeleteColumn(columnFrom, columns);
-      if (a == null) {
-        delSf.Add(sf.Index);
-      } else {
-        sf.Address = a.Address;
-        if (sf.StartCol > columnFrom) {
-          var c = Math.Min(sf.StartCol - columnFrom, columns);
-          sf.Formula = ExcelCellBase.UpdateFormulaReferences(sf.Formula, 0, -c, 0, 1);
-          sf.StartCol -= c;
-        }
-      }
-    }
-    foreach (var ix in delSf) {
-      _sharedFormulas.Remove(ix);
-    }
-    var cse = new CellsStoreEnumerator<object>(
-        _formulas,
-        1,
-        1,
-        ExcelPackage.MaxRows,
-        ExcelPackage.MaxColumns);
-    while (cse.Next()) {
-      if (cse.Value is string) {
-        cse.Value = ExcelCellBase.UpdateFormulaReferences(
-            cse.Value.ToString(),
-            0,
-            -columns,
-            0,
-            columnFrom);
-      }
-    }
-  }
-
-  /// <summary>
-  /// Deletes the specified row from the worksheet.
-  /// </summary>
-  /// <param name="rowFrom">The number of the start row to be deleted</param>
-  /// <param name="rows">Number of rows to delete</param>
-  /// <param name="shiftOtherRowsUp">Not used. Rows are always shifted</param>
-  public void DeleteRow(int rowFrom, int rows, bool shiftOtherRowsUp) {
-    DeleteRow(rowFrom, rows);
-  }
-
-  /// <summary>
-  /// Get the cell value from thw worksheet
-  /// </summary>
-  /// <param name="row">The row number</param>
-  /// <param name="column">The row number</param>
-  /// <returns>The value</returns>
-  public object GetValue(int row, int column) {
-    CheckSheetType();
-    var v = _values.GetValue(row, column);
-    if (v != null) {
-      if (_flags.GetFlagValue(row, column, CellFlags.RichText)) {
-        return Cells[row, column].RichText.Text;
-      }
-      return v;
-    }
-    return null;
-  }
-
-  /// <summary>
-  /// Get a strongly typed cell value from the worksheet
-  /// </summary>
-  /// <typeparam name="T">The type</typeparam>
-  /// <param name="row">The row number</param>
-  /// <param name="column">The row number</param>
-  /// <returns>The value. If the value can't be converted to the specified type, the default value will be returned</returns>
-  public T GetValue<T>(int row, int column) {
-    CheckSheetType();
-    //ulong cellID=ExcelCellBase.GetCellID(SheetID, Row, Column);
-    var v = _values.GetValue(row, column);
-    if (v == null) {
-      return default(T);
-    }
-
-    //var cell=((ExcelCell)_cells[cellID]);
-    if (_flags.GetFlagValue(row, column, CellFlags.RichText)) {
-      return (T)(object)Cells[row, column].RichText.Text;
-    }
-    return GetTypedValue<T>(v);
-  }
-
-  //Thanks to Michael Tran for parts of this method
-  internal T GetTypedValue<T>(object v) {
-    if (v == null) {
-      return default(T);
-    }
-    Type fromType = v.GetType();
-    Type toType = typeof(T);
-    if (fromType == toType) {
-      return (T)v;
-    }
-    var cnv = TypeDescriptor.GetConverter(fromType);
-    if (toType
-        == typeof(DateTime)) //Handle dates
-    {
-      if (fromType == typeof(TimeSpan)) {
-        return ((T)(object)(new DateTime(((TimeSpan)v).Ticks)));
-      }
-      if (fromType == typeof(string)) {
-        if (DateTime.TryParse(v.ToString(), out var dt)) {
-          return (T)(object)(dt);
-        }
-        return default(T);
-      }
-      if (cnv.CanConvertTo(typeof(double))) {
-        return (T)(object)(DateTime.FromOADate((double)cnv.ConvertTo(v, typeof(double))));
-      }
-      return default(T);
-    }
-    if (toType
-        == typeof(TimeSpan)) //Handle timespan
-    {
-      if (fromType == typeof(DateTime)) {
-        return ((T)(object)(new TimeSpan(((DateTime)v).Ticks)));
-      }
-      if (fromType == typeof(string)) {
-        if (TimeSpan.TryParse(v.ToString(), out var ts)) {
-          return (T)(object)(ts);
-        }
-        return default(T);
-      }
-      if (cnv.CanConvertTo(typeof(double))) {
-        return (T)
-          (object)(new TimeSpan(
-              DateTime.FromOADate((double)cnv.ConvertTo(v, typeof(double))).Ticks));
-      }
-      try {
-        // Issue 14682 -- "GetValue<decimal>() won't convert strings"
-        // As suggested, after all special cases, all .NET to do it's
-        // preferred conversion rather than simply returning the default
-        return (T)Convert.ChangeType(v, typeof(T));
-      } catch (Exception) {
-        // This was the previous behaviour -- no conversion is available.
-        return default(T);
-      }
-    }
-    if (cnv.CanConvertTo(toType)) {
-      return (T)cnv.ConvertTo(v, typeof(T));
-    }
-    if (toType.IsGenericType && toType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) {
-      toType = Nullable.GetUnderlyingType(toType);
-      if (cnv.CanConvertTo(toType)) {
-        return (T)cnv.ConvertTo(v, typeof(T));
-      }
-    }
-
-    if (fromType == typeof(double) && toType == typeof(decimal)) {
-      return (T)(object)Convert.ToDecimal(v);
-    }
-    if (fromType == typeof(decimal) && toType == typeof(double)) {
-      return (T)(object)Convert.ToDouble(v);
-    }
-    return default(T);
-  }
-
-  /// <summary>
-  /// Set the value of a cell
-  /// </summary>
-  /// <param name="row">The row number</param>
-  /// <param name="column">The column number</param>
-  /// <param name="value">The value</param>
-  public void SetValue(int row, int column, object value) {
-    CheckSheetType();
-    if (row < 1 || column < 1 || row > ExcelPackage.MaxRows && column > ExcelPackage.MaxColumns) {
-      throw new ArgumentOutOfRangeException("Row or Column out of range");
-    }
-    _values.SetValue(row, column, value);
-  }
-
-  /// <summary>
-  /// Set the value of a cell
-  /// </summary>
-  /// <param name="address">The Excel address</param>
-  /// <param name="value">The value</param>
-  public void SetValue(string address, object value) {
-    CheckSheetType();
-    ExcelCellBase.GetRowCol(address, out var row, out var col, true);
-    if (row < 1 || col < 1 || row > ExcelPackage.MaxRows && col > ExcelPackage.MaxColumns) {
-      throw new ArgumentOutOfRangeException("Address is invalid or out of range");
-    }
-    _values.SetValue(row, col, value);
-  }
-
-  /// <summary>
-  /// Get MergeCell Index No
-  /// </summary>
-  /// <param name="row"></param>
-  /// <param name="column"></param>
-  /// <returns></returns>
-  public int GetMergeCellId(int row, int column) {
-    for (int i = 0; i < _mergedCells.Count; i++) {
-      if (!string.IsNullOrEmpty(_mergedCells[i])) {
-        ExcelRange range = Cells[_mergedCells[i]];
-
-        if (range.Start.Row <= row && row <= range.End.Row) {
-          if (range.Start.Column <= column && column <= range.End.Column) {
-            return i + 1;
-          }
-        }
-      }
-    }
-    return 0;
-  }
-
-  internal void Save() {
-    DeletePrinterSettings();
-    if (!(this is ExcelChartsheet)) {
-      var d = Dimension;
-      if (d == null) {
-        DeleteAllNode("d:dimension/@ref");
-      } else {
-        SetXmlNodeString("d:dimension/@ref", d.Address);
-      }
-      SaveTables();
-      SavePivotTables();
-    }
-  }
-
-  internal void SaveHandler(StreamWriter streamWriter) {
-    //Create the nodes if they do not exist.
-    if (this is ExcelChartsheet) {
-      streamWriter.Write(WorksheetXml.OuterXml);
-    } else {
-      CreateNode("d:cols");
-      CreateNode("d:sheetData");
-      CreateNode("d:mergeCells");
-      CreateNode("d:hyperlinks");
-      CreateNode("d:rowBreaks");
-      CreateNode("d:colBreaks");
-
-      //StreamWriter sw=new StreamWriter(Part.GetStream(FileMode.Create, FileAccess.Write));
-      var xml = WorksheetXml.OuterXml;
-      int colStart = 0,
-          colEnd = 0;
-      GetBlockPos(xml, "cols", ref colStart, ref colEnd);
-
-      streamWriter.Write(xml.Substring(0, colStart));
-      UpdateColumnData(streamWriter);
-
-      int cellStart = colEnd,
-          cellEnd = colEnd;
-      GetBlockPos(xml, "sheetData", ref cellStart, ref cellEnd);
-
-      streamWriter.Write(xml.Substring(colEnd, cellStart - colEnd));
-      UpdateRowCellData(streamWriter);
-
-      int mergeStart = cellEnd,
-          mergeEnd = cellEnd;
-
-      GetBlockPos(xml, "mergeCells", ref mergeStart, ref mergeEnd);
-      streamWriter.Write(xml.Substring(cellEnd, mergeStart - cellEnd));
-
-      CleanupMergedCells(_mergedCells);
-      if (_mergedCells.Count > 0) {
-        UpdateMergedCells(streamWriter);
-      }
-
-      int hyperStart = mergeEnd,
-          hyperEnd = mergeEnd;
-      GetBlockPos(xml, "hyperlinks", ref hyperStart, ref hyperEnd);
-      streamWriter.Write(xml.Substring(mergeEnd, hyperStart - mergeEnd));
-      UpdateHyperLinks(streamWriter);
-
-      int rowBreakStart = hyperEnd,
-          rowBreakEnd = hyperEnd;
-      GetBlockPos(xml, "rowBreaks", ref rowBreakStart, ref rowBreakEnd);
-      streamWriter.Write(xml.Substring(hyperEnd, rowBreakStart - hyperEnd));
-      UpdateRowBreaks(streamWriter);
-
-      int colBreakStart = rowBreakEnd,
-          colBreakEnd = rowBreakEnd;
-      GetBlockPos(xml, "colBreaks", ref colBreakStart, ref colBreakEnd);
-      streamWriter.Write(xml.Substring(rowBreakEnd, colBreakStart - rowBreakEnd));
-      UpdateColBreaks(streamWriter);
-      streamWriter.Write(xml.Substring(colBreakEnd, xml.Length - colBreakEnd));
-    }
-  }
-
-  /// <summary>
-  /// Delete the printersettings relationship and part.
-  /// </summary>
-  private void DeletePrinterSettings() {
-    //Delete the relationship from the pageSetup tag
-    XmlAttribute attr = (XmlAttribute)
-      WorksheetXml.SelectSingleNode("//d:pageSetup/@r:id", NameSpaceManager);
-    if (attr != null) {
-      string relId = attr.Value;
-      //First delete the attribute from the XML
-      attr.OwnerElement.Attributes.Remove(attr);
-      if (Part.RelationshipExists(relId)) {
-        var rel = Part.GetRelationship(relId);
-        Uri printerSettingsUri = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri);
-        Part.DeleteRelationship(rel.Id);
-
-        //Delete the part from the package
-        if (_package.Package.PartExists(printerSettingsUri)) {
-          _package.Package.DeletePart(printerSettingsUri);
-        }
-      }
-    }
-  }
-
-  /// <summary>
-  /// Save all table data
-  /// </summary>
-  private void SaveTables() {
-    foreach (var tbl in Tables) {
-      if (tbl.ShowHeader || tbl.ShowTotal) {
-        int colNum = tbl.Address._fromCol;
-        var colVal = new HashSet<string>();
-        foreach (var col in tbl.Columns) {
-          string n = col.Name.ToLower(CultureInfo.InvariantCulture);
-          if (tbl.ShowHeader) {
-            n = tbl.WorkSheet.GetValue<string>(
-                tbl.Address._fromRow,
-                tbl.Address._fromCol + col.Position);
-            if (string.IsNullOrEmpty(n)) {
-              n = col.Name.ToLower(CultureInfo.InvariantCulture);
-            } else {
-              col.Name = n;
-            }
-          } else {
-            n = col.Name.ToLower(CultureInfo.InvariantCulture);
-          }
-
-          if (colVal.Contains(n)) {
-            throw (new InvalidDataException(
-                    string.Format(
-                        "Table {0} Column {1} does not have a unique name.",
-                        tbl.Name,
-                        col.Name)));
-          }
-          colVal.Add(n);
-          col.Name = ConvertUtil.ExcelEncodeString(col.Name);
-          if (tbl.ShowHeader) {
-            _values.SetValue(tbl.Address._fromRow, colNum, col.Name);
-          }
-          if (tbl.ShowTotal) {
-            SetTableTotalFunction(tbl, col, colNum);
-          }
-          if (!string.IsNullOrEmpty(col.CalculatedColumnFormula)) {
-            int fromRow = tbl.ShowHeader ? tbl.Address._fromRow + 1 : tbl.Address._fromRow;
-            int toRow = tbl.ShowTotal ? tbl.Address._toRow - 1 : tbl.Address._toRow;
-            for (int row = fromRow; row <= toRow; row++) {
-              //Cell(row, colNum).Formula = col.CalculatedColumnFormula;
-              SetFormula(row, colNum, col.CalculatedColumnFormula);
-            }
-          }
-          colNum++;
-        }
-      }
-    }
-  }
-
-  internal void SetTableTotalFunction(ExcelTable tbl, ExcelTableColumn col, int colNum = -1) {
-    if (tbl.ShowTotal == false) {
-      return;
-    }
-    if (colNum == -1) {
-      for (int i = 0; i < tbl.Columns.Count; i++) {
-        if (tbl.Columns[i].Name == col.Name) {
-          colNum = tbl.Address._fromCol + i;
-        }
-      }
-    }
-    if (col.TotalsRowFunction == RowFunctions.Custom) {
-      SetFormula(tbl.Address._toRow, colNum, col.TotalsRowFormula);
-    } else if (col.TotalsRowFunction != RowFunctions.None) {
-      switch (col.TotalsRowFunction) {
-        case RowFunctions.Average:
-          SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "101"));
-          break;
-        case RowFunctions.Count:
-          SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "102"));
-          break;
-        case RowFunctions.CountNums:
-          SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "103"));
-          break;
-        case RowFunctions.Max:
-          SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "104"));
-          break;
-        case RowFunctions.Min:
-          SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "105"));
-          break;
-        case RowFunctions.StdDev:
-          SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "107"));
-          break;
-        case RowFunctions.Var:
-          SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "110"));
-          break;
-        case RowFunctions.Sum:
-          SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "109"));
-          break;
-        default:
-          throw (new("Unknown RowFunction enum"));
-      }
-    } else {
-      _values.SetValue(tbl.Address._toRow, colNum, col.TotalsRowLabel);
-    }
-  }
-
-  internal void SetFormula(int row, int col, object value) {
-    _formulas.SetValue(row, col, value);
-    if (!_values.Exists(row, col)) {
-      _values.SetValue(row, col, null);
-    }
-  }
-
-  internal void SetStyle(int row, int col, int value) {
-    _styles.SetValue(row, col, value);
-    if (!_values.Exists(row, col)) {
-      _values.SetValue(row, col, null);
-    }
-  }
-
-  private void SavePivotTables() {
-    foreach (var pt in PivotTables) {
-      if (pt.DataFields.Count > 1) {
-        XmlElement parentNode;
-        if (pt.DataOnRows) {
-          parentNode =
-              pt.PivotTableXml.SelectSingleNode("//d:rowFields", pt.NameSpaceManager) as XmlElement;
-          if (parentNode == null) {
-            pt.CreateNode("d:rowFields");
-            parentNode =
-                pt.PivotTableXml.SelectSingleNode("//d:rowFields", pt.NameSpaceManager)
-                    as XmlElement;
-          }
-        } else {
-          parentNode =
-              pt.PivotTableXml.SelectSingleNode("//d:colFields", pt.NameSpaceManager) as XmlElement;
-          if (parentNode == null) {
-            pt.CreateNode("d:colFields");
-            parentNode =
-                pt.PivotTableXml.SelectSingleNode("//d:colFields", pt.NameSpaceManager)
-                    as XmlElement;
-          }
-        }
-
-        if (parentNode.SelectSingleNode("d:field[@ x= \"-2\"]", pt.NameSpaceManager) == null) {
-          XmlElement fieldNode = pt.PivotTableXml.CreateElement("field", ExcelPackage._schemaMain);
-          fieldNode.SetAttribute("x", "-2");
-          parentNode.AppendChild(fieldNode);
-        }
-      }
-      var ws = Workbook.Worksheets[pt.CacheDefinition.SourceRange.WorkSheet];
-      var t = ws.Tables.GetFromRange(pt.CacheDefinition.SourceRange);
-      var fields = pt.CacheDefinition.CacheDefinitionXml.SelectNodes(
-          "d:pivotCacheDefinition/d:cacheFields/d:cacheField",
-          NameSpaceManager);
-      int ix = 0;
-      if (fields != null) {
-        var flds = new HashSet<string>();
-        foreach (XmlElement node in fields) {
-          if (ix >= pt.CacheDefinition.SourceRange.Columns) {
-            break;
-          }
-          var fldName = node.GetAttribute("name"); //Fixes issue 15295 dup name error
-          if (string.IsNullOrEmpty(fldName)) {
-            fldName =
-                (t == null
-                    ? pt.CacheDefinition.SourceRange.Offset(0, ix++, 1, 1).Value.ToString()
-                    : t.Columns[ix++].Name);
-          }
-          if (flds.Contains(fldName)) {
-            fldName = GetNewName(flds, fldName);
-          }
-          flds.Add(fldName);
-          node.SetAttribute("name", fldName);
-        }
-        foreach (var df in pt.DataFields) {
-          if (string.IsNullOrEmpty(df.Name)) {
-            string name;
-            if (df.Function == DataFieldFunctions.None) {
-              name = df.Field.Name; //Name must be set or Excel will crash on rename.
-            } else {
-              name = df.Function + " of " + df.Field.Name; //Name must be set or Excel will crash on rename.
-            }
-            //Make sure name is unique
-            var newName = name;
-            var i = 2;
-            while (pt.DataFields.ExistsDfName(newName, df)) {
-              newName = name + (i++).ToString(CultureInfo.InvariantCulture);
-            }
-            df.Name = newName;
-          }
-        }
-      }
-    }
-  }
-
-  private string GetNewName(HashSet<string> flds, string fldName) {
-    int ix = 2;
-    while (flds.Contains(fldName + ix.ToString(CultureInfo.InvariantCulture))) {
-      ix++;
-    }
-    return fldName + ix.ToString(CultureInfo.InvariantCulture);
-  }
-
-  private static string GetTotalFunction(ExcelTableColumn col, string functionNum) {
-    return string.Format("SUBTOTAL({0},{1}[{2}])", functionNum, col._tbl.Name, col.Name);
-  }
-
-  private void CleanupMergedCells(MergeCellsCollection mergedCells) {
-    int i = 0;
-    while (i < mergedCells.List.Count) {
-      if (mergedCells[i] == null) {
-        mergedCells.List.RemoveAt(i);
-      } else {
-        i++;
-      }
-    }
-  }
-
-  private void UpdateColBreaks(StreamWriter sw) {
-    StringBuilder breaks = new StringBuilder();
-    int count = 0;
-    var cse = new CellsStoreEnumerator<object>(_values, 0, 0, 0, ExcelPackage.MaxColumns);
-    while (cse.Next()) {
-      var col = cse.Value as ExcelColumn;
-      if (col != null && col.PageBreak) {
-        breaks.AppendFormat("<brk id=\"{0}\" max=\"16383\" man=\"1\" />", cse.Column);
-        count++;
-      }
-    }
-    if (count > 0) {
-      sw.Write("<colBreaks count=\"{0}\" manualBreakCount=\"{0}\">{1}</colBreaks>", count, breaks);
-    }
-  }
-
-  private void UpdateRowBreaks(StreamWriter sw) {
-    StringBuilder breaks = new StringBuilder();
-    int count = 0;
-    var cse = new CellsStoreEnumerator<object>(_values, 0, 0, ExcelPackage.MaxRows, 0);
-    //foreach(ExcelRow row in _rows)
-    while (cse.Next()) {
-      var row = cse.Value as RowInternal;
-      if (row != null && row.PageBreak) {
-        breaks.AppendFormat("<brk id=\"{0}\" max=\"1048575\" man=\"1\" />", cse.Row);
-        count++;
-      }
-    }
-    if (count > 0) {
-      sw.Write("<rowBreaks count=\"{0}\" manualBreakCount=\"{0}\">{1}</rowBreaks>", count, breaks);
-    }
-  }
-
-  /// <summary>
-  /// Inserts the cols collection into the XML document
-  /// </summary>
-  private void UpdateColumnData(StreamWriter sw) {
-    var cse = new CellsStoreEnumerator<object>(_values, 0, 1, 0, ExcelPackage.MaxColumns);
-    bool first = true;
-    while (cse.Next()) {
-      if (first) {
-        sw.Write("<cols>");
-        first = false;
-      }
-      var col = cse.Value as ExcelColumn;
-      ExcelStyleCollection<ExcelXfs> cellXfs = _workbook.Styles.CellXfs;
-
-      sw.Write("<col min=\"{0}\" max=\"{1}\"", col.ColumnMin, col.ColumnMax);
-      if (col.Hidden) {
-        //sbXml.Append(" width=\"0\" hidden=\"1\" customWidth=\"1\"");
-        sw.Write(" hidden=\"1\"");
-      } else if (col.BestFit) {
-        sw.Write(" bestFit=\"1\"");
-      }
-      sw.Write(
-          string.Format(
-              CultureInfo.InvariantCulture,
-              " width=\"{0}\" customWidth=\"1\"",
-              col.Width));
-      if (col.OutlineLevel > 0) {
-        sw.Write(" outlineLevel=\"{0}\" ", col.OutlineLevel);
-        if (col.Collapsed) {
-          if (col.Hidden) {
-            sw.Write(" collapsed=\"1\"");
-          } else {
-            sw.Write(" collapsed=\"1\" hidden=\"1\""); //Always hidden
-          }
-        }
-      }
-      if (col.Phonetic) {
-        sw.Write(" phonetic=\"1\"");
-      }
-
-      var styleId = col.StyleID >= 0 ? cellXfs[col.StyleID].newID : col.StyleID;
-      if (styleId > 0) {
-        sw.Write(" style=\"{0}\"", styleId);
-      }
-      sw.Write(" />");
-    }
-    if (!first) {
-      sw.Write("</cols>");
-    }
-  }
-
-  /// <summary>
-  /// Insert row and cells into the XML document
-  /// </summary>
-  private void UpdateRowCellData(StreamWriter sw) {
-    ExcelStyleCollection<ExcelXfs> cellXfs = _workbook.Styles.CellXfs;
-
-    int row = -1;
-
-    var ss = _workbook._sharedStrings;
-    var styles = _workbook.Styles;
-    var cache = new StringBuilder();
-    cache.Append("<sheetData>");
-
-    //Set a value for cells with style and no value set.
-    var cseStyle = new CellsStoreEnumerator<int>(
-        _styles,
-        0,
-        0,
-        ExcelPackage.MaxRows,
-        ExcelPackage.MaxColumns);
-    foreach (var s in cseStyle) {
-      if (!_values.Exists(cseStyle.Row, cseStyle.Column)) {
-        _values.SetValue(cseStyle.Row, cseStyle.Column, null);
-      }
-    }
-
-    var cse = new CellsStoreEnumerator<object>(
-        _values,
-        1,
-        0,
-        ExcelPackage.MaxRows,
-        ExcelPackage.MaxColumns);
-    //foreach (IRangeID r in _cells)
-    while (cse.Next()) {
-      if (cse.Column > 0) {
-        int styleId = cellXfs[styles.GetStyleId(this, cse.Row, cse.Column)].newID;
-        //Add the row element if it's a new row
-        if (cse.Row != row) {
-          WriteRow(cache, cellXfs, row, cse.Row);
-          row = cse.Row;
-        }
-        object v = cse.Value;
-        object formula = _formulas.GetValue(cse.Row, cse.Column);
-        if (formula is int sfId) {
-          var f = _sharedFormulas[sfId];
-          if (f.Address.IndexOf(':') > 0) {
-            if (f.StartCol == cse.Column && f.StartRow == cse.Row) {
-              if (f.IsArray) {
-                cache.AppendFormat(
-                    "<c r=\"{0}\" s=\"{1}\"{5}><f ref=\"{2}\" t=\"array\">{3}</f>{4}</c>",
-                    cse.CellAddress,
-                    styleId < 0 ? 0 : styleId,
-                    f.Address,
-                    SecurityElement.Escape(f.Formula),
-                    GetFormulaValue(v),
-                    GetCellType(v, true));
-              } else {
-                cache.AppendFormat(
-                    "<c r=\"{0}\" s=\"{1}\"{6}><f ref=\"{2}\" t=\"shared\"  si=\"{3}\">{4}</f>{5}</c>",
-                    cse.CellAddress,
-                    styleId < 0 ? 0 : styleId,
-                    f.Address,
-                    sfId,
-                    SecurityElement.Escape(f.Formula),
-                    GetFormulaValue(v),
-                    GetCellType(v, true));
-              }
-            } else if (f.IsArray) {
-              cache.AppendFormat(
-                  "<c r=\"{0}\" s=\"{1}\" />",
-                  cse.CellAddress,
-                  styleId < 0 ? 0 : styleId);
-            } else {
-              cache.AppendFormat(
-                  "<c r=\"{0}\" s=\"{1}\"{4}><f t=\"shared\" si=\"{2}\" />{3}</c>",
-                  cse.CellAddress,
-                  styleId < 0 ? 0 : styleId,
-                  sfId,
-                  GetFormulaValue(v),
-                  GetCellType(v, true));
-            }
-          } else {
-            // We can also have a single cell array formula
-            if (f.IsArray) {
-              cache.AppendFormat(
-                  "<c r=\"{0}\" s=\"{1}\"{5}><f ref=\"{2}\" t=\"array\">{3}</f>{4}</c>",
-                  cse.CellAddress,
-                  styleId < 0 ? 0 : styleId,
-                  string.Format("{0}:{1}", f.Address, f.Address),
-                  SecurityElement.Escape(f.Formula),
-                  GetFormulaValue(v),
-                  GetCellType(v, true));
-            } else {
-              cache.AppendFormat("<c r=\"{0}\" s=\"{1}\">", f.Address, styleId < 0 ? 0 : styleId);
-              cache.AppendFormat(
-                  "<f>{0}</f>{1}</c>",
-                  SecurityElement.Escape(f.Formula),
-                  GetFormulaValue(v));
-            }
-          }
-        } else if (formula != null && formula.ToString() != "") {
-          cache.AppendFormat(
-              "<c r=\"{0}\" s=\"{1}\"{2}>",
-              cse.CellAddress,
-              styleId < 0 ? 0 : styleId,
-              GetCellType(v, true));
-          cache.AppendFormat(
-              "<f>{0}</f>{1}</c>",
-              SecurityElement.Escape(formula.ToString()),
-              GetFormulaValue(v));
-        } else {
-          if (v == null && styleId > 0) {
-            cache.AppendFormat(
-                "<c r=\"{0}\" s=\"{1}\" />",
-                cse.CellAddress,
-                styleId < 0 ? 0 : styleId);
-          } else if (v != null) {
-            if ((v.GetType().IsPrimitive
-                        || v is double
-                        || v is decimal
-                        || v is DateTime
-                        || v is TimeSpan)) {
-              //string sv = GetValueForXml(v);
-              cache.AppendFormat(
-                  "<c r=\"{0}\" s=\"{1}\" {2}>",
-                  cse.CellAddress,
-                  styleId < 0 ? 0 : styleId,
-                  GetCellType(v));
-              cache.AppendFormat("{0}</c>", GetFormulaValue(v));
-            } else {
-              int ix;
-              if (!ss.ContainsKey(v.ToString())) {
-                ix = ss.Count;
-                ss.Add(
-                    v.ToString(),
-                    new() {
-                      isRichText = _flags.GetFlagValue(cse.Row, cse.Column, CellFlags.RichText),
-                      pos = ix,
-                    });
-              } else {
-                ix = ss[v.ToString()].pos;
-              }
-              cache.AppendFormat(
-                  "<c r=\"{0}\" s=\"{1}\" t=\"s\">",
-                  cse.CellAddress,
-                  styleId < 0 ? 0 : styleId);
-              cache.AppendFormat("<v>{0}</v></c>", ix);
-            }
-          }
-        }
-      } else //ExcelRow
-      {
-        WriteRow(cache, cellXfs, row, cse.Row);
-        row = cse.Row;
-      }
-      if (cache.Length > 0x600000) {
-        sw.Write(cache.ToString());
-        cache = new();
-      }
-    }
-
-    if (row != -1) {
-      cache.Append("</row>");
-    }
-    cache.Append("</sheetData>");
-    sw.Write(cache.ToString());
-    sw.Flush();
-  }
-
-  private object GetFormulaValue(object v) {
-    if (v != null && v.ToString() != "") {
-      return "<v>" + SecurityElement.Escape(GetValueForXml(v)) + "</v>"; //Fixes issue 15071
-    }
-    return "";
-  }
-
-  private string GetCellType(object v, bool allowStr = false) {
-    if (v is bool) {
-      return " t=\"b\"";
-    }
-    if ((v is double d && double.IsInfinity(d)) || v is ExcelErrorValue) {
-      return " t=\"e\"";
-    }
-    if (allowStr
-        && v != null
-        && !(v.GetType().IsPrimitive
-                || v is double
-                || v is decimal
-                || v is DateTime
-                || v is TimeSpan)) {
-      return " t=\"str\"";
-    }
-    return "";
-  }
-
-  private string GetValueForXml(object v) {
-    string s;
-    try {
-      if (v is DateTime time) {
-        double sdv = time.ToOADate();
-
-        if (Workbook.Date1904) {
-          sdv -= ExcelWorkbook._date1904Offset;
-        }
-
-        s = sdv.ToString(CultureInfo.InvariantCulture);
-      } else if (v is TimeSpan span) {
-        s = new DateTime(span.Ticks).ToOADate().ToString(CultureInfo.InvariantCulture);
-        ;
-      } else if (v.GetType().IsPrimitive || v is double || v is decimal) {
-        if (v is double d && double.IsNaN(d)) {
-          s = "";
-        } else if (v is double d1 && double.IsInfinity(d1)) {
-          s = "#NUM!";
-        } else {
-          s = Convert
-              .ToDouble(v, CultureInfo.InvariantCulture)
-              .ToString("R15", CultureInfo.InvariantCulture);
-        }
-      } else {
-        s = v.ToString();
-      }
-    } catch {
-      s = "0";
-    }
-    return s;
-  }
-
-  private void WriteRow(
-      StringBuilder cache,
-      ExcelStyleCollection<ExcelXfs> cellXfs,
-      int prevRow,
-      int row) {
-    if (prevRow != -1) {
-      cache.Append("</row>");
-    }
-    //ulong rowID = ExcelRow.GetRowID(SheetID, row);
-    cache.AppendFormat("<row r=\"{0}\" ", row);
-    RowInternal currRow = _values.GetValue(row, 0) as RowInternal;
-    if (currRow != null) {
-      if (currRow.Hidden) {
-        cache.Append("ht=\"0\" hidden=\"1\" ");
-      } else if (currRow.Height != DefaultRowHeight && currRow.Height >= 0) {
-        cache.AppendFormat(CultureInfo.InvariantCulture, "ht=\"{0}\" ", currRow.Height);
-        if (currRow.CustomHeight) {
-          cache.Append("customHeight=\"1\" ");
-        }
-      }
-
-      if (currRow.OutlineLevel > 0) {
-        cache.AppendFormat("outlineLevel =\"{0}\" ", currRow.OutlineLevel);
-        if (currRow.Collapsed) {
-          if (currRow.Hidden) {
-            cache.Append(" collapsed=\"1\" ");
-          } else {
-            cache.Append(" collapsed=\"1\" hidden=\"1\" "); //Always hidden
-          }
-        }
-      }
-      if (currRow.Phonetic) {
-        cache.Append("ph=\"1\" ");
-      }
-    }
-    var s = _styles.GetValue(row, 0);
-    if (s > 0) {
-      cache.AppendFormat("s=\"{0}\" customFormat=\"1\"", cellXfs[s].newID);
-    }
-    cache.Append(">");
-  }
-
-  /// <summary>
-  /// Update xml with hyperlinks
-  /// </summary>
-  /// <param name="sw">The stream</param>
-  private void UpdateHyperLinks(StreamWriter sw) {
-    Dictionary<string, string> hyps = new Dictionary<string, string>();
-    var cse = new CellsStoreEnumerator<Uri>(_hyperLinks);
-    bool first = true;
-    //foreach (ulong cell in _hyperLinks)
-    while (cse.Next()) {
-      if (first) {
-        sw.Write("<hyperlinks>");
-        first = false;
-      }
-      //int row, col;
-      var uri = _hyperLinks.GetValue(cse.Row, cse.Column);
-      //ExcelCell cell = _cells[cellId] as ExcelCell;
-      if (uri is ExcelHyperLink link && !string.IsNullOrEmpty(link.ReferenceAddress)) {
-        sw.Write(
-            "<hyperlink ref=\"{0}\" location=\"{1}\" {2}{3}/>",
-            Cells[cse.Row, cse.Column, cse.Row + link.RowSpann, cse.Column + link.ColSpann].Address,
-            ExcelCellBase.GetFullAddress(
-                SecurityElement.Escape(Name),
-                SecurityElement.Escape(link.ReferenceAddress)),
-            string.IsNullOrEmpty(link.Display)
-                ? ""
-                : "display=\"" + SecurityElement.Escape(link.Display) + "\" ",
-            string.IsNullOrEmpty(link.ToolTip)
-                ? ""
-                : "tooltip=\"" + SecurityElement.Escape(link.ToolTip) + "\" ");
-      } else if (uri != null) {
-        Uri hyp;
-        if (uri is ExcelHyperLink hyperLink) {
-          hyp = hyperLink.OriginalUri;
-        } else {
-          hyp = uri;
-        }
-        if (!hyps.ContainsKey(hyp.OriginalString)) {
-          var relationship = Part.CreateRelationship(
-              hyp,
-              TargetMode.External,
-              ExcelPackage._schemaHyperlink);
-          if (uri is ExcelHyperLink hl) {
-            sw.Write(
-                "<hyperlink ref=\"{0}\" {2}{3}r:id=\"{1}\" />",
-                ExcelCellBase.GetAddress(cse.Row, cse.Column),
-                relationship.Id,
-                string.IsNullOrEmpty(hl.Display)
-                    ? ""
-                    : "display=\"" + SecurityElement.Escape(hl.Display) + "\" ",
-                string.IsNullOrEmpty(hl.ToolTip)
-                    ? ""
-                    : "tooltip=\"" + SecurityElement.Escape(hl.ToolTip) + "\" ");
-          } else {
-            sw.Write(
-                "<hyperlink ref=\"{0}\" r:id=\"{1}\" />",
-                ExcelCellBase.GetAddress(cse.Row, cse.Column),
-                relationship.Id);
-          }
-        }
-      }
-    }
-    if (!first) {
-      sw.Write("</hyperlinks>");
-    }
-  }
-
-  /// <summary>
-  /// Dimension address for the worksheet.
-  /// Top left cell to Bottom right.
-  /// If the worksheet has no cells, null is returned
-  /// </summary>
-  public ExcelAddressBase Dimension {
-    get {
-      CheckSheetType();
-      if (_values.GetDimension(out var fromRow, out var fromCol, out var toRow, out var toCol)) {
-        var addr = new ExcelAddressBase(fromRow, fromCol, toRow, toCol);
-        addr._ws = Name;
-        return addr;
-      }
-      return null;
-    }
-  }
-
-  private ExcelSheetProtection _protection;
-
-  /// <summary>
-  /// Access to sheet protection properties
-  /// </summary>
-  public ExcelSheetProtection Protection {
-    get {
-      if (_protection == null) {
-        _protection = new(NameSpaceManager, TopNode);
-      }
-      return _protection;
-    }
-  }
-
-  private ExcelProtectedRangeCollection _protectedRanges;
-
-  public ExcelProtectedRangeCollection ProtectedRanges {
-    get {
-      if (_protectedRanges == null) {
-        _protectedRanges = new(NameSpaceManager, TopNode);
-      }
-      return _protectedRanges;
-    }
-  }
-
-  private ExcelTableCollection _tables;
-
-  /// <summary>
-  /// Tables defined in the worksheet.
-  /// </summary>
-  public ExcelTableCollection Tables {
-    get {
-      CheckSheetType();
-      if (Workbook._nextTableID == int.MinValue) {
-        Workbook.ReadAllTables();
-      }
-      if (_tables == null) {
-        _tables = new(this);
-      }
-      return _tables;
-    }
-  }
-
-  private ExcelPivotTableCollection _pivotTables;
-
-  /// <summary>
-  /// Pivottables defined in the worksheet.
-  /// </summary>
-  public ExcelPivotTableCollection PivotTables {
-    get {
-      CheckSheetType();
-      if (_pivotTables == null) {
-        if (Workbook._nextPivotTableID == int.MinValue) {
-          Workbook.ReadAllTables();
-        }
-        _pivotTables = new(this);
-      }
-      return _pivotTables;
-    }
-  }
-
-  private ExcelConditionalFormattingCollection _conditionalFormatting;
-
-  /// <summary>
-  /// ConditionalFormatting defined in the worksheet. Use the Add methods to create ConditionalFormatting and add them to the worksheet. Then
-  /// set the properties on the instance returned.
-  /// </summary>
-  /// <seealso cref="ExcelConditionalFormattingCollection"/>
-  public ExcelConditionalFormattingCollection ConditionalFormatting {
-    get {
-      CheckSheetType();
-      if (_conditionalFormatting == null) {
-        _conditionalFormatting = new(this);
-      }
-      return _conditionalFormatting;
-    }
-  }
-
-  private ExcelDataValidationCollection _dataValidation;
-
-  /// <summary>
-  /// DataValidation defined in the worksheet. Use the Add methods to create DataValidations and add them to the worksheet. Then
-  /// set the properties on the instance returned.
-  /// </summary>
-  /// <seealso cref="ExcelDataValidationCollection"/>
-  public ExcelDataValidationCollection DataValidations {
-    get {
-      CheckSheetType();
-      if (_dataValidation == null) {
-        _dataValidation = new(this);
-      }
-      return _dataValidation;
-    }
-  }
-
-  /// <summary>
-  /// Returns the style ID given a style name.
-  /// The style ID will be created if not found, but only if the style name exists!
-  /// </summary>
-  /// <param name="styleName"></param>
-  /// <returns></returns>
-  internal int GetStyleId(string styleName) {
-    ExcelNamedStyleXml namedStyle = null;
-    Workbook.Styles.NamedStyles.FindById(styleName, ref namedStyle);
-    if (namedStyle.XfId == int.MinValue) {
-      namedStyle.XfId = Workbook.Styles.CellXfs.FindIndexById(namedStyle.Style.Id);
-    }
-    return namedStyle.XfId;
-  }
-
-  /// <summary>
-  /// The workbook object
-  /// </summary>
-  public ExcelWorkbook Workbook => _workbook;
-
-  /// <summary>
-  /// Get the next ID from a shared formula or an Array formula
-  /// Sharedforumlas will have an id from 0-x. Array formula ids start from 0x4000001-.
-  /// </summary>
-  /// <param name="isArray">If the formula is an array formula</param>
-  /// <returns></returns>
-  internal int GetMaxShareFunctionIndex(bool isArray) {
-    int i = _sharedFormulas.Count + 1;
-    if (isArray) {
-      i |= 0x40000000;
-    }
-
-    while (_sharedFormulas.ContainsKey(i)) {
-      i++;
-    }
-    return i;
-  }
-
-  internal void UpdateCellsWithDate1904Setting() {
-    var cse = new CellsStoreEnumerator<object>(_values);
-    var offset = Workbook.Date1904 ? -ExcelWorkbook._date1904Offset : ExcelWorkbook._date1904Offset;
-    while (cse.MoveNext()) {
-      if (cse.Value is DateTime time) {
-        try {
-          double sdv = time.ToOADate();
-          sdv += offset;
-
-          cse.Value = DateTime.FromOADate(sdv);
-        } catch {}
-      }
-    }
-  }
-
-  public string GetFormula(int row, int col) {
-    var v = _formulas.GetValue(row, col);
-    if (v is int i) {
-      return _sharedFormulas[i].GetFormula(row, col, Name);
-    }
-    if (v != null) {
-      return v.ToString();
-    }
-    return "";
-  }
-
-  public string GetFormulaR1C1(int row, int col) {
-    var v = _formulas.GetValue(row, col);
-    if (v is int i) {
-      var sf = _sharedFormulas[i];
-      return ExcelCellBase.TranslateToR1C1(
-          Formulas.RemoveDummyFunction(sf.Formula),
-          sf.StartRow,
-          sf.StartCol);
-    }
-    if (v != null) {
-      return ExcelCellBase.TranslateToR1C1(Formulas.RemoveDummyFunction(v.ToString()), row, col);
-    }
-    return "";
-  }
-
-  public string GetFormulaR1C1_V1(int row, int col) {
-    var v = _formulas.GetValue(row, col);
-    if (v is int i) {
-      var sf = _sharedFormulas[i];
-      return ExcelCellBase.TranslateToR1C1_V1(
-          Formulas.RemoveDummyFunction(sf.Formula),
-          sf.StartRow,
-          sf.StartCol);
-    }
-    if (v != null) {
-      return ExcelCellBase.TranslateToR1C1_V1(Formulas.RemoveDummyFunction(v.ToString()), row, col);
-    }
-    return "";
-  }
-
-  public bool IsArrayFormula(int row, int col) =>
-    _flags.GetFlagValue(row, col, CellFlags.ArrayFormula);
-
-  public string GetArrayFormulaAddress(int row, int col) {
-    var v = _formulas.GetValue(row, col);
-    if ((v is int i) && (_sharedFormulas[i].IsArray)) {
-      return _sharedFormulas[i].Address;
-    }
-    return "";
-  }
-
-  public int GetStyleId(int row, int col) {
-    int styleId = 0;
-    if (!_styles.Exists(row, col, ref styleId) && !_styles.Exists(row, 0, ref styleId)) {
-      styleId = _styles.GetValue(0, col);
-    }
-    return styleId;
-  }
-
-  /// <summary>
-  /// Get the ExcelColumn for column (span ColumnMin and ColumnMax)
-  /// </summary>
-  /// <param name="column"></param>
-  /// <returns></returns>
-  internal ExcelColumn GetColumn(int column) {
-    var c = _values.GetValue(0, column) as ExcelColumn;
-    if (c == null) {
-      int row = 0,
-          col = column;
-      if (_values.PrevCell(ref row, ref col)) {
-        c = _values.GetValue(0, col) as ExcelColumn;
-        if (c != null && c.ColumnMax >= column) {
-          return c;
-        }
-        return null;
-      }
-    }
-    return c;
-  }
-
-  public bool Equals(ExcelWorksheet x, ExcelWorksheet y) {
-    return x.Name == y.Name
-        && x.SheetID == y.SheetID
-        && x.WorksheetXml.OuterXml == y.WorksheetXml.OuterXml;
-  }
-
-  public int GetHashCode(ExcelWorksheet obj) {
-    return obj.WorksheetXml.OuterXml.GetHashCode();
-  }
-}
diff --git a/EPPlus/ExcelWorksheetView.cs b/EPPlus/ExcelWorksheetView.cs
deleted file mode 100644
index 758ec6e..0000000
--- a/EPPlus/ExcelWorksheetView.cs
+++ /dev/null
@@ -1,396 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan K�llman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan K�llman		    Initial Release		       2009-10-01
- * Jan K�llman		    License changed GPL-->LGPL 2011-12-27
- *******************************************************************************/
-
-using System;
-using System.Collections.Immutable;
-using System.Xml;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// Represents the different view states of the worksheet
-/// </summary>
-public class ExcelWorksheetView : XmlHelper {
-  /// <summary>
-  /// The worksheet panes after a freeze or split.
-  /// </summary>
-  public class ExcelWorksheetPanes : XmlHelper {
-    private XmlElement _selectionNode;
-
-    internal ExcelWorksheetPanes(XmlNamespaceManager ns, XmlNode topNode)
-        : base(ns, topNode) {
-      if (topNode.Name == "selection") {
-        _selectionNode = topNode as XmlElement;
-      }
-    }
-
-    private const string _activeCellPath = "@activeCell";
-
-    /// <summary>
-    /// Set the active cell. Must be set within the SelectedRange.
-    /// </summary>
-    public string ActiveCell {
-      get {
-        string address = GetXmlNodeString(_activeCellPath);
-        if (address == "") {
-          return "A1";
-        }
-        return address;
-      }
-      set {
-        int toCol,
-            toRow;
-        if (_selectionNode == null) {
-          CreateSelectionElement();
-        }
-        ExcelCellBase.GetRowColFromAddress(
-            value,
-            out var fromRow,
-            out var fromCol,
-            out toRow,
-            out toCol);
-        SetXmlNodeString(_activeCellPath, value);
-        if (((XmlElement)TopNode).GetAttribute("sqref") == "") {
-          SelectedRange = ExcelCellBase.GetAddress(fromRow, fromCol);
-        }
-        //TODO:Add fix for out of range here
-      }
-    }
-
-    private void CreateSelectionElement() {
-      _selectionNode = TopNode.OwnerDocument.CreateElement("selection", ExcelPackage._schemaMain);
-      TopNode.AppendChild(_selectionNode);
-      TopNode = _selectionNode;
-    }
-
-    private const string _selectionRangePath = "@sqref";
-
-    /// <summary>
-    /// Selected Cells.Used in combination with ActiveCell
-    /// </summary>
-    public string SelectedRange {
-      get {
-        string address = GetXmlNodeString(_selectionRangePath);
-        if (address == "") {
-          return "A1";
-        }
-        return address;
-      }
-      set {
-        int toCol,
-            toRow;
-        if (_selectionNode == null) {
-          CreateSelectionElement();
-        }
-        ExcelCellBase.GetRowColFromAddress(
-            value,
-            out var fromRow,
-            out var fromCol,
-            out toRow,
-            out toCol);
-        SetXmlNodeString(_selectionRangePath, value);
-        if (((XmlElement)TopNode).GetAttribute("activeCell") == "") {
-          ActiveCell = ExcelCellBase.GetAddress(fromRow, fromCol);
-        }
-        //TODO:Add fix for out of range here
-      }
-    }
-  }
-
-  private readonly ExcelWorksheet _worksheet;
-
-  protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
-    "sheetViews",
-    "sheetView",
-    "pane",
-    "selection",
-  ];
-
-  /// <summary>
-  /// Creates a new ExcelWorksheetView which provides access to all the view states of the worksheet.
-  /// </summary>
-  /// <param name="ns"></param>
-  /// <param name="node"></param>
-  /// <param name="xlWorksheet"></param>
-  internal ExcelWorksheetView(XmlNamespaceManager ns, XmlNode node, ExcelWorksheet xlWorksheet)
-      : base(ns, node) {
-    _worksheet = xlWorksheet;
-    Panes = LoadPanes();
-  }
-
-  private ExcelWorksheetPanes[] LoadPanes() {
-    XmlNodeList nodes = TopNode.SelectNodes("//d:selection", NameSpaceManager);
-    if (nodes.Count == 0) {
-      return new[] { new ExcelWorksheetPanes(NameSpaceManager, TopNode) };
-    }
-    ExcelWorksheetPanes[] panes = new ExcelWorksheetPanes[nodes.Count];
-    int i = 0;
-    foreach (XmlElement elem in nodes) {
-      panes[i++] = new(NameSpaceManager, elem);
-    }
-    return panes;
-  }
-
-  /// <summary>
-  /// Returns a reference to the sheetView element
-  /// </summary>
-  protected internal XmlElement SheetViewElement => (XmlElement)TopNode;
-
-  /// <summary>
-  /// The active cell.
-  /// </summary>
-  public string ActiveCell {
-    get => Panes[Panes.GetUpperBound(0)].ActiveCell;
-    set => Panes[Panes.GetUpperBound(0)].ActiveCell = value;
-  }
-
-  /// <summary>
-  /// Selected Cells in the worksheet.Used in combination with ActiveCell
-  /// </summary>
-  public string SelectedRange {
-    get => Panes[Panes.GetUpperBound(0)].SelectedRange;
-    set => Panes[Panes.GetUpperBound(0)].SelectedRange = value;
-  }
-
-  /// <summary>
-  /// Indicates if the worksheet is selected within the workbook
-  /// </summary>
-  public bool TabSelected {
-    get => GetXmlNodeBool("@tabSelected");
-    set {
-      if (value) {
-        //    // ensure no other worksheet has its tabSelected attribute set to 1
-        foreach (ExcelWorksheet sheet in _worksheet.Workbook.Worksheets) {
-          sheet.View.TabSelected = false;
-        }
-
-        SheetViewElement.SetAttribute("tabSelected", "1");
-        XmlElement bookView =
-            _worksheet.Workbook.WorkbookXml.SelectSingleNode(
-                "//d:workbookView",
-                _worksheet.NameSpaceManager) as XmlElement;
-        if (bookView != null) {
-          bookView.SetAttribute("activeTab", (_worksheet.PositionID - 1).ToString());
-        }
-      } else {
-        SetXmlNodeString("@tabSelected", "0");
-      }
-    }
-  }
-
-  /// <summary>
-  /// Sets the view mode of the worksheet to pagelayout
-  /// </summary>
-  public bool PageLayoutView {
-    get => GetXmlNodeString("@view") == "pageLayout";
-    set {
-      if (value) {
-        SetXmlNodeString("@view", "pageLayout");
-      } else {
-        SheetViewElement.RemoveAttribute("view");
-      }
-    }
-  }
-
-  /// <summary>
-  /// Sets the view mode of the worksheet to pagebreak
-  /// </summary>
-  public bool PageBreakView {
-    get => GetXmlNodeString("@view") == "pageBreakPreview";
-    set {
-      if (value) {
-        SetXmlNodeString("@view", "pageBreakPreview");
-      } else {
-        SheetViewElement.RemoveAttribute("view");
-      }
-    }
-  }
-
-  /// <summary>
-  /// Show gridlines in the worksheet
-  /// </summary>
-  public bool ShowGridLines {
-    get => GetXmlNodeBool("@showGridLines");
-    set => SetXmlNodeString("@showGridLines", value ? "1" : "0");
-  }
-
-  /// <summary>
-  /// Show the Column/Row headers (containg column letters and row numbers)
-  /// </summary>
-  public bool ShowHeaders {
-    get => GetXmlNodeBool("@showRowColHeaders");
-    set => SetXmlNodeString("@showRowColHeaders", value ? "1" : "0");
-  }
-
-  /// <summary>
-  /// Window zoom magnification for current view representing percent values.
-  /// </summary>
-  public int ZoomScale {
-    get => GetXmlNodeInt("@zoomScale");
-    set {
-      if (value < 10 || value > 400) {
-        throw new ArgumentOutOfRangeException("Zoome scale out of range (10-400)");
-      }
-      SetXmlNodeString("@zoomScale", value.ToString());
-    }
-  }
-
-  /// <summary>
-  /// Flag indicating whether the sheet is in 'right to left' display mode. When in this mode,Column A is on the far right, Column B ;is one column left of Column A, and so on. Also,information in cells is displayed in the Right to Left format.
-  /// </summary>
-  public bool RightToLeft {
-    get => GetXmlNodeBool("@rightToLeft");
-    set => SetXmlNodeString("@rightToLeft", value ? "1" : "0");
-  }
-
-  internal bool WindowProtection {
-    get => GetXmlNodeBool("@windowProtection", false);
-    set => SetXmlNodeBool("@windowProtection", value, false);
-  }
-
-  /// <summary>
-  /// Reference to the panes
-  /// </summary>
-  public ExcelWorksheetPanes[] Panes { get; internal set; }
-
-  private readonly string _paneNodePath = "d:pane";
-  private readonly string _selectionNodePath = "d:selection";
-
-  /// <summary>
-  /// Freeze the columns/rows to left and above the cell
-  /// </summary>
-  /// <param name="row"></param>
-  /// <param name="column"></param>
-  public void FreezePanes(int row, int column) {
-    //TODO:fix this method to handle splits as well.
-    if (row == 1 && column == 1) {
-      UnFreezePanes();
-    }
-    string sqRef = SelectedRange,
-        activeCell = ActiveCell;
-
-    XmlElement paneNode = TopNode.SelectSingleNode(_paneNodePath, NameSpaceManager) as XmlElement;
-    if (paneNode == null) {
-      CreateNode(_paneNodePath);
-      paneNode = TopNode.SelectSingleNode(_paneNodePath, NameSpaceManager) as XmlElement;
-    }
-    paneNode.RemoveAll(); //Clear all attributes
-    if (column > 1) {
-      paneNode.SetAttribute("xSplit", (column - 1).ToString());
-    }
-    if (row > 1) {
-      paneNode.SetAttribute("ySplit", (row - 1).ToString());
-    }
-    paneNode.SetAttribute("topLeftCell", ExcelCellBase.GetAddress(row, column));
-    paneNode.SetAttribute("state", "frozen");
-
-    RemoveSelection();
-
-    if (row > 1 && column == 1) {
-      paneNode.SetAttribute("activePane", "bottomLeft");
-      XmlElement sel = TopNode.OwnerDocument.CreateElement("selection", ExcelPackage._schemaMain);
-      sel.SetAttribute("pane", "bottomLeft");
-      if (activeCell != "") {
-        sel.SetAttribute("activeCell", activeCell);
-      }
-      if (sqRef != "") {
-        sel.SetAttribute("sqref", sqRef);
-      }
-      sel.SetAttribute("sqref", sqRef);
-      TopNode.InsertAfter(sel, paneNode);
-    } else if (column > 1 && row == 1) {
-      paneNode.SetAttribute("activePane", "topRight");
-      XmlElement sel = TopNode.OwnerDocument.CreateElement("selection", ExcelPackage._schemaMain);
-      sel.SetAttribute("pane", "topRight");
-      if (activeCell != "") {
-        sel.SetAttribute("activeCell", activeCell);
-      }
-      if (sqRef != "") {
-        sel.SetAttribute("sqref", sqRef);
-      }
-      TopNode.InsertAfter(sel, paneNode);
-    } else {
-      paneNode.SetAttribute("activePane", "bottomRight");
-      XmlElement sel1 = TopNode.OwnerDocument.CreateElement("selection", ExcelPackage._schemaMain);
-      sel1.SetAttribute("pane", "topRight");
-      string cell = ExcelCellBase.GetAddress(1, column);
-      sel1.SetAttribute("activeCell", cell);
-      sel1.SetAttribute("sqref", cell);
-      paneNode.ParentNode.InsertAfter(sel1, paneNode);
-
-      XmlElement sel2 = TopNode.OwnerDocument.CreateElement("selection", ExcelPackage._schemaMain);
-      cell = ExcelCellBase.GetAddress(row, 1);
-      sel2.SetAttribute("pane", "bottomLeft");
-      sel2.SetAttribute("activeCell", cell);
-      sel2.SetAttribute("sqref", cell);
-      sel1.ParentNode.InsertAfter(sel2, sel1);
-
-      XmlElement sel3 = TopNode.OwnerDocument.CreateElement("selection", ExcelPackage._schemaMain);
-      sel3.SetAttribute("pane", "bottomRight");
-      if (activeCell != "") {
-        sel3.SetAttribute("activeCell", activeCell);
-      }
-      if (sqRef != "") {
-        sel3.SetAttribute("sqref", sqRef);
-      }
-      sel2.ParentNode.InsertAfter(sel3, sel2);
-    }
-    Panes = LoadPanes();
-  }
-
-  private void RemoveSelection() {
-    //Find selection nodes and remove them
-    XmlNodeList selections = TopNode.SelectNodes(_selectionNodePath, NameSpaceManager);
-    foreach (XmlNode sel in selections) {
-      sel.ParentNode.RemoveChild(sel);
-    }
-  }
-
-  /// <summary>
-  /// Unlock all rows and columns to scroll freely
-  /// /// </summary>
-  public void UnFreezePanes() {
-    string sqRef = SelectedRange,
-        activeCell = ActiveCell;
-
-    XmlElement paneNode = TopNode.SelectSingleNode(_paneNodePath, NameSpaceManager) as XmlElement;
-    if (paneNode != null) {
-      paneNode.ParentNode.RemoveChild(paneNode);
-    }
-    RemoveSelection();
-
-    Panes = LoadPanes();
-
-    SelectedRange = sqRef;
-    ActiveCell = activeCell;
-  }
-}
diff --git a/EPPlus/ExcelWorksheets.cs b/EPPlus/ExcelWorksheets.cs
deleted file mode 100644
index a0e4ebb..0000000
--- a/EPPlus/ExcelWorksheets.cs
+++ /dev/null
@@ -1,336 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		    Initial Release		       2009-10-01
- * Jan Källman		    License changed GPL-->LGPL 2011-12-27
- *******************************************************************************/
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Text.RegularExpressions;
-using System.Xml;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// The collection of worksheets for the workbook
-/// </summary>
-public class ExcelWorksheets : XmlHelper, IEnumerable<ExcelWorksheet> {
-  private readonly ExcelPackage _pck;
-  private readonly ExcelWorkbook _workbook;
-  private Dictionary<int, ExcelWorksheet> _worksheets = new();
-  private readonly XmlNamespaceManager _namespaceManager;
-
-  internal ExcelWorksheets(
-      ExcelPackage pck,
-      ExcelWorkbook workbook,
-      XmlNamespaceManager nsm,
-      XmlNode topNode)
-      : base(nsm, topNode) {
-    _pck = pck;
-    _workbook = workbook;
-    _namespaceManager = nsm;
-    int positionId = 1;
-
-    foreach (XmlNode sheetNode in topNode.ChildNodes) {
-      if (sheetNode.NodeType == XmlNodeType.Element) {
-        string name = sheetNode.Attributes["name"].Value;
-        //Get the relationship id
-        string relId = sheetNode.Attributes["r:id"].Value;
-        int sheetId = Convert.ToInt32(sheetNode.Attributes["sheetId"].Value);
-
-        //Hidden property
-        eWorkSheetHidden hidden = eWorkSheetHidden.Visible;
-        XmlNode attr = sheetNode.Attributes["state"];
-        if (attr != null) {
-          hidden = TranslateHidden(attr.Value);
-        }
-
-        var sheetRelation = _workbook.Part.GetRelationship(relId);
-        Uri uriWorksheet = UriHelper.ResolvePartUri(
-            ExcelWorkbook.WorkbookUri,
-            sheetRelation.TargetUri);
-
-        //add the worksheet
-        if (sheetRelation.RelationshipType.EndsWith("chartsheet")) {
-          _worksheets.Add(
-              positionId,
-              new ExcelChartsheet(
-                  _namespaceManager,
-                  pck,
-                  _workbook,
-                  uriWorksheet,
-                  name,
-                  sheetId,
-                  positionId,
-                  hidden));
-        } else {
-          _worksheets.Add(
-              positionId,
-              new(
-                  _namespaceManager,
-                  pck,
-                  _workbook,
-                  uriWorksheet,
-                  name,
-                  sheetId,
-                  positionId,
-                  hidden));
-        }
-        positionId++;
-      }
-    }
-  }
-
-  private eWorkSheetHidden TranslateHidden(string value) {
-    switch (value) {
-      case "hidden":
-        return eWorkSheetHidden.Hidden;
-      case "veryHidden":
-        return eWorkSheetHidden.VeryHidden;
-      default:
-        return eWorkSheetHidden.Visible;
-    }
-  }
-
-  /// <summary>
-  /// Returns the number of worksheets in the workbook
-  /// </summary>
-  public int Count => (_worksheets.Count);
-
-  private const string _errDupWorksheet =
-      "A worksheet with this name already exists in the workbook";
-  internal const string _worksheetContentType =
-      "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml";
-
-  /// <summary>
-  /// Foreach support
-  /// </summary>
-  /// <returns>An enumerator</returns>
-  public IEnumerator<ExcelWorksheet> GetEnumerator() {
-    return (_worksheets.Values.GetEnumerator());
-  }
-
-  IEnumerator IEnumerable.GetEnumerator() {
-    return (_worksheets.Values.GetEnumerator());
-  }
-
-  /// <summary>
-  /// Adds a new blank worksheet.
-  /// </summary>
-  /// <param name="name">The name of the workbook</param>
-  public ExcelWorksheet Add(string name) {
-    name = ValidateFixSheetName(name);
-    if (GetByName(name) != null) {
-      throw (new InvalidOperationException(_errDupWorksheet + " : " + name));
-    }
-    GetSheetUri(ref name, out var sheetId, out var uriWorksheet, false);
-
-    // Create the new worksheet
-    var rel = _pck.CreateXmlDocument(
-        uriWorksheet,
-        _worksheetContentType,
-        ExcelPackage._schemaRelationships + "/worksheet",
-        CreateNewWorksheet(false));
-
-    // Add worksheet to the workbook
-    XmlElement worksheetNode = _workbook.WorkbookXml.CreateElement(
-        "sheet",
-        ExcelPackage._schemaMain);
-    worksheetNode.SetAttribute("name", name);
-    worksheetNode.SetAttribute("sheetId", sheetId.ToString());
-    worksheetNode.SetAttribute("id", ExcelPackage._schemaRelationships, rel.Id);
-    TopNode.AppendChild(worksheetNode);
-
-    int positionId = _worksheets.Count + 1;
-
-    ExcelWorksheet worksheet = new(
-        _namespaceManager,
-        _pck,
-        _workbook,
-        uriWorksheet,
-        name,
-        sheetId,
-        positionId,
-        eWorkSheetHidden.Visible);
-
-    _worksheets.Add(positionId, worksheet);
-    return worksheet;
-  }
-
-  private void GetSheetUri(ref string name, out int sheetId, out Uri uriWorksheet, bool isChart) {
-    name = ValidateFixSheetName(name);
-
-    //First find maximum existing sheetID
-    sheetId = 0;
-    foreach (var ws in this) {
-      if (ws.SheetID > sheetId) {
-        sheetId = ws.SheetID;
-      }
-    }
-    // we now have the max existing values, so add one
-    sheetId++;
-
-    // add the new worksheet to the package
-    if (isChart) {
-      uriWorksheet = new("/xl/chartsheets/chartsheet" + sheetId + ".xml", UriKind.Relative);
-    } else {
-      uriWorksheet = new("/xl/worksheets/sheet" + sheetId + ".xml", UriKind.Relative);
-    }
-  }
-
-  internal string ValidateFixSheetName(string name) {
-    //remove invalid characters
-    if (ValidateName(name)) {
-      if (name.IndexOf(':') > -1) {
-        name = name.Replace(":", " ");
-      }
-      if (name.IndexOf('/') > -1) {
-        name = name.Replace("/", " ");
-      }
-      if (name.IndexOf('\\') > -1) {
-        name = name.Replace("\\", " ");
-      }
-      if (name.IndexOf('?') > -1) {
-        name = name.Replace("?", " ");
-      }
-      if (name.IndexOf('[') > -1) {
-        name = name.Replace("[", " ");
-      }
-      if (name.IndexOf(']') > -1) {
-        name = name.Replace("]", " ");
-      }
-    }
-
-    if (name.Trim() == "") {
-      throw new ArgumentException("The worksheet can not have an empty name");
-    }
-    if (name.Length > 31) {
-      name = name.Substring(0, 31); //A sheet can have max 31 char's
-    }
-    return name;
-  }
-
-  /// <summary>
-  /// Validate the sheetname
-  /// </summary>
-  /// <param name="name">The Name</param>
-  /// <returns>True if valid</returns>
-  private bool ValidateName(string name) {
-    return Regex.IsMatch(name, @":|\?|/|\\|\[|\]");
-  }
-
-  /// <summary>
-  /// Creates the XML document representing a new empty worksheet
-  /// </summary>
-  /// <returns></returns>
-  internal XmlDocument CreateNewWorksheet(bool isChart) {
-    XmlDocument xmlDoc = new XmlDocument();
-    XmlElement elemWs = xmlDoc.CreateElement(
-        isChart ? "chartsheet" : "worksheet",
-        ExcelPackage._schemaMain);
-    elemWs.SetAttribute("xmlns:r", ExcelPackage._schemaRelationships);
-    xmlDoc.AppendChild(elemWs);
-
-    if (isChart) {
-      XmlElement elemSheetPr = xmlDoc.CreateElement("sheetPr", ExcelPackage._schemaMain);
-      elemWs.AppendChild(elemSheetPr);
-
-      XmlElement elemSheetViews = xmlDoc.CreateElement("sheetViews", ExcelPackage._schemaMain);
-      elemWs.AppendChild(elemSheetViews);
-
-      XmlElement elemSheetView = xmlDoc.CreateElement("sheetView", ExcelPackage._schemaMain);
-      elemSheetView.SetAttribute("workbookViewId", "0");
-      elemSheetView.SetAttribute("zoomToFit", "1");
-
-      elemSheetViews.AppendChild(elemSheetView);
-    } else {
-      XmlElement elemSheetViews = xmlDoc.CreateElement("sheetViews", ExcelPackage._schemaMain);
-      elemWs.AppendChild(elemSheetViews);
-
-      XmlElement elemSheetView = xmlDoc.CreateElement("sheetView", ExcelPackage._schemaMain);
-      elemSheetView.SetAttribute("workbookViewId", "0");
-      elemSheetViews.AppendChild(elemSheetView);
-
-      XmlElement elemSheetFormatPr = xmlDoc.CreateElement(
-          "sheetFormatPr",
-          ExcelPackage._schemaMain);
-      elemSheetFormatPr.SetAttribute("defaultRowHeight", "15");
-      elemWs.AppendChild(elemSheetFormatPr);
-
-      XmlElement elemSheetData = xmlDoc.CreateElement("sheetData", ExcelPackage._schemaMain);
-      elemWs.AppendChild(elemSheetData);
-    }
-    return xmlDoc;
-  }
-
-  /// <summary>
-  /// Returns the worksheet at the specified position.
-  /// </summary>
-  /// <param name="positionId">The position of the worksheet. 1-base</param>
-  /// <returns></returns>
-  public ExcelWorksheet this[int positionId] {
-    get {
-      if (_worksheets.ContainsKey(positionId)) {
-        return _worksheets[positionId];
-      }
-      throw (new IndexOutOfRangeException("Worksheet position out of range."));
-    }
-  }
-
-  /// <summary>
-  /// Returns the worksheet matching the specified name
-  /// </summary>
-  /// <param name="name">The name of the worksheet</param>
-  /// <returns></returns>
-  public ExcelWorksheet this[string name] => GetByName(name);
-
-  internal ExcelWorksheet GetBySheetId(int localSheetId) {
-    foreach (ExcelWorksheet ws in this) {
-      if (ws.SheetID == localSheetId) {
-        return ws;
-      }
-    }
-    return null;
-  }
-
-  private ExcelWorksheet GetByName(string name) {
-    if (string.IsNullOrEmpty(name)) {
-      return null;
-    }
-    ExcelWorksheet xlWorksheet = null;
-    foreach (ExcelWorksheet worksheet in _worksheets.Values) {
-      if (worksheet.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)) {
-        xlWorksheet = worksheet;
-      }
-    }
-    return (xlWorksheet);
-  }
-} // end class Worksheets
diff --git a/EPPlus/FormulaParsing/CalculateExtentions.cs b/EPPlus/FormulaParsing/CalculateExtentions.cs
deleted file mode 100644
index afeb3ff..0000000
--- a/EPPlus/FormulaParsing/CalculateExtentions.cs
+++ /dev/null
@@ -1,159 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman                      Added                       2012-03-04
- *******************************************************************************/
-
-using System;
-using OfficeOpenXml.FormulaParsing;
-using OfficeOpenXml.FormulaParsing.Excel.Functions;
-using OfficeOpenXml.FormulaParsing.Exceptions;
-
-namespace OfficeOpenXml;
-
-public static class CalculationExtension {
-  public static void Calculate(this ExcelWorkbook workbook) {
-    Calculate(
-        workbook,
-        new() {
-          AllowCirculareReferences = false,
-        });
-  }
-
-  public static void Calculate(this ExcelWorkbook workbook, ExcelCalculationOption options) {
-    Init(workbook);
-
-    var dc = DependencyChainFactory.Create(workbook, options);
-    workbook.FormulaParser.InitNewCalc();
-    CalcChain(workbook, workbook.FormulaParser, dc);
-  }
-
-  public static void Calculate(this ExcelWorksheet worksheet) {
-    Calculate(worksheet, new ExcelCalculationOption());
-  }
-
-  public static void Calculate(this ExcelWorksheet worksheet, ExcelCalculationOption options) {
-    Init(worksheet.Workbook);
-    //worksheet.Workbook._formulaParser = null; TODO:Cant reset. Don't work with userdefined or overrided worksheet functions
-    var dc = DependencyChainFactory.Create(worksheet, options);
-
-    // Display Calc Chain to determine why formula calculation is taking so long.
-    // Uncomment the following line to display the Calc Chain.
-    // DisplayCalcChain(worksheet, dc);
-
-    var parser = worksheet.Workbook.FormulaParser;
-    parser.InitNewCalc();
-    CalcChain(worksheet.Workbook, parser, dc);
-  }
-
-  public static void Calculate(this ExcelRangeBase range) {
-    Calculate(range, new());
-  }
-
-  public static void Calculate(this ExcelRangeBase range, ExcelCalculationOption options) {
-    Init(range._workbook);
-    var parser = range._workbook.FormulaParser;
-    parser.InitNewCalc();
-    var dc = DependencyChainFactory.Create(range, options);
-    CalcChain(range._workbook, parser, dc);
-  }
-
-  public static object Calculate(this ExcelWorksheet worksheet, string formula) {
-    return Calculate(worksheet, formula, new());
-  }
-
-  public static object Calculate(
-      this ExcelWorksheet worksheet,
-      string formula,
-      ExcelCalculationOption options) {
-    try {
-      worksheet.CheckSheetType();
-      if (string.IsNullOrEmpty(formula.Trim())) {
-        return null;
-      }
-      Init(worksheet.Workbook);
-      var parser = worksheet.Workbook.FormulaParser;
-      parser.InitNewCalc();
-      if (formula[0] == '=') {
-        formula = formula.Substring(1); //Remove any starting equal sign
-      }
-      var dc = DependencyChainFactory.Create(worksheet, formula, options);
-      var f = dc.list[0];
-      dc.CalcOrder.RemoveAt(dc.CalcOrder.Count - 1);
-
-      CalcChain(worksheet.Workbook, parser, dc);
-
-      return parser.ParseCell(f.Tokens, worksheet.Name, -1, -1);
-    } catch (Exception ex) {
-      return new ExcelErrorValueException(ex.Message, ExcelErrorValue.Create(eErrorType.Value));
-    }
-  }
-
-  private static void CalcChain(ExcelWorkbook wb, FormulaParser parser, DependencyChain dc) {
-    foreach (var ix in dc.CalcOrder) {
-      var item = dc.list[ix];
-      try {
-        var ws = wb.Worksheets.GetBySheetId(item.SheetID);
-        var v = parser.ParseCell(item.Tokens, ws == null ? "" : ws.Name, item.Row, item.Column);
-        SetValue(wb, item, v);
-      } catch (FunctionException) {
-        // Excel function is not supported by EPPlus
-        throw;
-      } catch (FormatException) {
-        throw;
-      } catch (Exception) {
-        var error = ExcelErrorValue.Parse(ExcelErrorValue.Values.Value);
-        SetValue(wb, item, error);
-      }
-    }
-  }
-
-  private static void Init(ExcelWorkbook workbook) {
-    workbook._formulaTokens = new();
-    ;
-    foreach (var ws in workbook.Worksheets) {
-      if (!(ws is ExcelChartsheet)) {
-        ws._formulaTokens = new();
-      }
-    }
-  }
-
-  private static void SetValue(ExcelWorkbook workbook, FormulaCell item, object v) {
-    if (item.Column == 0) {
-      if (item.SheetID <= 0) {
-        workbook.Names[item.Row].NameValue = v;
-      } else {
-        var sh = workbook.Worksheets.GetBySheetId(item.SheetID);
-        sh.Names[item.Row].NameValue = v;
-      }
-    } else {
-      var sheet = workbook.Worksheets.GetBySheetId(item.SheetID);
-      sheet._values.SetValue(item.Row, item.Column, v);
-    }
-  }
-}
diff --git a/EPPlus/FormulaParsing/DependencyChain/DependencyChain.cs b/EPPlus/FormulaParsing/DependencyChain/DependencyChain.cs
deleted file mode 100644
index 74a0a7e..0000000
--- a/EPPlus/FormulaParsing/DependencyChain/DependencyChain.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.FormulaParsing;
-
-internal class DependencyChain {
-  internal List<FormulaCell> list = new();
-  internal Dictionary<ulong, int> index = new();
-  internal List<int> CalcOrder = new();
-
-  internal void Add(FormulaCell f) {
-    list.Add(f);
-    f.Index = list.Count - 1;
-    index.Add(ExcelCellBase.GetCellId(f.SheetID, f.Row, f.Column), f.Index);
-  }
-}
diff --git a/EPPlus/FormulaParsing/DependencyChain/DependenyChainFactory.cs b/EPPlus/FormulaParsing/DependencyChain/DependenyChainFactory.cs
deleted file mode 100644
index f198123..0000000
--- a/EPPlus/FormulaParsing/DependencyChain/DependenyChainFactory.cs
+++ /dev/null
@@ -1,373 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman                      Added                       2012-03-04
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.Exceptions;
-using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-
-namespace OfficeOpenXml.FormulaParsing;
-
-internal static class DependencyChainFactory {
-  internal static DependencyChain Create(ExcelWorkbook wb, ExcelCalculationOption options) {
-    var depChain = new DependencyChain();
-    foreach (var ws in wb.Worksheets) {
-      if (!(ws is ExcelChartsheet)) {
-        GetChain(depChain, wb.FormulaParser.Lexer, ws.Cells, options);
-        GetWorksheetNames(ws, depChain, options);
-      }
-    }
-    foreach (var name in wb.Names) {
-      if (name.NameValue == null) {
-        GetChain(depChain, wb.FormulaParser.Lexer, name, options);
-      }
-    }
-    return depChain;
-  }
-
-  internal static DependencyChain Create(ExcelWorksheet ws, ExcelCalculationOption options) {
-    ws.CheckSheetType();
-    var depChain = new DependencyChain();
-
-    GetChain(depChain, ws.Workbook.FormulaParser.Lexer, ws.Cells, options);
-
-    GetWorksheetNames(ws, depChain, options);
-
-    return depChain;
-  }
-
-  internal static DependencyChain Create(
-      ExcelWorksheet ws,
-      string formula,
-      ExcelCalculationOption options) {
-    ws.CheckSheetType();
-    var depChain = new DependencyChain();
-
-    GetChain(depChain, ws.Workbook.FormulaParser.Lexer, ws, formula, options);
-
-    return depChain;
-  }
-
-  private static void GetWorksheetNames(
-      ExcelWorksheet ws,
-      DependencyChain depChain,
-      ExcelCalculationOption options) {
-    foreach (var name in ws.Names) {
-      if (!string.IsNullOrEmpty(name.NameFormula)) {
-        GetChain(depChain, ws.Workbook.FormulaParser.Lexer, name, options);
-      }
-    }
-  }
-
-  internal static DependencyChain Create(ExcelRangeBase range, ExcelCalculationOption options) {
-    var depChain = new DependencyChain();
-
-    GetChain(depChain, range.Worksheet.Workbook.FormulaParser.Lexer, range, options);
-
-    return depChain;
-  }
-
-  private static void GetChain(
-      DependencyChain depChain,
-      ILexer lexer,
-      ExcelNamedRange name,
-      ExcelCalculationOption options) {
-    var ws = name.Worksheet;
-    var id = ExcelCellBase.GetCellId(ws?.SheetID ?? 0, name.Index, 0);
-    if (!depChain.index.ContainsKey(id)) {
-      var f = new FormulaCell {
-        SheetID = ws?.SheetID ?? 0,
-        Row = name.Index,
-        Column = 0,
-        Formula = name.NameFormula,
-      };
-      if (!string.IsNullOrEmpty(f.Formula)) {
-        f.Tokens = lexer.Tokenize(f.Formula, ws?.Name).ToList();
-        if (ws == null) {
-          name._workbook._formulaTokens.SetValue(name.Index, 0, f.Tokens);
-        } else {
-          ws._formulaTokens.SetValue(name.Index, 0, f.Tokens);
-        }
-        depChain.Add(f);
-        FollowChain(depChain, lexer, name._workbook, ws, f, options);
-      }
-    }
-  }
-
-  private static void GetChain(
-      DependencyChain depChain,
-      ILexer lexer,
-      ExcelWorksheet ws,
-      string formula,
-      ExcelCalculationOption options) {
-    var f = new FormulaCell {
-      SheetID = ws.SheetID,
-      Row = -1,
-      Column = -1,
-    };
-    f.Formula = formula;
-    if (!string.IsNullOrEmpty(f.Formula)) {
-      f.Tokens = lexer.Tokenize(f.Formula, ws.Name).ToList();
-      depChain.Add(f);
-      FollowChain(depChain, lexer, ws.Workbook, ws, f, options);
-    }
-  }
-
-  private static void GetChain(
-      DependencyChain depChain,
-      ILexer lexer,
-      ExcelRangeBase range,
-      ExcelCalculationOption options) {
-    var ws = range.Worksheet;
-    var fs = new CellsStoreEnumerator<object>(
-        ws._formulas,
-        range.Start.Row,
-        range.Start.Column,
-        range.End.Row,
-        range.End.Column);
-    while (fs.Next()) {
-      if (fs.Value == null || fs.Value.ToString().Trim() == "") {
-        continue;
-      }
-      var id = ExcelCellBase.GetCellId(ws.SheetID, fs.Row, fs.Column);
-      if (!depChain.index.ContainsKey(id)) {
-        var f = new FormulaCell {
-          SheetID = ws.SheetID,
-          Row = fs.Row,
-          Column = fs.Column,
-        };
-        if (fs.Value is int value) {
-          f.Formula = ws._sharedFormulas[value].GetFormula(fs.Row, fs.Column, ws.Name);
-        } else {
-          f.Formula = fs.Value.ToString();
-        }
-        if (!string.IsNullOrEmpty(f.Formula)) {
-          f.Tokens = lexer.Tokenize(f.Formula, range.Worksheet.Name).ToList();
-          ws._formulaTokens.SetValue(fs.Row, fs.Column, f.Tokens);
-          depChain.Add(f);
-          FollowChain(depChain, lexer, ws.Workbook, ws, f, options);
-        }
-      }
-    }
-  }
-
-  /// <summary>
-  /// This method follows the calculation chain to get the order of the calculation
-  /// Goto (!) is used internally to prevent stackoverflow on extremly larget dependency trees (that is, many recursive formulas).
-  /// </summary>
-  /// <param name="depChain">The dependency chain object</param>
-  /// <param name="lexer">The formula tokenizer</param>
-  /// <param name="wb">The workbook where the formula comes from</param>
-  /// <param name="ws">The worksheet where the formula comes from</param>
-  /// <param name="f">The cell function object</param>
-  /// <param name="options">Calcultaiton options</param>
-  private static void FollowChain(
-      DependencyChain depChain,
-      ILexer lexer,
-      ExcelWorkbook wb,
-      ExcelWorksheet ws,
-      FormulaCell f,
-      ExcelCalculationOption options) {
-    Stack<FormulaCell> stack = new Stack<FormulaCell>();
-    iterateToken:
-    while (f.tokenIx < f.Tokens.Count) {
-      var t = f.Tokens[f.tokenIx];
-      if (t.TokenType == TokenType.ExcelAddress) {
-        var adr = new ExcelFormulaAddress(t.Value);
-        if (adr.Table != null) {
-          adr.SetRcFromTable(ws.Workbook, new(f.Row, f.Column, f.Row, f.Column));
-        }
-
-        if (adr.WorkSheet == null
-            && adr.Collide(new(f.Row, f.Column, f.Row, f.Column))
-                != ExcelAddressBase.eAddressCollition.No) {
-          throw (new CircularReferenceException(
-                  string.Format(
-                      "Circular Reference in cell {0}",
-                      ExcelCellBase.GetAddress(f.Row, f.Column))));
-        }
-
-        if (adr._fromRow > 0 && adr._fromCol > 0) {
-          if (string.IsNullOrEmpty(adr.WorkSheet)) {
-            if (f.ws == null) {
-              f.ws = ws;
-            } else if (f.ws.SheetID != f.SheetID) {
-              f.ws = wb.Worksheets.GetBySheetId(f.SheetID);
-            }
-          } else {
-            f.ws = wb.Worksheets[adr.WorkSheet];
-          }
-
-          if (f.ws != null) {
-            f.iterator = new(
-                f.ws._formulas,
-                adr.Start.Row,
-                adr.Start.Column,
-                adr.End.Row,
-                adr.End.Column);
-            goto iterateCells;
-          }
-        }
-      } else if (t.TokenType == TokenType.NameValue) {
-        string adrWb;
-        ExcelNamedRange name;
-        ExcelAddressBase.SplitAddress(
-            t.Value,
-            out adrWb,
-            out var adrWs,
-            out var adrName,
-            f.ws == null ? "" : f.ws.Name);
-        if (!string.IsNullOrEmpty(adrWs)) {
-          if (f.ws == null) {
-            f.ws = wb.Worksheets[adrWs];
-          }
-          if (f.ws.Names.ContainsKey(t.Value)) {
-            name = f.ws.Names[adrName];
-          } else if (wb.Names.ContainsKey(adrName)) {
-            name = wb.Names[adrName];
-          } else {
-            name = null;
-          }
-          if (name != null) {
-            f.ws = name.Worksheet;
-          }
-        } else if (wb.Names.ContainsKey(adrName)) {
-          name = wb.Names[t.Value];
-          if (string.IsNullOrEmpty(adrWs)) {
-            f.ws = name.Worksheet;
-          }
-        } else {
-          name = null;
-        }
-
-        if (name != null) {
-          if (string.IsNullOrEmpty(name.NameFormula)) {
-            if (name.NameValue == null) {
-              f.iterator = new(
-                  f.ws._formulas,
-                  name.Start.Row,
-                  name.Start.Column,
-                  name.End.Row,
-                  name.End.Column);
-              goto iterateCells;
-            }
-          } else {
-            var id = ExcelCellBase.GetCellId(name.LocalSheetId, name.Index, 0);
-
-            if (!depChain.index.ContainsKey(id)) {
-              var rf = new FormulaCell {
-                SheetID = name.LocalSheetId,
-                Row = name.Index,
-                Column = 0,
-              };
-              rf.Formula = name.NameFormula;
-              rf.Tokens =
-                  name.LocalSheetId == -1
-                      ? lexer.Tokenize(rf.Formula).ToList()
-                      : lexer
-                          .Tokenize(rf.Formula, wb.Worksheets.GetBySheetId(name.LocalSheetId).Name)
-                          .ToList();
-
-              depChain.Add(rf);
-              stack.Push(f);
-              f = rf;
-              goto iterateToken;
-            }
-            if (stack.Count > 0) {
-              //Check for circular references
-              foreach (var par in stack) {
-                if (ExcelCellBase.GetCellId(par.SheetID, par.Row, par.Column) == id) {
-                  throw (new CircularReferenceException(
-                          string.Format("Circular Reference in name {0}", name.Name)));
-                }
-              }
-            }
-          }
-        }
-      }
-      f.tokenIx++;
-    }
-    depChain.CalcOrder.Add(f.Index);
-    if (stack.Count > 0) {
-      f = stack.Pop();
-      goto iterateCells;
-    }
-    return;
-    iterateCells:
-
-    while (f.iterator != null && f.iterator.Next()) {
-      var v = f.iterator.Value;
-      if (v == null || v.ToString().Trim() == "") {
-        continue;
-      }
-      var id = ExcelCellBase.GetCellId(f.ws.SheetID, f.iterator.Row, f.iterator.Column);
-      if (!depChain.index.ContainsKey(id)) {
-        var rf = new FormulaCell {
-          SheetID = f.ws.SheetID,
-          Row = f.iterator.Row,
-          Column = f.iterator.Column,
-        };
-        if (f.iterator.Value is int) {
-          rf.Formula = f.ws._sharedFormulas[(int)v]
-              .GetFormula(f.iterator.Row, f.iterator.Column, ws.Name);
-        } else {
-          rf.Formula = v.ToString();
-        }
-        rf.ws = f.ws;
-        rf.Tokens = lexer.Tokenize(rf.Formula, f.ws.Name).ToList();
-        ws._formulaTokens.SetValue(rf.Row, rf.Column, rf.Tokens);
-        depChain.Add(rf);
-        stack.Push(f);
-        f = rf;
-        goto iterateToken;
-      }
-      if (stack.Count > 0) {
-        //Check for circular references
-        foreach (var par in stack) {
-          if (ExcelCellBase.GetCellId(par.ws.SheetID, par.iterator.Row, par.iterator.Column)
-              == id) {
-            if (options.AllowCirculareReferences == false) {
-              throw (new CircularReferenceException(
-                      string.Format(
-                          "Circular Reference in cell {0}!{1}",
-                          par.ws.Name,
-                          ExcelCellBase.GetAddress(f.Row, f.Column))));
-            }
-            f = stack.Pop();
-            goto iterateCells;
-          }
-        }
-      }
-    }
-    f.tokenIx++;
-    goto iterateToken;
-  }
-}
diff --git a/EPPlus/FormulaParsing/DependencyChain/FormulaCell.cs b/EPPlus/FormulaParsing/DependencyChain/FormulaCell.cs
deleted file mode 100644
index 2b96a7d..0000000
--- a/EPPlus/FormulaParsing/DependencyChain/FormulaCell.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-/* Copyright (C) 2011  Jan K�llman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-
-namespace OfficeOpenXml.FormulaParsing;
-
-internal class FormulaCell {
-  internal int Index { get; set; }
-
-  internal int SheetID { get; set; }
-
-  internal int Row { get; set; }
-
-  internal int Column { get; set; }
-
-  internal string Formula { get; set; }
-
-  internal List<Token> Tokens { get; set; }
-
-  internal int tokenIx = 0;
-  internal int addressIx = 0;
-  internal CellsStoreEnumerator<object> iterator;
-  internal ExcelWorksheet ws;
-}
diff --git a/EPPlus/FormulaParsing/EpplusExcelDataProvider.cs b/EPPlus/FormulaParsing/EpplusExcelDataProvider.cs
deleted file mode 100644
index 8dfe6d1..0000000
--- a/EPPlus/FormulaParsing/EpplusExcelDataProvider.cs
+++ /dev/null
@@ -1,359 +0,0 @@
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExcelUtilities;
-using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-using OfficeOpenXml.Style.XmlAccess;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.FormulaParsing;
-
-public class EpplusExcelDataProvider : ExcelDataProvider {
-  public class RangeInfo : IRangeInfo {
-    internal ExcelWorksheet _ws;
-    private readonly CellsStoreEnumerator<object> _values;
-    private readonly int _fromRow;
-    private readonly int _toRow;
-    private readonly int _fromCol;
-    private readonly int _toCol;
-    private int _cellCount;
-    private readonly ExcelAddressBase _address;
-    private readonly ICellInfo _cell;
-
-    public RangeInfo(ExcelWorksheet ws, int fromRow, int fromCol, int toRow, int toCol) {
-      _ws = ws;
-      _fromRow = fromRow;
-      _fromCol = fromCol;
-      _toRow = toRow;
-      _toCol = toCol;
-      _address = new(_fromRow, _fromCol, _toRow, _toCol);
-      _address._ws = ws.Name;
-      _values = new(ws._values, _fromRow, _fromCol, _toRow, _toCol);
-      _cell = new CellInfo(_ws, _values);
-    }
-
-    public int GetNCells() {
-      return ((_toRow - _fromRow) + 1) * ((_toCol - _fromCol) + 1);
-    }
-
-    public bool IsEmpty {
-      get {
-        if (_cellCount > 0) {
-          return false;
-        }
-        if (_values.Next()) {
-          _values.Reset();
-          return false;
-        }
-        return true;
-      }
-    }
-
-    public bool IsMulti {
-      get {
-        if (_cellCount == 0) {
-          if (_values.Next() && _values.Next()) {
-            _values.Reset();
-            return true;
-          }
-          _values.Reset();
-          return false;
-        }
-        if (_cellCount > 1) {
-          return true;
-        }
-        return false;
-      }
-    }
-
-    public ICellInfo Current => _cell;
-
-    public ExcelWorksheet Worksheet => _ws;
-
-    public void Dispose() {}
-
-    object IEnumerator.Current => this;
-
-    public bool MoveNext() {
-      _cellCount++;
-      return _values.MoveNext();
-    }
-
-    public void Reset() {
-      _values.Init();
-    }
-
-    public bool NextCell() {
-      _cellCount++;
-      return _values.MoveNext();
-    }
-
-    public IEnumerator<ICellInfo> GetEnumerator() {
-      Reset();
-      return this;
-    }
-
-    IEnumerator IEnumerable.GetEnumerator() {
-      return this;
-    }
-
-    public ExcelAddressBase Address => _address;
-
-    public object GetValue(int row, int col) {
-      return _ws.GetValue(row, col);
-    }
-
-    public object GetOffset(int rowOffset, int colOffset) {
-      if (_values.Row < _fromRow || _values.Column < _fromCol) {
-        return _ws.GetValue(_fromRow + rowOffset, _fromCol + colOffset);
-      }
-      return _ws.GetValue(_values.Row + rowOffset, _values.Column + colOffset);
-    }
-  }
-
-  public class CellInfo : ICellInfo {
-    private readonly ExcelWorksheet _ws;
-    private readonly CellsStoreEnumerator<object> _values;
-
-    internal CellInfo(ExcelWorksheet ws, CellsStoreEnumerator<object> values) {
-      _ws = ws;
-      _values = values;
-    }
-
-    public string Address => _values.CellAddress;
-
-    public int Row => _values.Row;
-
-    public int Column => _values.Column;
-
-    public string Formula => _ws.GetFormula(_values.Row, _values.Column);
-
-    public object Value => _values.Value;
-
-    public double ValueDouble => ConvertUtil.GetValueDouble(_values.Value, true);
-
-    public double ValueDoubleLogical => ConvertUtil.GetValueDouble(_values.Value);
-
-    public bool IsHiddenRow {
-      get {
-        var row = _ws._values.GetValue(_values.Row, 0) as RowInternal;
-        if (row != null) {
-          return row.Hidden || row.Height == 0;
-        }
-        return false;
-      }
-    }
-
-    public bool IsExcelError => ExcelErrorValue.Values.IsErrorValue(_values.Value);
-
-    public IList<Token> Tokens => _ws._formulaTokens.GetValue(_values.Row, _values.Column);
-  }
-
-  public class NameInfo : INameInfo {
-    public ulong Id { get; set; }
-
-    public string Worksheet { get; set; }
-
-    public string Name { get; set; }
-
-    public string Formula { get; set; }
-
-    public IList<Token> Tokens { get; internal set; }
-
-    public object Value { get; set; }
-  }
-
-  private readonly ExcelWorkbook _workbook;
-  private ExcelWorksheet _currentWorksheet;
-  private Dictionary<ulong, INameInfo> _names = new();
-
-  public EpplusExcelDataProvider(ExcelWorkbook workbook) {
-    _workbook = workbook;
-  }
-
-  public override ExcelNamedRangeCollection GetWorksheetNames(string worksheet) {
-    var ws = _workbook.Worksheets[worksheet];
-    if (ws != null) {
-      return ws.Names;
-    }
-    return null;
-  }
-
-  public override ExcelNamedRangeCollection GetWorkbookNameValues() {
-    return _workbook.Names;
-  }
-
-  public override IRangeInfo GetRange(
-      string worksheet,
-      int fromRow,
-      int fromCol,
-      int toRow,
-      int toCol) {
-    SetCurrentWorksheet(worksheet);
-    var wsName = string.IsNullOrEmpty(worksheet) ? _currentWorksheet.Name : worksheet;
-    var ws = _workbook.Worksheets[wsName];
-    return new RangeInfo(ws, fromRow, fromCol, toRow, toCol);
-  }
-
-  public override IRangeInfo GetRange(string worksheet, int row, int column, string address) {
-    var addr = new ExcelAddress(worksheet, address);
-    if (addr.Table != null) {
-      addr.SetRcFromTable(_workbook, new(row, column, row, column));
-    }
-    //SetCurrentWorksheet(addr.WorkSheet);
-    var wsName = string.IsNullOrEmpty(addr.WorkSheet) ? _currentWorksheet.Name : addr.WorkSheet;
-    var ws = _workbook.Worksheets[wsName];
-    //return new CellsStoreEnumerator<object>(ws._values, addr._fromRow, addr._fromCol, addr._toRow, addr._toCol);
-    return new RangeInfo(ws, addr._fromRow, addr._fromCol, addr._toRow, addr._toCol);
-  }
-
-  public override INameInfo GetName(string worksheet, string name) {
-    ExcelNamedRange nameItem;
-    ulong id;
-    ExcelWorksheet ws;
-    if (string.IsNullOrEmpty(worksheet)) {
-      if (_workbook.Names.ContainsKey(name)) {
-        nameItem = _workbook.Names[name];
-      } else {
-        return null;
-      }
-      ws = null;
-    } else {
-      ws = _workbook.Worksheets[worksheet];
-      if (ws != null && ws.Names.ContainsKey(name)) {
-        nameItem = ws.Names[name];
-      } else if (_workbook.Names.ContainsKey(name)) {
-        nameItem = _workbook.Names[name];
-      } else {
-        return null;
-      }
-    }
-    id = ExcelCellBase.GetCellId(nameItem.LocalSheetId, nameItem.Index, 0);
-
-    if (_names.ContainsKey(id)) {
-      return _names[id];
-    }
-    var ni = new NameInfo {
-      Id = id,
-      Name = name,
-      Worksheet = nameItem.Worksheet == null ? nameItem._ws : nameItem.Worksheet.Name,
-      Formula = nameItem.Formula,
-    };
-    if (nameItem._fromRow > 0) {
-      ni.Value = new RangeInfo(
-          nameItem.Worksheet ?? ws,
-          nameItem._fromRow,
-          nameItem._fromCol,
-          nameItem._toRow,
-          nameItem._toCol);
-    } else {
-      ni.Value = nameItem.Value;
-    }
-    _names.Add(id, ni);
-    return ni;
-  }
-
-  public override IEnumerable<object> GetRangeValues(string address) {
-    SetCurrentWorksheet(ExcelAddressInfo.Parse(address));
-    var addr = new ExcelAddress(address);
-    var wsName = string.IsNullOrEmpty(addr.WorkSheet) ? _currentWorksheet.Name : addr.WorkSheet;
-    var ws = _workbook.Worksheets[wsName];
-    return (new CellsStoreEnumerator<object>(
-            ws._values,
-            addr._fromRow,
-            addr._fromCol,
-            addr._toRow,
-            addr._toCol));
-  }
-
-  public object GetValue(int row, int column) {
-    return _currentWorksheet._values.GetValue(row, column);
-  }
-
-  public bool IsMerged(int row, int column) {
-    //return _currentWorksheet._flags.GetFlagValue(row, column, CellFlags.Merged);
-    return _currentWorksheet.MergedCells[row, column] != null;
-  }
-
-  public bool IsHidden(int row, int column) {
-    return _currentWorksheet.Column(column).Hidden
-        || _currentWorksheet.Column(column).Width == 0
-        || _currentWorksheet.Row(row).Hidden
-        || _currentWorksheet.Row(column).Height == 0;
-  }
-
-  public override object GetCellValue(string sheetName, int row, int col) {
-    SetCurrentWorksheet(sheetName);
-    return _currentWorksheet._values.GetValue(row, col);
-  }
-
-  public override ExcelCellAddress GetDimensionEnd(string worksheet) {
-    ExcelCellAddress address = null;
-    try {
-      address = _workbook.Worksheets[worksheet].Dimension.End;
-    } catch {}
-
-    return address;
-  }
-
-  private void SetCurrentWorksheet(ExcelAddressInfo addressInfo) {
-    if (addressInfo.WorksheetIsSpecified) {
-      _currentWorksheet = _workbook.Worksheets[addressInfo.Worksheet];
-    } else if (_currentWorksheet == null) {
-      _currentWorksheet = _workbook.Worksheets.First();
-    }
-  }
-
-  private void SetCurrentWorksheet(string worksheetName) {
-    if (!string.IsNullOrEmpty(worksheetName)) {
-      _currentWorksheet = _workbook.Worksheets[worksheetName];
-    } else {
-      _currentWorksheet = _workbook.Worksheets.First();
-    }
-  }
-
-  public override int ExcelMaxColumns => ExcelPackage.MaxColumns;
-
-  public override int ExcelMaxRows => ExcelPackage.MaxRows;
-
-  public override string GetRangeFormula(string worksheetName, int row, int column) {
-    SetCurrentWorksheet(worksheetName);
-    return _currentWorksheet.GetFormula(row, column);
-  }
-
-  public override object GetRangeValue(string worksheetName, int row, int column) {
-    SetCurrentWorksheet(worksheetName);
-    return _currentWorksheet.GetValue(row, column);
-  }
-
-  public override string GetFormat(object value, string format) {
-    var styles = _workbook.Styles;
-    ExcelNumberFormatXml.ExcelFormatTranslator ft = null;
-    foreach (var f in styles.NumberFormats) {
-      if (f.Format == format) {
-        ft = f.FormatTranslator;
-        break;
-      }
-    }
-    if (ft == null) {
-      ft = new(format, -1);
-    }
-    return ExcelRangeBase.FormatValue(value, ft, format, ft.NetFormat);
-  }
-
-  public override List<Token> GetRangeFormulaTokens(string worksheetName, int row, int column) {
-    return _workbook.Worksheets[worksheetName]._formulaTokens.GetValue(row, column);
-  }
-
-  public override bool IsRowHidden(string worksheetName, int row) {
-    var b =
-        _workbook.Worksheets[worksheetName].Row(row).Height == 0
-            || _workbook.Worksheets[worksheetName].Row(row).Hidden;
-
-    return b;
-  }
-
-  public override void Reset() {
-    _names = new(); //Reset name cache.
-  }
-}
diff --git a/EPPlus/FormulaParsing/EpplusNameValueProvider.cs b/EPPlus/FormulaParsing/EpplusNameValueProvider.cs
deleted file mode 100644
index 65b9db3..0000000
--- a/EPPlus/FormulaParsing/EpplusNameValueProvider.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-namespace OfficeOpenXml.FormulaParsing;
-
-public class EpplusNameValueProvider : INameValueProvider {
-  private readonly ExcelDataProvider _excelDataProvider;
-  private ExcelNamedRangeCollection _values;
-
-  public EpplusNameValueProvider(ExcelDataProvider excelDataProvider) {
-    _excelDataProvider = excelDataProvider;
-    _values = _excelDataProvider.GetWorkbookNameValues();
-  }
-
-  public virtual bool IsNamedValue(string key, string ws) {
-    if (ws != null) {
-      var wsNames = _excelDataProvider.GetWorksheetNames(ws);
-      if (wsNames != null && wsNames.ContainsKey(key)) {
-        return true;
-      }
-    }
-    return _values != null && _values.ContainsKey(key);
-  }
-
-  public virtual object GetNamedValue(string key) {
-    return _values[key];
-  }
-
-  public virtual void Reload() {
-    _values = _excelDataProvider.GetWorkbookNameValues();
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/ExcelCellState.cs b/EPPlus/FormulaParsing/Excel/ExcelCellState.cs
deleted file mode 100644
index 3551b8a..0000000
--- a/EPPlus/FormulaParsing/Excel/ExcelCellState.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System;
-
-namespace OfficeOpenXml.FormulaParsing.Excel;
-
-[Flags]
-public enum ExcelCellState {
-  HiddenCell = 1,
-  ContainsError = 2,
-  IsResultOfSubtotal = 4,
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/ArgumentCollectionUtil.cs b/EPPlus/FormulaParsing/Excel/Functions/ArgumentCollectionUtil.cs
deleted file mode 100644
index 9f04f77..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/ArgumentCollectionUtil.cs
+++ /dev/null
@@ -1,83 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-public class ArgumentCollectionUtil {
-  private readonly DoubleEnumerableArgConverter _doubleEnumerableArgConverter;
-  private readonly ObjectEnumerableArgConverter _objectEnumerableArgConverter;
-
-  public ArgumentCollectionUtil()
-      : this(new(), new()) {}
-
-  public ArgumentCollectionUtil(
-      DoubleEnumerableArgConverter doubleEnumerableArgConverter,
-      ObjectEnumerableArgConverter objectEnumerableArgConverter) {
-    _doubleEnumerableArgConverter = doubleEnumerableArgConverter;
-    _objectEnumerableArgConverter = objectEnumerableArgConverter;
-  }
-
-  public virtual IEnumerable<double> ArgsToDoubleEnumerable(
-      bool ignoreHidden,
-      bool ignoreErrors,
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    return _doubleEnumerableArgConverter.ConvertArgs(
-        ignoreHidden,
-        ignoreErrors,
-        arguments,
-        context);
-  }
-
-  public virtual IEnumerable<object> ArgsToObjectEnumerable(
-      bool ignoreHidden,
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    return _objectEnumerableArgConverter.ConvertArgs(ignoreHidden, arguments, context);
-  }
-
-  public virtual double CalculateCollection(
-      IEnumerable<FunctionArgument> collection,
-      double result,
-      Func<FunctionArgument, double, double> action) {
-    foreach (var item in collection) {
-      if (item.Value is IEnumerable<FunctionArgument> value) {
-        result = CalculateCollection(value, result, action);
-      } else {
-        result = action(item, result);
-      }
-    }
-    return result;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/ArgumentParser.cs b/EPPlus/FormulaParsing/Excel/Functions/ArgumentParser.cs
deleted file mode 100644
index d198dea..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/ArgumentParser.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
-*
-* This library is free software; you can redistribute it and/or
-* modify it under the terms of the GNU Lesser General Public
-* License as published by the Free Software Foundation; either
-* version 2.1 of the License, or (at your option) any later version.
-
-* This library is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-* See the GNU Lesser General Public License for more details.
-*
-* The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
-* If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
-*
-* All code and executables are provided "as is" with no warranty either express or implied.
-* The author accepts no liability for any damage or loss of business that this product may cause.
-*
-* Code change notes:
-*
-* Author							Change						Date
-*******************************************************************************
-* Mats Alm   		                Added		                2013-12-03
-*******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-public abstract class ArgumentParser {
-  public abstract object Parse(object obj);
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/ArgumentParserFactory.cs b/EPPlus/FormulaParsing/Excel/Functions/ArgumentParserFactory.cs
deleted file mode 100644
index 817f85a..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/ArgumentParserFactory.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-public class ArgumentParserFactory {
-  public virtual ArgumentParser CreateArgumentParser(DataType dataType) {
-    switch (dataType) {
-      case DataType.Integer:
-        return new IntArgumentParser();
-      case DataType.Boolean:
-        return new BoolArgumentParser();
-      case DataType.Decimal:
-        return new DoubleArgumentParser();
-      default:
-        throw new InvalidOperationException("non supported argument parser type " + dataType);
-    }
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/ArgumentParsers.cs b/EPPlus/FormulaParsing/Excel/Functions/ArgumentParsers.cs
deleted file mode 100644
index 0a518f9..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/ArgumentParsers.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-using OfficeOpenXml.FormulaParsing.Utilities;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-public class ArgumentParsers {
-  private readonly Dictionary<DataType, ArgumentParser> _parsers = new();
-  private readonly ArgumentParserFactory _parserFactory;
-
-  public ArgumentParsers()
-      : this(new()) {}
-
-  public ArgumentParsers(ArgumentParserFactory factory) {
-    Require.That(factory).Named("argumentParserfactory").IsNotNull();
-    _parserFactory = factory;
-  }
-
-  public ArgumentParser GetParser(DataType dataType) {
-    if (!_parsers.ContainsKey(dataType)) {
-      if (!_parsers.ContainsKey(dataType)) {
-        _parsers.Add(dataType, _parserFactory.CreateArgumentParser(dataType));
-      }
-    }
-    return _parsers[dataType];
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/BoolArgumentParser.cs b/EPPlus/FormulaParsing/Excel/Functions/BoolArgumentParser.cs
deleted file mode 100644
index 3f24d9c..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/BoolArgumentParser.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.Utilities;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-public class BoolArgumentParser : ArgumentParser {
-  public override object Parse(object obj) {
-    if (obj is ExcelDataProvider.IRangeInfo info) {
-      var r = info.FirstOrDefault();
-      obj = r?.Value;
-    }
-    if (obj == null) {
-      return false;
-    }
-    if (obj is bool b) {
-      return b;
-    }
-    if (obj.IsNumeric()) {
-      return Convert.ToBoolean(obj);
-    }
-    if (bool.TryParse(obj.ToString(), out var result)) {
-      return result;
-    }
-    return result;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/BuiltInFunctions.cs b/EPPlus/FormulaParsing/Excel/Functions/BuiltInFunctions.cs
deleted file mode 100644
index c7d56b2..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/BuiltInFunctions.cs
+++ /dev/null
@@ -1,202 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using OfficeOpenXml.FormulaParsing.Excel.Functions.Database;
-using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-using OfficeOpenXml.FormulaParsing.Excel.Functions.Information;
-using OfficeOpenXml.FormulaParsing.Excel.Functions.Logical;
-using OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-using OfficeOpenXml.FormulaParsing.Excel.Functions.Numeric;
-using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
-using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-public class BuiltInFunctions : FunctionsModule {
-  public BuiltInFunctions() {
-    // Text
-    Functions["len"] = new Len();
-    Functions["lower"] = new Lower();
-    Functions["upper"] = new Upper();
-    Functions["left"] = new Left();
-    Functions["right"] = new Right();
-    Functions["mid"] = new Mid();
-    Functions["replace"] = new Replace();
-    Functions["rept"] = new Rept();
-    Functions["substitute"] = new Substitute();
-    Functions["concatenate"] = new Concatenate();
-    Functions["char"] = new CharFunction();
-    Functions["exact"] = new Exact();
-    Functions["find"] = new Find();
-    Functions["fixed"] = new Fixed();
-    Functions["proper"] = new Proper();
-    Functions["text"] = new Text.Text();
-    Functions["t"] = new T();
-    Functions["hyperlink"] = new Hyperlink();
-    // Numbers
-    Functions["int"] = new CInt();
-    // Math
-    Functions["abs"] = new Abs();
-    Functions["asin"] = new Asin();
-    Functions["asinh"] = new Asinh();
-    Functions["cos"] = new Cos();
-    Functions["cosh"] = new Cosh();
-    Functions["power"] = new Power();
-    Functions["sign"] = new Sign();
-    Functions["sqrt"] = new Sqrt();
-    Functions["sqrtpi"] = new SqrtPi();
-    Functions["pi"] = new Pi();
-    Functions["product"] = new Product();
-    Functions["ceiling"] = new Ceiling();
-    Functions["count"] = new Count();
-    Functions["counta"] = new CountA();
-    Functions["countblank"] = new CountBlank();
-    Functions["countif"] = new CountIf();
-    Functions["countifs"] = new CountIfs();
-    Functions["fact"] = new Fact();
-    Functions["floor"] = new Floor();
-    Functions["sin"] = new Sin();
-    Functions["sinh"] = new Sinh();
-    Functions["sum"] = new Sum();
-    Functions["sumif"] = new SumIf();
-    Functions["sumifs"] = new SumIfs();
-    Functions["sumproduct"] = new SumProduct();
-    Functions["sumsq"] = new Sumsq();
-    Functions["stdev"] = new Stdev();
-    Functions["stdevp"] = new StdevP();
-    Functions["stdev.s"] = new Stdev();
-    Functions["stdev.p"] = new StdevP();
-    Functions["subtotal"] = new Subtotal();
-    Functions["exp"] = new Exp();
-    Functions["log"] = new Log();
-    Functions["log10"] = new Log10();
-    Functions["ln"] = new Ln();
-    Functions["max"] = new Max();
-    Functions["maxa"] = new Maxa();
-    Functions["median"] = new Median();
-    Functions["min"] = new Min();
-    Functions["mina"] = new Mina();
-    Functions["mod"] = new Mod();
-    Functions["average"] = new Average();
-    Functions["averagea"] = new AverageA();
-    Functions["averageif"] = new AverageIf();
-    Functions["averageifs"] = new AverageIfs();
-    Functions["round"] = new Round();
-    Functions["rounddown"] = new Rounddown();
-    Functions["roundup"] = new Roundup();
-    Functions["rand"] = new Rand();
-    Functions["randbetween"] = new RandBetween();
-    Functions["quotient"] = new Quotient();
-    Functions["trunc"] = new Trunc();
-    Functions["tan"] = new Tan();
-    Functions["tanh"] = new Tanh();
-    Functions["atan"] = new Atan();
-    Functions["atan2"] = new Atan2();
-    Functions["atanh"] = new Atanh();
-    Functions["acos"] = new Acos();
-    Functions["acosh"] = new Acosh();
-    Functions["var"] = new Var();
-    Functions["varp"] = new VarP();
-    Functions["large"] = new Large();
-    Functions["small"] = new Small();
-    Functions["degrees"] = new Degrees();
-    // Information
-    Functions["isblank"] = new IsBlank();
-    Functions["isnumber"] = new IsNumber();
-    Functions["istext"] = new IsText();
-    Functions["isnontext"] = new IsNonText();
-    Functions["iserror"] = new IsError();
-    Functions["iserr"] = new IsErr();
-    Functions["error.type"] = new ErrorType();
-    Functions["iseven"] = new IsEven();
-    Functions["isodd"] = new IsOdd();
-    Functions["islogical"] = new IsLogical();
-    Functions["isna"] = new IsNa();
-    Functions["na"] = new Na();
-    Functions["n"] = new N();
-    // Logical
-    Functions["if"] = new If();
-    Functions["iferror"] = new IfError();
-    Functions["ifna"] = new IfNa();
-    Functions["not"] = new Not();
-    Functions["and"] = new And();
-    Functions["or"] = new Or();
-    Functions["true"] = new True();
-    Functions["false"] = new False();
-    // Reference and lookup
-    Functions["address"] = new Address();
-    Functions["hlookup"] = new HLookup();
-    Functions["vlookup"] = new VLookup();
-    Functions["lookup"] = new Lookup();
-    Functions["match"] = new Match();
-    Functions["row"] = new Row {
-      SkipArgumentEvaluation = true,
-    };
-    Functions["rows"] = new Rows {
-      SkipArgumentEvaluation = true,
-    };
-    Functions["column"] = new Column {
-      SkipArgumentEvaluation = true,
-    };
-    Functions["columns"] = new Columns {
-      SkipArgumentEvaluation = true,
-    };
-    Functions["choose"] = new Choose();
-    Functions["index"] = new Index();
-    Functions["indirect"] = new Indirect();
-    Functions["offset"] = new Offset {
-      SkipArgumentEvaluation = true,
-    };
-    // Date
-    Functions["date"] = new Date();
-    Functions["today"] = new Today();
-    Functions["now"] = new Now();
-    Functions["day"] = new Day();
-    Functions["month"] = new Month();
-    Functions["year"] = new Year();
-    Functions["time"] = new Time();
-    Functions["hour"] = new Hour();
-    Functions["minute"] = new Minute();
-    Functions["second"] = new Second();
-    Functions["weeknum"] = new Weeknum();
-    Functions["weekday"] = new Weekday();
-    Functions["days360"] = new Days360();
-    Functions["yearfrac"] = new Yearfrac();
-    Functions["edate"] = new Edate();
-    Functions["eomonth"] = new Eomonth();
-    Functions["isoweeknum"] = new IsoWeekNum();
-    Functions["workday"] = new Workday();
-    // Database
-    Functions["dget"] = new Dget();
-    Functions["dcount"] = new Dcount();
-    Functions["dcounta"] = new DcountA();
-    Functions["dmax"] = new Dmax();
-    Functions["dmin"] = new Dmin();
-    Functions["dsum"] = new Dsum();
-    Functions["daverage"] = new Daverage();
-    Functions["dvar"] = new Dvar();
-    Functions["dvarp"] = new Dvarp();
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/CellStateHelper.cs b/EPPlus/FormulaParsing/Excel/Functions/CellStateHelper.cs
deleted file mode 100644
index e461919..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/CellStateHelper.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-internal static class CellStateHelper {
-  private static bool IsSubTotal(ExcelDataProvider.ICellInfo c) {
-    var tokens = c.Tokens;
-    if (tokens == null) {
-      return false;
-    }
-    return c.Tokens.Any(token =>
-        token.TokenType == TokenType.Function
-            && token.Value.Equals("SUBTOTAL", StringComparison.InvariantCultureIgnoreCase));
-  }
-
-  internal static bool ShouldIgnore(
-      bool ignoreHiddenValues,
-      ExcelDataProvider.ICellInfo c,
-      ParsingContext context) {
-    return (ignoreHiddenValues && c.IsHiddenRow)
-        || (context.Scopes.Current.IsSubtotal && IsSubTotal(c));
-  }
-
-  internal static bool ShouldIgnore(
-      bool ignoreHiddenValues,
-      FunctionArgument arg,
-      ParsingContext context) {
-    return (ignoreHiddenValues && arg.ExcelStateFlagIsSet(ExcelCellState.HiddenCell));
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/CollectionFlattener.cs b/EPPlus/FormulaParsing/Excel/Functions/CollectionFlattener.cs
deleted file mode 100644
index dfcf5d9..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/CollectionFlattener.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-public abstract class CollectionFlattener<T> {
-  public virtual IEnumerable<T> FuncArgsToFlatEnumerable(
-      IEnumerable<FunctionArgument> arguments,
-      Action<FunctionArgument, IList<T>> convertFunc) {
-    var argList = new List<T>();
-    FuncArgsToFlatEnumerable(arguments, argList, convertFunc);
-    return argList;
-  }
-
-  private void FuncArgsToFlatEnumerable(
-      IEnumerable<FunctionArgument> arguments,
-      List<T> argList,
-      Action<FunctionArgument, IList<T>> convertFunc) {
-    foreach (var arg in arguments) {
-      if (arg.Value is IEnumerable<FunctionArgument> value) {
-        FuncArgsToFlatEnumerable(value, argList, convertFunc);
-      } else {
-        convertFunc(arg, argList);
-      }
-    }
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/CompileResultValidator.cs b/EPPlus/FormulaParsing/Excel/Functions/CompileResultValidator.cs
deleted file mode 100644
index e936798..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/CompileResultValidator.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-26
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-public abstract class CompileResultValidator {
-  public abstract void Validate(object obj);
-
-  private static CompileResultValidator _empty;
-
-  public static CompileResultValidator Empty =>
-    _empty ?? (_empty = new EmptyCompileResultValidator());
-}
-
-internal class EmptyCompileResultValidator : CompileResultValidator {
-  public override void Validate(object obj) {
-    // empty validator - do nothing
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/CompileResultValidators.cs b/EPPlus/FormulaParsing/Excel/Functions/CompileResultValidators.cs
deleted file mode 100644
index 40f74c5..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/CompileResultValidators.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-26
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-public class CompileResultValidators {
-  private readonly Dictionary<DataType, CompileResultValidator> _validators = new();
-
-  private CompileResultValidator CreateOrGet(DataType dataType) {
-    if (_validators.ContainsKey(dataType)) {
-      return _validators[dataType];
-    }
-    if (dataType == DataType.Decimal) {
-      return _validators[DataType.Decimal] = new DecimalCompileResultValidator();
-    }
-    return CompileResultValidator.Empty;
-  }
-
-  public CompileResultValidator GetValidator(DataType dataType) {
-    return CreateOrGet(dataType);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/DSum.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/DSum.cs
deleted file mode 100644
index 5522539..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Database/DSum.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-04-19
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database;
-
-public class Dsum : DatabaseFunction {
-  public Dsum()
-      : this(new()) {}
-
-  public Dsum(RowMatcher rowMatcher)
-      : base(rowMatcher) {}
-
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 3);
-    var values = GetMatchingValues(arguments, context);
-    if (!values.Any()) {
-      return CreateResult(0d, DataType.Integer);
-    }
-    return CreateResult(values.Sum(), DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/DatabaseFunction.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/DatabaseFunction.cs
deleted file mode 100644
index f686f8e..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Database/DatabaseFunction.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-04-19
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database;
-
-public abstract class DatabaseFunction : ExcelFunction {
-  protected RowMatcher RowMatcher { get; private set; }
-
-  public DatabaseFunction()
-      : this(new()) {}
-
-  public DatabaseFunction(RowMatcher rowMatcher) {
-    RowMatcher = rowMatcher;
-  }
-
-  protected IEnumerable<double> GetMatchingValues(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    var dbAddress = arguments.ElementAt(0).ValueAsRangeInfo.Address.Address;
-    //var field = ArgToString(arguments, 1).ToLower(CultureInfo.InvariantCulture);
-    var field = arguments.ElementAt(1).Value;
-    var criteriaRange = arguments.ElementAt(2).ValueAsRangeInfo.Address.Address;
-
-    var db = new ExcelDatabase(context.ExcelDataProvider, dbAddress);
-    var criteria = new ExcelDatabaseCriteria(context.ExcelDataProvider, criteriaRange);
-    var values = new List<double>();
-
-    while (db.HasMoreRows) {
-      var dataRow = db.Read();
-      if (!RowMatcher.IsMatch(dataRow, criteria)) {
-        continue;
-      }
-      var candidate = ConvertUtil.IsNumeric(field)
-          ? dataRow[(int)ConvertUtil.GetValueDouble(field)]
-          : dataRow[field.ToString().ToLower(CultureInfo.InvariantCulture)];
-      if (ConvertUtil.IsNumeric(candidate)) {
-        values.Add(ConvertUtil.GetValueDouble(candidate));
-      }
-    }
-    return values;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/Daverage.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/Daverage.cs
deleted file mode 100644
index 21a890a..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Database/Daverage.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-04-19
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database;
-
-public class Daverage : DatabaseFunction {
-  public Daverage()
-      : this(new()) {}
-
-  public Daverage(RowMatcher rowMatcher)
-      : base(rowMatcher) {}
-
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 3);
-    var values = GetMatchingValues(arguments, context);
-    if (!values.Any()) {
-      return CreateResult(0d, DataType.Integer);
-    }
-    return CreateResult(values.Average(), DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/Dcount.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/Dcount.cs
deleted file mode 100644
index 2ad31fa..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Database/Dcount.cs
+++ /dev/null
@@ -1,79 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-04-06
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database;
-
-public class Dcount : ExcelFunction {
-  private readonly RowMatcher _rowMatcher;
-
-  public Dcount()
-      : this(new()) {}
-
-  public Dcount(RowMatcher rowMatcher) {
-    _rowMatcher = rowMatcher;
-  }
-
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var dbAddress = arguments.ElementAt(0).ValueAsRangeInfo.Address.Address;
-    string field = null;
-    string criteriaRange = null;
-    if (arguments.Count() == 2) {
-      criteriaRange = arguments.ElementAt(1).ValueAsRangeInfo.Address.Address;
-    } else {
-      field = ArgToString(arguments, 1).ToLower(CultureInfo.InvariantCulture);
-      criteriaRange = arguments.ElementAt(2).ValueAsRangeInfo.Address.Address;
-    }
-    var db = new ExcelDatabase(context.ExcelDataProvider, dbAddress);
-    var criteria = new ExcelDatabaseCriteria(context.ExcelDataProvider, criteriaRange);
-
-    var nHits = 0;
-    while (db.HasMoreRows) {
-      var dataRow = db.Read();
-      if (_rowMatcher.IsMatch(dataRow, criteria)) {
-        // if a fieldname is supplied, count only this row if the value
-        // of the supplied field is numeric.
-        if (!string.IsNullOrEmpty(field)) {
-          var candidate = dataRow[field];
-          if (ConvertUtil.IsNumeric(candidate)) {
-            nHits++;
-          }
-        } else {
-          // no fieldname was supplied, always count matching row.
-          nHits++;
-        }
-      }
-    }
-    return CreateResult(nHits, DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/DcountA.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/DcountA.cs
deleted file mode 100644
index 3af4c77..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Database/DcountA.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-04-06
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database;
-
-public class DcountA : DatabaseFunction {
-  public DcountA()
-      : this(new()) {}
-
-  public DcountA(RowMatcher rowMatcher)
-      : base(rowMatcher) {}
-
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var dbAddress = arguments.ElementAt(0).ValueAsRangeInfo.Address.Address;
-    string field = null;
-    string criteriaRange;
-    if (arguments.Count() == 2) {
-      criteriaRange = arguments.ElementAt(1).ValueAsRangeInfo.Address.Address;
-    } else {
-      field = ArgToString(arguments, 1).ToLower(CultureInfo.InvariantCulture);
-      criteriaRange = arguments.ElementAt(2).ValueAsRangeInfo.Address.Address;
-    }
-    var db = new ExcelDatabase(context.ExcelDataProvider, dbAddress);
-    var criteria = new ExcelDatabaseCriteria(context.ExcelDataProvider, criteriaRange);
-
-    var nHits = 0;
-    while (db.HasMoreRows) {
-      var dataRow = db.Read();
-      if (RowMatcher.IsMatch(dataRow, criteria)) {
-        // if a fieldname is supplied, count only this row if the value
-        // of the supplied field is not blank.
-        if (!string.IsNullOrEmpty(field)) {
-          var candidate = dataRow[field];
-          if (ShouldCount(candidate)) {
-            nHits++;
-          }
-        } else {
-          // no fieldname was supplied, always count matching row.
-          nHits++;
-        }
-      }
-    }
-    return CreateResult(nHits, DataType.Integer);
-  }
-
-  private bool ShouldCount(object value) {
-    if (value == null) {
-      return false;
-    }
-    return (!string.IsNullOrEmpty(value.ToString()));
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/Dget.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/Dget.cs
deleted file mode 100644
index e8aa790..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Database/Dget.cs
+++ /dev/null
@@ -1,65 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-04-06
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database;
-
-public class Dget : DatabaseFunction {
-  public Dget()
-      : this(new()) {}
-
-  public Dget(RowMatcher rowMatcher)
-      : base(rowMatcher) {}
-
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 3);
-    var dbAddress = arguments.ElementAt(0).ValueAsRangeInfo.Address.Address;
-    var field = ArgToString(arguments, 1).ToLower(CultureInfo.InvariantCulture);
-    var criteriaRange = arguments.ElementAt(2).ValueAsRangeInfo.Address.Address;
-
-    var db = new ExcelDatabase(context.ExcelDataProvider, dbAddress);
-    var criteria = new ExcelDatabaseCriteria(context.ExcelDataProvider, criteriaRange);
-
-    var nHits = 0;
-    object retVal = null;
-    while (db.HasMoreRows) {
-      var dataRow = db.Read();
-      if (!RowMatcher.IsMatch(dataRow, criteria)) {
-        continue;
-      }
-      if (++nHits > 1) {
-        return CreateResult(ExcelErrorValue.Values.Num, DataType.ExcelError);
-      }
-      retVal = dataRow[field];
-    }
-    return new CompileResultFactory().Create(retVal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/Dmax.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/Dmax.cs
deleted file mode 100644
index 62f7d1c..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Database/Dmax.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-04-19
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database;
-
-public class Dmax : DatabaseFunction {
-  public Dmax()
-      : this(new()) {}
-
-  public Dmax(RowMatcher rowMatcher)
-      : base(rowMatcher) {}
-
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 3);
-    var values = GetMatchingValues(arguments, context);
-    if (!values.Any()) {
-      return CreateResult(0d, DataType.Integer);
-    }
-    return CreateResult(values.Max(), DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/Dmin.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/Dmin.cs
deleted file mode 100644
index 8203884..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Database/Dmin.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-04-19
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database;
-
-public class Dmin : DatabaseFunction {
-  public Dmin()
-      : this(new()) {}
-
-  public Dmin(RowMatcher rowMatcher)
-      : base(rowMatcher) {}
-
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 3);
-    var values = GetMatchingValues(arguments, context);
-    if (!values.Any()) {
-      return CreateResult(0d, DataType.Integer);
-    }
-    return CreateResult(values.Min(), DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/Dvar.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/Dvar.cs
deleted file mode 100644
index d961b82..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Database/Dvar.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-04-19
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database;
-
-public class Dvar : DatabaseFunction {
-  public Dvar()
-      : this(new()) {}
-
-  public Dvar(RowMatcher rowMatcher)
-      : base(rowMatcher) {}
-
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 3);
-    var values = GetMatchingValues(arguments, context);
-    if (!values.Any()) {
-      return CreateResult(0d, DataType.Integer);
-    }
-    return CreateResult(VarMethods.Var(values), DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/Dvarp.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/Dvarp.cs
deleted file mode 100644
index 7c43e88..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Database/Dvarp.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-04-19
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database;
-
-public class Dvarp : DatabaseFunction {
-  public Dvarp()
-      : this(new()) {}
-
-  public Dvarp(RowMatcher rowMatcher)
-      : base(rowMatcher) {}
-
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 3);
-    var values = GetMatchingValues(arguments, context);
-    if (!values.Any()) {
-      return CreateResult(0d, DataType.Integer);
-    }
-    return CreateResult(VarMethods.VarP(values), DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabase.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabase.cs
deleted file mode 100644
index 90e3f97..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabase.cs
+++ /dev/null
@@ -1,81 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-04-06
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Globalization;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database;
-
-public class ExcelDatabase {
-  private readonly ExcelDataProvider _dataProvider;
-  private readonly int _fromCol;
-  private readonly int _toCol;
-  private readonly int _fieldRow;
-  private readonly int _endRow;
-  private readonly string _worksheet;
-  private int _rowIndex;
-  private readonly List<ExcelDatabaseField> _fields = new();
-
-  public IEnumerable<ExcelDatabaseField> Fields => _fields;
-
-  public ExcelDatabase(ExcelDataProvider dataProvider, string range) {
-    _dataProvider = dataProvider;
-    var address = new ExcelAddressBase(range);
-    _fromCol = address._fromCol;
-    _toCol = address._toCol;
-    _fieldRow = address._fromRow;
-    _endRow = address._toRow;
-    _worksheet = address.WorkSheet;
-    _rowIndex = _fieldRow;
-    Initialize();
-  }
-
-  private void Initialize() {
-    var fieldIx = 0;
-    for (var colIndex = _fromCol; colIndex <= _toCol; colIndex++) {
-      var nameObj = GetCellValue(_fieldRow, colIndex);
-      var name =
-          nameObj != null ? nameObj.ToString().ToLower(CultureInfo.InvariantCulture) : string.Empty;
-      _fields.Add(new(name, fieldIx++));
-    }
-  }
-
-  private object GetCellValue(int row, int col) {
-    return _dataProvider.GetRangeValue(_worksheet, row, col);
-  }
-
-  public bool HasMoreRows => _rowIndex < _endRow;
-
-  public ExcelDatabaseRow Read() {
-    var retVal = new ExcelDatabaseRow();
-    _rowIndex++;
-    foreach (var field in Fields) {
-      var colIndex = _fromCol + field.ColIndex;
-      var val = GetCellValue(_rowIndex, colIndex);
-      retVal[field.FieldName] = val;
-    }
-    return retVal;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseCriteria.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseCriteria.cs
deleted file mode 100644
index f8b8846..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseCriteria.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-04-06
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Globalization;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database;
-
-public class ExcelDatabaseCriteria {
-  private readonly ExcelDataProvider _dataProvider;
-  private readonly int _fromCol;
-  private readonly int _toCol;
-  private readonly string _worksheet;
-  private readonly int _fieldRow;
-  private readonly Dictionary<ExcelDatabaseCriteriaField, object> _criterias = new();
-
-  public ExcelDatabaseCriteria(ExcelDataProvider dataProvider, string range) {
-    _dataProvider = dataProvider;
-    var address = new ExcelAddressBase(range);
-    _fromCol = address._fromCol;
-    _toCol = address._toCol;
-    _worksheet = address.WorkSheet;
-    _fieldRow = address._fromRow;
-    Initialize();
-  }
-
-  private void Initialize() {
-    for (var x = _fromCol; x <= _toCol; x++) {
-      var fieldObj = _dataProvider.GetCellValue(_worksheet, _fieldRow, x);
-      var val = _dataProvider.GetCellValue(_worksheet, _fieldRow + 1, x);
-      if (fieldObj != null && val != null) {
-        if (fieldObj is string) {
-          var field = new ExcelDatabaseCriteriaField(
-              fieldObj.ToString().ToLower(CultureInfo.InvariantCulture));
-          _criterias.Add(field, val);
-        } else if (ConvertUtil.IsNumeric(fieldObj)) {
-          var field = new ExcelDatabaseCriteriaField((int)fieldObj);
-          _criterias.Add(field, val);
-        }
-      }
-    }
-  }
-
-  public virtual IDictionary<ExcelDatabaseCriteriaField, object> Items => _criterias;
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseCriteriaField.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseCriteriaField.cs
deleted file mode 100644
index eec151c..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseCriteriaField.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-04-19
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database;
-
-public class ExcelDatabaseCriteriaField {
-  public ExcelDatabaseCriteriaField(string fieldName) {
-    FieldName = fieldName;
-  }
-
-  public ExcelDatabaseCriteriaField(int fieldIndex) {
-    FieldIndex = fieldIndex;
-  }
-
-  public override string ToString() {
-    if (!string.IsNullOrEmpty(FieldName)) {
-      return FieldName;
-    }
-    return base.ToString();
-  }
-
-  public string FieldName { get; private set; }
-
-  public int? FieldIndex { get; private set; }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseField.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseField.cs
deleted file mode 100644
index 9578486..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseField.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-04-06
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database;
-
-public class ExcelDatabaseField {
-  public string FieldName { get; private set; }
-
-  public int ColIndex { get; private set; }
-
-  public ExcelDatabaseField(string fieldName, int colIndex) {
-    FieldName = fieldName;
-    ColIndex = colIndex;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseRow.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseRow.cs
deleted file mode 100644
index e3c9a12..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseRow.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-04-19
- *******************************************************************************/
-
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database;
-
-public class ExcelDatabaseRow {
-  private readonly Dictionary<int, string> _fieldIndexes = new();
-  private readonly Dictionary<string, object> _items = new();
-  private int _colIndex = 1;
-
-  public object this[string field] {
-    get => _items[field];
-    set {
-      _items[field] = value;
-      _fieldIndexes[_colIndex++] = field;
-    }
-  }
-
-  public object this[int index] {
-    get {
-      var field = _fieldIndexes[index];
-      return _items[field];
-    }
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/RowMatcher.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/RowMatcher.cs
deleted file mode 100644
index 3493872..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Database/RowMatcher.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-04-06
- *******************************************************************************/
-
-using OfficeOpenXml.FormulaParsing.ExcelUtilities;
-using OfficeOpenXml.FormulaParsing.Utilities;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database;
-
-public class RowMatcher {
-  private readonly WildCardValueMatcher _wildCardValueMatcher;
-  private readonly NumericExpressionEvaluator _numericExpressionEvaluator;
-
-  public RowMatcher()
-      : this(new(), new()) {}
-
-  public RowMatcher(
-      WildCardValueMatcher wildCardValueMatcher,
-      NumericExpressionEvaluator numericExpressionEvaluator) {
-    _wildCardValueMatcher = wildCardValueMatcher;
-    _numericExpressionEvaluator = numericExpressionEvaluator;
-  }
-
-  public bool IsMatch(ExcelDatabaseRow row, ExcelDatabaseCriteria criteria) {
-    var retVal = true;
-    foreach (var c in criteria.Items) {
-      var candidate = c.Key.FieldIndex.HasValue
-          ? row[c.Key.FieldIndex.Value]
-          : row[c.Key.FieldName];
-      var crit = c.Value;
-      if (candidate.IsNumeric() && crit.IsNumeric()) {
-        if (System.Math.Abs(
-                ConvertUtil.GetValueDouble(candidate) - ConvertUtil.GetValueDouble(crit))
-            > double.Epsilon) {
-          return false;
-        }
-      } else {
-        var criteriaString = crit.ToString();
-        if (!Evaluate(candidate, criteriaString)) {
-          return false;
-        }
-      }
-    }
-    return retVal;
-  }
-
-  private bool Evaluate(object obj, string expression) {
-    if (obj == null) {
-      return false;
-    }
-    double? candidate = default(double?);
-    if (ConvertUtil.IsNumeric(obj)) {
-      candidate = ConvertUtil.GetValueDouble(obj);
-    }
-    if (candidate.HasValue) {
-      return _numericExpressionEvaluator.Evaluate(candidate.Value, expression);
-    }
-    return _wildCardValueMatcher.IsMatch(expression, obj.ToString()) == 0;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Date.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Date.cs
deleted file mode 100644
index e2e8ad9..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Date.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-public class Date : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 3);
-    var year = ArgToInt(arguments, 0);
-    var month = ArgToInt(arguments, 1);
-    var day = ArgToInt(arguments, 2);
-    var date = new System.DateTime(year, 1, 1);
-    month -= 1;
-    date = date.AddMonths(month);
-    date = date.AddDays(day - 1);
-    return CreateResult(date.ToOADate(), DataType.Date);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/DateParsingFunction.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/DateParsingFunction.cs
deleted file mode 100644
index 47143ef..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/DateParsingFunction.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System.Collections.Generic;
-using System.Globalization;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-public abstract class DateParsingFunction : ExcelFunction {
-  protected System.DateTime ParseDate(IEnumerable<FunctionArgument> arguments, object dateObj) {
-    System.DateTime date;
-    if (dateObj is string) {
-      date = System.DateTime.Parse(dateObj.ToString(), CultureInfo.InvariantCulture);
-    } else {
-      var d = ArgToDecimal(arguments, 0);
-      date = System.DateTime.FromOADate(d);
-    }
-    return date;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/DateStringParser.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/DateStringParser.cs
deleted file mode 100644
index 74860bf..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/DateStringParser.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-public class DateStringParser {}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/DateValue.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/DateValue.cs
deleted file mode 100644
index a474018..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/DateValue.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-/// <summary>
-/// Simple implementation of DateValue function, just using .NET built-in
-/// function System.DateTime.TryParse, based on current culture
-/// </summary>
-public class DateValue : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var dateString = ArgToString(arguments, 0);
-    return Execute(dateString);
-  }
-
-  internal CompileResult Execute(string dateString) {
-    System.DateTime.TryParse(dateString, out var result);
-    return result != System.DateTime.MinValue
-        ? CreateResult(result.ToOADate(), DataType.Date)
-        : CreateResult(ExcelErrorValue.Create(eErrorType.Value), DataType.ExcelError);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Day.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Day.cs
deleted file mode 100644
index dc4d39c..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Day.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-public class Day : DateParsingFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var dateObj = GetFirstValue(arguments);
-    var date = ParseDate(arguments, dateObj);
-
-    return CreateResult(date.Day, DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Days360.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Days360.cs
deleted file mode 100644
index 797053e..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Days360.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-public class Days360 : ExcelFunction {
-  private enum Days360Calctype {
-    European,
-    Us,
-  }
-
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var numDate1 = ArgToDecimal(arguments, 0);
-    var numDate2 = ArgToDecimal(arguments, 1);
-    var dt1 = System.DateTime.FromOADate(numDate1);
-    var dt2 = System.DateTime.FromOADate(numDate2);
-
-    var calcType = Days360Calctype.Us;
-    if (arguments.Count() > 2) {
-      var european = ArgToBool(arguments, 2);
-      if (european) {
-        calcType = Days360Calctype.European;
-      }
-    }
-
-    var startYear = dt1.Year;
-    var startMonth = dt1.Month;
-    var startDay = dt1.Day;
-    var endYear = dt2.Year;
-    var endMonth = dt2.Month;
-    var endDay = dt2.Day;
-
-    if (calcType == Days360Calctype.European) {
-      if (startDay == 31) {
-        startDay = 30;
-      }
-      if (endDay == 31) {
-        endDay = 30;
-      }
-    } else {
-      var calendar = new GregorianCalendar();
-      var nDaysInFeb = calendar.IsLeapYear(dt1.Year) ? 29 : 28;
-
-      // If the investment is EOM and (Date1 is the last day of February) and (Date2 is the last day of February), then change D2 to 30.
-      if (startMonth == 2 && startDay == nDaysInFeb && endMonth == 2 && endDay == nDaysInFeb) {
-        endDay = 30;
-      }
-      // If the investment is EOM and (Date1 is the last day of February), then change D1 to 30.
-      if (startMonth == 2 && startDay == nDaysInFeb) {
-        startDay = 30;
-      }
-      // If D2 is 31 and D1 is 30 or 31, then change D2 to 30.
-      if (endDay == 31 && (startDay == 30 || startDay == 31)) {
-        endDay = 30;
-      }
-      // If D1 is 31, then change D1 to 30.
-      if (startDay == 31) {
-        startDay = 30;
-      }
-    }
-    var result =
-        (endYear * 12 * 30 + endMonth * 30 + endDay)
-            - (startYear * 12 * 30 + startMonth * 30 + startDay);
-    return CreateResult(result, DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Edate.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Edate.cs
deleted file mode 100644
index 7a1af10..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Edate.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-public class Edate : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2, eErrorType.Value);
-    var dateSerial = ArgToDecimal(arguments, 0);
-    var date = System.DateTime.FromOADate(dateSerial);
-    var nMonthsToAdd = ArgToInt(arguments, 1);
-    var resultDate = date.AddMonths(nMonthsToAdd);
-    return CreateResult(resultDate.ToOADate(), DataType.Date);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Eomonth.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Eomonth.cs
deleted file mode 100644
index 33454da..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Eomonth.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-public class Eomonth : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var date = System.DateTime.FromOADate(ArgToDecimal(arguments, 0));
-    var monthsToAdd = ArgToInt(arguments, 1);
-    var resultDate = new System.DateTime(date.Year, date.Month, 1)
-        .AddMonths(monthsToAdd + 1)
-        .AddDays(-1);
-    return CreateResult(resultDate.ToOADate(), DataType.Date);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Hour.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Hour.cs
deleted file mode 100644
index 5509889..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Hour.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-public class Hour : DateParsingFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var dateObj = arguments.ElementAt(0).Value;
-    var date = ParseDate(arguments, dateObj);
-    return CreateResult(date.Hour, DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/IsoWeekNum.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/IsoWeekNum.cs
deleted file mode 100644
index 45b838b..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/IsoWeekNum.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-using System;
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-public class IsoWeekNum : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var dateInt = ArgToInt(arguments, 0);
-    var date = System.DateTime.FromOADate(dateInt);
-    return CreateResult(WeekNumber(date), DataType.Integer);
-  }
-
-  /// <summary>
-  /// This implementation was found on http://stackoverflow.com/questions/1285191/get-week-of-date-from-linq-query
-  /// </summary>
-  /// <param name="fromDate"></param>
-  /// <returns></returns>
-  private int WeekNumber(System.DateTime fromDate) {
-    // Get jan 1st of the year
-    var startOfYear = fromDate.AddDays(-fromDate.Day + 1).AddMonths(-fromDate.Month + 1);
-    // Get dec 31st of the year
-    var endOfYear = startOfYear.AddYears(1).AddDays(-1);
-    // ISO 8601 weeks start with Monday
-    // The first week of a year includes the first Thursday
-    // DayOfWeek returns 0 for sunday up to 6 for saterday
-    int[] iso8601Correction = { 6, 7, 8, 9, 10, 4, 5 };
-    int nds = fromDate.Subtract(startOfYear).Days + iso8601Correction[(int)startOfYear.DayOfWeek];
-    int wk = nds / 7;
-    switch (wk) {
-      case 0:
-        // Return weeknumber of dec 31st of the previous year
-        return WeekNumber(startOfYear.AddDays(-1));
-      case 53:
-        // If dec 31st falls before thursday it is week 01 of next year
-        if (endOfYear.DayOfWeek < DayOfWeek.Thursday) {
-          return 1;
-        }
-        return wk;
-      default:
-        return wk;
-    }
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Minute.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Minute.cs
deleted file mode 100644
index a93b354..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Minute.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-public class Minute : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var dateObj = arguments.ElementAt(0).Value;
-    System.DateTime date;
-    if (dateObj is string) {
-      date = System.DateTime.Parse(dateObj.ToString());
-    } else {
-      var d = ArgToDecimal(arguments, 0);
-      date = System.DateTime.FromOADate(d);
-    }
-    return CreateResult(date.Minute, DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Month.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Month.cs
deleted file mode 100644
index c6aaba4..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Month.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-public class Month : DateParsingFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var dateObj = arguments.ElementAt(0).Value;
-    var date = ParseDate(arguments, dateObj);
-    return CreateResult(date.Month, DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Networkdays.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Networkdays.cs
deleted file mode 100644
index 93e419e..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Networkdays.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime.Workdays;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-public class Networkdays : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray();
-    ValidateArguments(functionArguments, 2);
-    var startDate = System.DateTime.FromOADate(ArgToInt(functionArguments, 0));
-    var endDate = System.DateTime.FromOADate(ArgToInt(functionArguments, 1));
-    var calculator = new WorkdayCalculator();
-    var result = calculator.CalculateNumberOfWorkdays(startDate, endDate);
-    if (functionArguments.Length > 2) {
-      result = calculator.ReduceWorkdaysWithHolidays(result, functionArguments[2]);
-    }
-
-    return new(result.NumberOfWorkdays, DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/NetworkdaysIntl.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/NetworkdaysIntl.cs
deleted file mode 100644
index e3e1891..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/NetworkdaysIntl.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text.RegularExpressions;
-using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime.Workdays;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-public class NetworkdaysIntl : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray();
-    ValidateArguments(functionArguments, 2);
-    var startDate = System.DateTime.FromOADate(ArgToInt(functionArguments, 0));
-    var endDate = System.DateTime.FromOADate(ArgToInt(functionArguments, 1));
-    WorkdayCalculator calculator = new WorkdayCalculator();
-    var weekdayFactory = new HolidayWeekdaysFactory();
-    if (functionArguments.Length > 2) {
-      var holidayArg = functionArguments[2].Value;
-      if (Regex.IsMatch(holidayArg.ToString(), "^[01]{7}")) {
-        calculator = new(weekdayFactory.Create(holidayArg.ToString()));
-      } else if (IsNumeric(holidayArg)) {
-        var holidayCode = Convert.ToInt32(holidayArg);
-        calculator = new(weekdayFactory.Create(holidayCode));
-      } else {
-        return new(eErrorType.Value);
-      }
-    }
-    var result = calculator.CalculateNumberOfWorkdays(startDate, endDate);
-    if (functionArguments.Length > 3) {
-      result = calculator.ReduceWorkdaysWithHolidays(result, functionArguments[3]);
-    }
-    return new(result.NumberOfWorkdays, DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Now.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Now.cs
deleted file mode 100644
index b4bd17d..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Now.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-public class Now : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    return CreateResult(System.DateTime.Now.ToOADate(), DataType.Date);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Second.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Second.cs
deleted file mode 100644
index 443e913..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Second.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-public class Second : DateParsingFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var dateObj = arguments.ElementAt(0).Value;
-    System.DateTime date = ParseDate(arguments, dateObj);
-    return CreateResult(date.Second, DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Time.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Time.cs
deleted file mode 100644
index fb1144e..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Time.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-public class Time : TimeBaseFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var firstArg = arguments.ElementAt(0).Value.ToString();
-    if (arguments.Count() == 1 && TimeStringParser.CanParse(firstArg)) {
-      var result = TimeStringParser.Parse(firstArg);
-      return new(result, DataType.Time);
-    }
-    ValidateArguments(arguments, 3);
-    var hour = ArgToInt(arguments, 0);
-    var min = ArgToInt(arguments, 1);
-    var sec = ArgToInt(arguments, 2);
-
-    ThrowArgumentExceptionIf(() => sec < 0 || sec > 59, "Invalid second: " + sec);
-    ThrowArgumentExceptionIf(() => min < 0 || min > 59, "Invalid minute: " + min);
-    ThrowArgumentExceptionIf(() => min < 0 || hour > 23, "Invalid hour: " + hour);
-
-    var secondsOfThisTime = (double)(hour * 60 * 60 + min * 60 + sec);
-    return CreateResult(GetTimeSerialNumber(secondsOfThisTime), DataType.Time);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeBaseFunction.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeBaseFunction.cs
deleted file mode 100644
index 4b2ef4a..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeBaseFunction.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-public abstract class TimeBaseFunction : ExcelFunction {
-  protected TimeStringParser TimeStringParser { get; private set; } = new();
-
-  protected double SerialNumber { get; private set; }
-
-  public void ValidateAndInitSerialNumber(IEnumerable<FunctionArgument> arguments) {
-    ValidateArguments(arguments, 1);
-    SerialNumber = ArgToDecimal(arguments, 0);
-  }
-
-  protected double SecondsInADay => 24 * 60 * 60;
-
-  protected double GetTimeSerialNumber(double seconds) {
-    return seconds / SecondsInADay;
-  }
-
-  protected double GetSeconds(double serialNumber) {
-    return serialNumber * SecondsInADay;
-  }
-
-  protected double GetHour(double serialNumber) {
-    var seconds = GetSeconds(serialNumber);
-    return (int)seconds / (60 * 60);
-  }
-
-  protected double GetMinute(double serialNumber) {
-    var seconds = GetSeconds(serialNumber);
-    seconds -= GetHour(serialNumber) * 60 * 60;
-    return (seconds - (seconds % 60)) / 60;
-  }
-
-  protected double GetSecond(double serialNumber) {
-    return GetSeconds(serialNumber) % 60;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeStringParser.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeStringParser.cs
deleted file mode 100644
index 0c403b6..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeStringParser.cs
+++ /dev/null
@@ -1,109 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System;
-using System.Text.RegularExpressions;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-public class TimeStringParser {
-  private const string _regEx24 = @"^[0-9]{1,2}(\:[0-9]{1,2}){0,2}$";
-  private const string _regEx12 = @"^[0-9]{1,2}(\:[0-9]{1,2}){0,2}( PM| AM)$";
-
-  private double GetSerialNumber(int hour, int minute, int second) {
-    var secondsInADay = 24d * 60d * 60d;
-    return ((double)hour * 60 * 60 + (double)minute * 60 + second) / secondsInADay;
-  }
-
-  private void ValidateValues(int hour, int minute, int second) {
-    if (second < 0 || second > 59) {
-      throw new FormatException("Illegal value for second: " + second);
-    }
-    if (minute < 0 || minute > 59) {
-      throw new FormatException("Illegal value for minute: " + minute);
-    }
-  }
-
-  public virtual double Parse(string input) {
-    return InternalParse(input);
-  }
-
-  public virtual bool CanParse(string input) {
-    System.DateTime dt;
-    return Regex.IsMatch(input, _regEx24)
-        || Regex.IsMatch(input, _regEx12)
-        || System.DateTime.TryParse(input, out dt);
-  }
-
-  private double InternalParse(string input) {
-    if (Regex.IsMatch(input, _regEx24)) {
-      return Parse24HourTimeString(input);
-    }
-    if (Regex.IsMatch(input, _regEx12)) {
-      return Parse12HourTimeString(input);
-    }
-    if (System.DateTime.TryParse(input, out var dateTime)) {
-      return GetSerialNumber(dateTime.Hour, dateTime.Minute, dateTime.Second);
-    }
-    return -1;
-  }
-
-  private double Parse12HourTimeString(string input) {
-    var dayPart = input.Substring(input.Length - 2, 2);
-    GetValuesFromString(input, out var hour, out var minute, out var second);
-    if (dayPart == "PM") {
-      hour += 12;
-    }
-    ValidateValues(hour, minute, second);
-    return GetSerialNumber(hour, minute, second);
-  }
-
-  private double Parse24HourTimeString(string input) {
-    GetValuesFromString(input, out var hour, out var minute, out var second);
-    ValidateValues(hour, minute, second);
-    return GetSerialNumber(hour, minute, second);
-  }
-
-  private static void GetValuesFromString(
-      string input,
-      out int hour,
-      out int minute,
-      out int second) {
-    hour = 0;
-    minute = 0;
-    second = 0;
-
-    var items = input.Split(':');
-    hour = int.Parse(items[0]);
-    if (items.Length > 1) {
-      minute = int.Parse(items[1]);
-    }
-    if (items.Length > 2) {
-      var val = items[2];
-      val = Regex.Replace(val, "[^0-9]+$", string.Empty);
-      second = int.Parse(val);
-    }
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeValue.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeValue.cs
deleted file mode 100644
index c2de2e0..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeValue.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-/// <summary>
-/// Simple implementation of TimeValue function, just using .NET built-in
-/// function System.DateTime.TryParse, based on current culture
-/// </summary>
-public class TimeValue : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var dateString = ArgToString(arguments, 0);
-    return Execute(dateString);
-  }
-
-  internal CompileResult Execute(string dateString) {
-    System.DateTime.TryParse(dateString, out var result);
-    return result != System.DateTime.MinValue
-        ? CreateResult(GetTimeValue(result), DataType.Date)
-        : CreateResult(ExcelErrorValue.Create(eErrorType.Value), DataType.ExcelError);
-  }
-
-  private double GetTimeValue(System.DateTime result) {
-    return (int)result.TimeOfDay.TotalSeconds == 0
-        ? 0d
-        : result.TimeOfDay.TotalSeconds / (3600 * 24);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Today.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Today.cs
deleted file mode 100644
index e6ff48f..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Today.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-public class Today : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    return CreateResult(System.DateTime.Today.ToOADate(), DataType.Date);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Weekday.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Weekday.cs
deleted file mode 100644
index cf1af33..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Weekday.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.Exceptions;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-public class Weekday : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var serialNumber = ArgToDecimal(arguments, 0);
-    var returnType = arguments.Count() > 1 ? ArgToInt(arguments, 1) : 1;
-    return CreateResult(
-        CalculateDayOfWeek(System.DateTime.FromOADate(serialNumber), returnType),
-        DataType.Integer);
-  }
-
-  private static readonly List<int> _oneBasedStartOnSunday = new() { 1, 2, 3, 4, 5, 6, 7 };
-  private static readonly List<int> _oneBasedStartOnMonday = new() { 7, 1, 2, 3, 4, 5, 6 };
-  private static readonly List<int> _zeroBasedStartOnSunday = new() { 6, 0, 1, 2, 3, 4, 5 };
-
-  private int CalculateDayOfWeek(System.DateTime dateTime, int returnType) {
-    var dayIx = (int)dateTime.DayOfWeek;
-    switch (returnType) {
-      case 1:
-        return _oneBasedStartOnSunday[dayIx];
-      case 2:
-        return _oneBasedStartOnMonday[dayIx];
-      case 3:
-        return _zeroBasedStartOnSunday[dayIx];
-      default:
-        throw new ExcelErrorValueException(eErrorType.Num);
-    }
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Weeknum.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Weeknum.cs
deleted file mode 100644
index f5c1b05..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Weeknum.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-public class Weeknum : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1, eErrorType.Value);
-    var dateSerial = ArgToDecimal(arguments, 0);
-    var date = System.DateTime.FromOADate(dateSerial);
-    var startDay = DayOfWeek.Sunday;
-    if (arguments.Count() > 1) {
-      var argStartDay = ArgToInt(arguments, 1);
-      switch (argStartDay) {
-        case 1:
-          startDay = DayOfWeek.Sunday;
-          break;
-        case 2:
-        case 11:
-          startDay = DayOfWeek.Monday;
-          break;
-        case 12:
-          startDay = DayOfWeek.Tuesday;
-          break;
-        case 13:
-          startDay = DayOfWeek.Wednesday;
-          break;
-        case 14:
-          startDay = DayOfWeek.Thursday;
-          break;
-        case 15:
-          startDay = DayOfWeek.Friday;
-          break;
-        case 16:
-          startDay = DayOfWeek.Saturday;
-          break;
-        default:
-          // Not supported
-          ThrowExcelErrorValueException(eErrorType.Num);
-          break;
-      }
-    }
-    if (DateTimeFormatInfo.CurrentInfo == null) {
-      throw new InvalidOperationException(
-          "Could not execute Weeknum function because DateTimeFormatInfo.CurrentInfo was null");
-    }
-    var week = DateTimeFormatInfo.CurrentInfo.Calendar.GetWeekOfYear(
-        date,
-        CalendarWeekRule.FirstDay,
-        startDay);
-    return CreateResult(week, DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workday.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workday.cs
deleted file mode 100644
index 947bc3e..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workday.cs
+++ /dev/null
@@ -1,79 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-public class Workday : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var startDate = System.DateTime.FromOADate(ArgToInt(arguments, 0));
-    var nWorkDays = ArgToInt(arguments, 1);
-    var resultDate = System.DateTime.MinValue;
-    var workdaysCounted = 0;
-    var tmpDate = startDate;
-    // first move forward to the first monday
-    while (tmpDate.DayOfWeek != DayOfWeek.Monday && (nWorkDays - workdaysCounted) > 0) {
-      if (!IsHoliday(tmpDate)) {
-        workdaysCounted++;
-      }
-      tmpDate = tmpDate.AddDays(1);
-    }
-    // then calculate whole weeks
-    var nWholeWeeks = (nWorkDays - workdaysCounted) / 5;
-    tmpDate = tmpDate.AddDays(nWholeWeeks * 7);
-    workdaysCounted += nWholeWeeks * 5;
-
-    // calculate the rest
-    while (workdaysCounted < nWorkDays) {
-      tmpDate = tmpDate.AddDays(1);
-      if (!IsHoliday(tmpDate)) {
-        workdaysCounted++;
-      }
-    }
-    resultDate = AdjustResultWithHolidays(tmpDate, arguments);
-    return CreateResult(resultDate.ToOADate(), DataType.Date);
-  }
-
-  private System.DateTime AdjustResultWithHolidays(
-      System.DateTime resultDate,
-      IEnumerable<FunctionArgument> arguments) {
-    if (arguments.Count() == 2) {
-      return resultDate;
-    }
-    var holidays = arguments.ElementAt(2).Value as IEnumerable<FunctionArgument>;
-    if (holidays != null) {
-      foreach (var arg in holidays) {
-        if (ConvertUtil.IsNumeric(arg.Value)) {
-          var dateSerial = ConvertUtil.GetValueDouble(arg.Value);
-          var holidayDate = System.DateTime.FromOADate(dateSerial);
-          if (!IsHoliday(holidayDate)) {
-            resultDate = resultDate.AddDays(1);
-          }
-        }
-      }
-    } else {
-      var range = arguments.ElementAt(2).Value as ExcelDataProvider.IRangeInfo;
-      if (range != null) {
-        foreach (var cell in range) {
-          if (ConvertUtil.IsNumeric(cell.Value)) {
-            var dateSerial = ConvertUtil.GetValueDouble(cell.Value);
-            var holidayDate = System.DateTime.FromOADate(dateSerial);
-            if (!IsHoliday(holidayDate)) {
-              resultDate = resultDate.AddDays(1);
-            }
-          }
-        }
-      }
-    }
-    return resultDate;
-  }
-
-  private bool IsHoliday(System.DateTime date) {
-    return date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/AdditionalHolidayDays.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/AdditionalHolidayDays.cs
deleted file mode 100644
index 38bd021..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/AdditionalHolidayDays.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime.Workdays;
-
-public class AdditionalHolidayDays {
-  private readonly FunctionArgument _holidayArg;
-  private readonly List<System.DateTime> _holidayDates = new();
-
-  public AdditionalHolidayDays(FunctionArgument holidayArg) {
-    _holidayArg = holidayArg;
-    Initialize();
-  }
-
-  public IEnumerable<System.DateTime> AdditionalDates => _holidayDates;
-
-  private void Initialize() {
-    var holidays = _holidayArg.Value as IEnumerable<FunctionArgument>;
-    if (holidays != null) {
-      foreach (var holidayDate in from arg in holidays
-          where ConvertUtil.IsNumeric(arg.Value)
-          select ConvertUtil.GetValueDouble(arg.Value) into dateSerial
-          select System.DateTime.FromOADate(dateSerial)) {
-        _holidayDates.Add(holidayDate);
-      }
-    }
-    var range = _holidayArg.Value as ExcelDataProvider.IRangeInfo;
-    if (range != null) {
-      foreach (var holidayDate in from cell in range
-          where ConvertUtil.IsNumeric(cell.Value)
-          select ConvertUtil.GetValueDouble(cell.Value) into dateSerial
-          select System.DateTime.FromOADate(dateSerial)) {
-        _holidayDates.Add(holidayDate);
-      }
-    }
-    if (ConvertUtil.IsNumeric(_holidayArg.Value)) {
-      _holidayDates.Add(System.DateTime.FromOADate(ConvertUtil.GetValueDouble(_holidayArg.Value)));
-    }
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/HolidayWeekdays.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/HolidayWeekdays.cs
deleted file mode 100644
index 3e866b0..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/HolidayWeekdays.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime.Workdays;
-
-public class HolidayWeekdays {
-  private readonly List<DayOfWeek> _holidayDays = new();
-
-  public HolidayWeekdays()
-      : this(DayOfWeek.Saturday, DayOfWeek.Sunday) {}
-
-  public int NumberOfWorkdaysPerWeek => 7 - _holidayDays.Count;
-
-  public HolidayWeekdays(params DayOfWeek[] holidayDays) {
-    foreach (var dayOfWeek in holidayDays) {
-      _holidayDays.Add(dayOfWeek);
-    }
-  }
-
-  public bool IsHolidayWeekday(System.DateTime dateTime) {
-    return _holidayDays.Contains(dateTime.DayOfWeek);
-  }
-
-  public System.DateTime AdjustResultWithHolidays(
-      System.DateTime resultDate,
-      IEnumerable<FunctionArgument> arguments) {
-    if (arguments.Count() == 2) {
-      return resultDate;
-    }
-    var holidays = arguments.ElementAt(2).Value as IEnumerable<FunctionArgument>;
-    if (holidays != null) {
-      foreach (var arg in holidays) {
-        if (ConvertUtil.IsNumeric(arg.Value)) {
-          var dateSerial = ConvertUtil.GetValueDouble(arg.Value);
-          var holidayDate = System.DateTime.FromOADate(dateSerial);
-          if (!IsHolidayWeekday(holidayDate)) {
-            resultDate = resultDate.AddDays(1);
-          }
-        }
-      }
-    } else {
-      var range = arguments.ElementAt(2).Value as ExcelDataProvider.IRangeInfo;
-      if (range != null) {
-        foreach (var cell in range) {
-          if (ConvertUtil.IsNumeric(cell.Value)) {
-            var dateSerial = ConvertUtil.GetValueDouble(cell.Value);
-            var holidayDate = System.DateTime.FromOADate(dateSerial);
-            if (!IsHolidayWeekday(holidayDate)) {
-              resultDate = resultDate.AddDays(1);
-            }
-          }
-        }
-      }
-    }
-    return resultDate;
-  }
-
-  public System.DateTime GetNextWorkday(
-      System.DateTime date,
-      WorkdayCalculationDirection direction = WorkdayCalculationDirection.Forward) {
-    var changeParam = (int)direction;
-    var tmpDate = date.AddDays(changeParam);
-    while (IsHolidayWeekday(tmpDate)) {
-      tmpDate = tmpDate.AddDays(changeParam);
-    }
-    return tmpDate;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/HolidayWeekdaysFactory.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/HolidayWeekdaysFactory.cs
deleted file mode 100644
index cf17962..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/HolidayWeekdaysFactory.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime.Workdays;
-
-public class HolidayWeekdaysFactory {
-  private readonly DayOfWeek[] _dayOfWeekArray = {
-    DayOfWeek.Monday,
-    DayOfWeek.Tuesday,
-    DayOfWeek.Wednesday,
-    DayOfWeek.Thursday,
-    DayOfWeek.Friday,
-    DayOfWeek.Saturday,
-    DayOfWeek.Sunday,
-  };
-
-  public HolidayWeekdays Create(string weekdays) {
-    if (string.IsNullOrEmpty(weekdays) || weekdays.Length != 7) {
-      throw new ArgumentException("Illegal weekday string", nameof(Weekday));
-    }
-
-    var retVal = new List<DayOfWeek>();
-    var arr = weekdays.ToCharArray();
-    for (var i = 0; i < arr.Length; i++) {
-      var ch = arr[i];
-      if (ch == '1') {
-        retVal.Add(_dayOfWeekArray[i]);
-      }
-    }
-    return new(retVal.ToArray());
-  }
-
-  public HolidayWeekdays Create(int code) {
-    switch (code) {
-      case 1:
-        return new(DayOfWeek.Saturday, DayOfWeek.Sunday);
-      case 2:
-        return new(DayOfWeek.Sunday, DayOfWeek.Monday);
-      case 3:
-        return new(DayOfWeek.Monday, DayOfWeek.Tuesday);
-      case 4:
-        return new(DayOfWeek.Tuesday, DayOfWeek.Wednesday);
-      case 5:
-        return new(DayOfWeek.Wednesday, DayOfWeek.Thursday);
-      case 6:
-        return new(DayOfWeek.Thursday, DayOfWeek.Friday);
-      case 7:
-        return new(DayOfWeek.Friday, DayOfWeek.Saturday);
-      case 11:
-        return new(DayOfWeek.Sunday);
-      case 12:
-        return new(DayOfWeek.Monday);
-      case 13:
-        return new(DayOfWeek.Tuesday);
-      case 14:
-        return new(DayOfWeek.Wednesday);
-      case 15:
-        return new(DayOfWeek.Thursday);
-      case 16:
-        return new(DayOfWeek.Friday);
-      case 17:
-        return new(DayOfWeek.Saturday);
-      default:
-        throw new ArgumentException("Invalid code supplied to HolidayWeekdaysFactory: " + code);
-    }
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculationDirection.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculationDirection.cs
deleted file mode 100644
index c0f56b4..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculationDirection.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime.Workdays;
-
-public enum WorkdayCalculationDirection {
-  Forward = 1,
-  Backward = -1,
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculator.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculator.cs
deleted file mode 100644
index e09e7ba..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculator.cs
+++ /dev/null
@@ -1,123 +0,0 @@
-using System.Linq;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime.Workdays;
-
-public class WorkdayCalculator {
-  private readonly HolidayWeekdays _holidayWeekdays;
-
-  public WorkdayCalculator()
-      : this(new()) {}
-
-  public WorkdayCalculator(HolidayWeekdays holidayWeekdays) {
-    _holidayWeekdays = holidayWeekdays;
-  }
-
-  public WorkdayCalculatorResult CalculateNumberOfWorkdays(
-      System.DateTime startDate,
-      System.DateTime endDate) {
-    var calcDirection =
-        startDate < endDate
-            ? WorkdayCalculationDirection.Forward
-            : WorkdayCalculationDirection.Backward;
-    System.DateTime calcStartDate;
-    System.DateTime calcEndDate;
-    if (calcDirection == WorkdayCalculationDirection.Forward) {
-      calcStartDate = startDate.Date;
-      calcEndDate = endDate.Date;
-    } else {
-      calcStartDate = endDate.Date;
-      calcEndDate = startDate.Date;
-    }
-    var nWholeWeeks = (int)calcEndDate.Subtract(calcStartDate).TotalDays / 7;
-    var workdaysCounted = nWholeWeeks * _holidayWeekdays.NumberOfWorkdaysPerWeek;
-    if (!_holidayWeekdays.IsHolidayWeekday(calcStartDate)) {
-      workdaysCounted++;
-    }
-    var tmpDate = calcStartDate.AddDays(nWholeWeeks * 7);
-    while (tmpDate < calcEndDate) {
-      tmpDate = tmpDate.AddDays(1);
-      if (!_holidayWeekdays.IsHolidayWeekday(tmpDate)) {
-        workdaysCounted++;
-      }
-    }
-    return new(workdaysCounted, startDate, endDate, calcDirection);
-  }
-
-  public WorkdayCalculatorResult CalculateWorkday(System.DateTime startDate, int nWorkDays) {
-    var calcDirection =
-        nWorkDays > 0 ? WorkdayCalculationDirection.Forward : WorkdayCalculationDirection.Backward;
-    var direction = (int)calcDirection;
-    nWorkDays *= direction;
-    var workdaysCounted = 0;
-    var tmpDate = startDate;
-
-    // calculate whole weeks
-    var nWholeWeeks = nWorkDays / _holidayWeekdays.NumberOfWorkdaysPerWeek;
-    tmpDate = tmpDate.AddDays(nWholeWeeks * 7 * direction);
-    workdaysCounted += nWholeWeeks * _holidayWeekdays.NumberOfWorkdaysPerWeek;
-
-    // calculate the rest
-    while (workdaysCounted < nWorkDays) {
-      tmpDate = tmpDate.AddDays(direction);
-      if (!_holidayWeekdays.IsHolidayWeekday(tmpDate)) {
-        workdaysCounted++;
-      }
-    }
-    return new(workdaysCounted, startDate, tmpDate, calcDirection);
-  }
-
-  public WorkdayCalculatorResult ReduceWorkdaysWithHolidays(
-      WorkdayCalculatorResult calculatedResult,
-      FunctionArgument holidayArgument) {
-    var startDate = calculatedResult.StartDate;
-    var endDate = calculatedResult.EndDate;
-    var additionalDays = new AdditionalHolidayDays(holidayArgument);
-    System.DateTime calcStartDate;
-    System.DateTime calcEndDate;
-    if (startDate < endDate) {
-      calcStartDate = startDate;
-      calcEndDate = endDate;
-    } else {
-      calcStartDate = endDate;
-      calcEndDate = startDate;
-    }
-    var nAdditionalHolidayDays = additionalDays.AdditionalDates.Count(x =>
-        x >= calcStartDate && x <= calcEndDate && !_holidayWeekdays.IsHolidayWeekday(x));
-    return new(
-        calculatedResult.NumberOfWorkdays - nAdditionalHolidayDays,
-        startDate,
-        endDate,
-        calculatedResult.Direction);
-  }
-
-  public WorkdayCalculatorResult AdjustResultWithHolidays(
-      WorkdayCalculatorResult calculatedResult,
-      FunctionArgument holidayArgument) {
-    var startDate = calculatedResult.StartDate;
-    var endDate = calculatedResult.EndDate;
-    var direction = calculatedResult.Direction;
-    var workdaysCounted = calculatedResult.NumberOfWorkdays;
-    var additionalDays = new AdditionalHolidayDays(holidayArgument);
-    foreach (var date in additionalDays.AdditionalDates) {
-      if (direction == WorkdayCalculationDirection.Forward
-          && (date < startDate || date > endDate)) {
-        continue;
-      }
-      if (direction == WorkdayCalculationDirection.Backward
-          && (date > startDate || date < endDate)) {
-        continue;
-      }
-      if (_holidayWeekdays.IsHolidayWeekday(date)) {
-        continue;
-      }
-      var tmpDate = _holidayWeekdays.GetNextWorkday(endDate, direction);
-      while (additionalDays.AdditionalDates.Contains(tmpDate)) {
-        tmpDate = _holidayWeekdays.GetNextWorkday(tmpDate, direction);
-      }
-      workdaysCounted++;
-      endDate = tmpDate;
-    }
-
-    return new(workdaysCounted, calculatedResult.StartDate, endDate, direction);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculatorResult.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculatorResult.cs
deleted file mode 100644
index a61a05e..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculatorResult.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime.Workdays;
-
-public class WorkdayCalculatorResult {
-  public WorkdayCalculatorResult(
-      int numberOfWorkdays,
-      System.DateTime startDate,
-      System.DateTime endDate,
-      WorkdayCalculationDirection direction) {
-    NumberOfWorkdays = numberOfWorkdays;
-    StartDate = startDate;
-    EndDate = endDate;
-    Direction = direction;
-  }
-
-  public int NumberOfWorkdays { get; }
-
-  public System.DateTime StartDate { get; }
-
-  public System.DateTime EndDate { get; }
-
-  public WorkdayCalculationDirection Direction { get; set; }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Year.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Year.cs
deleted file mode 100644
index 103c487..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Year.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-public class Year : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var dateObj = arguments.ElementAt(0).Value;
-    System.DateTime date = System.DateTime.MinValue;
-    if (dateObj is string) {
-      date = System.DateTime.Parse(dateObj.ToString());
-    } else {
-      var d = ArgToDecimal(arguments, 0);
-      date = System.DateTime.FromOADate(d);
-    }
-    return CreateResult(date.Year, DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Yearfrac.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Yearfrac.cs
deleted file mode 100644
index 440c46a..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Yearfrac.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-
-public class Yearfrac : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray();
-    ValidateArguments(functionArguments, 2);
-    var date1Num = ArgToDecimal(functionArguments, 0);
-    var date2Num = ArgToDecimal(functionArguments, 1);
-    if (date1Num
-        > date2Num) //Switch to make date1 the lowest date
-    {
-      var t = date1Num;
-      date1Num = date2Num;
-      date2Num = t;
-      var fa = functionArguments[1];
-      functionArguments[1] = functionArguments[0];
-      functionArguments[0] = fa;
-    }
-    var date1 = System.DateTime.FromOADate(date1Num);
-    var date2 = System.DateTime.FromOADate(date2Num);
-
-    var basis = 0;
-    if (functionArguments.Count() > 2) {
-      basis = ArgToInt(functionArguments, 2);
-      ThrowExcelErrorValueExceptionIf(() => basis < 0 || basis > 4, eErrorType.Num);
-    }
-    var func = context.Configuration.FunctionRepository.GetFunction("days360");
-    var calendar = new GregorianCalendar();
-    switch (basis) {
-      case 0:
-        var d360Result = System.Math.Abs(func.Execute(functionArguments, context).ResultNumeric);
-        // reproducing excels behaviour
-        if (date1.Month == 2 && date2.Day == 31) {
-          var daysInFeb = calendar.IsLeapYear(date1.Year) ? 29 : 28;
-          if (date1.Day == daysInFeb) {
-            d360Result++;
-          }
-        }
-        return CreateResult(d360Result / 360d, DataType.Decimal);
-      case 1:
-        return CreateResult(
-            System.Math.Abs((date2 - date1).TotalDays / CalculateAcutalYear(date1, date2)),
-            DataType.Decimal);
-      case 2:
-        return CreateResult(System.Math.Abs((date2 - date1).TotalDays / 360d), DataType.Decimal);
-      case 3:
-        return CreateResult(System.Math.Abs((date2 - date1).TotalDays / 365d), DataType.Decimal);
-      case 4:
-        var args = functionArguments.ToList();
-        args.Add(new(true));
-        double? result = System.Math.Abs(func.Execute(args, context).ResultNumeric / 360d);
-        return CreateResult(result.Value, DataType.Decimal);
-      default:
-        return null;
-    }
-  }
-
-  private double CalculateAcutalYear(System.DateTime dt1, System.DateTime dt2) {
-    var calendar = new GregorianCalendar();
-    var perYear = 0d;
-    var nYears = dt2.Year - dt1.Year + 1;
-    for (var y = dt1.Year; y <= dt2.Year; ++y) {
-      perYear += calendar.IsLeapYear(y) ? 366 : 365;
-    }
-    if (new System.DateTime(dt1.Year + 1, dt1.Month, dt1.Day) >= dt2) {
-      nYears = 1;
-      perYear = 365;
-      if (calendar.IsLeapYear(dt1.Year) && dt1.Month <= 2) {
-        perYear = 366;
-      } else if (calendar.IsLeapYear(dt2.Year) && dt2.Month > 2) {
-        perYear = 366;
-      } else if (dt2.Month == 2 && dt2.Day == 29) {
-        perYear = 366;
-      }
-    }
-    return perYear / nYears;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DecimalCompileResultValidator.cs b/EPPlus/FormulaParsing/Excel/Functions/DecimalCompileResultValidator.cs
deleted file mode 100644
index 208cfa2..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DecimalCompileResultValidator.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-26
- *******************************************************************************/
-
-using OfficeOpenXml.FormulaParsing.Exceptions;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-public class DecimalCompileResultValidator : CompileResultValidator {
-  public override void Validate(object obj) {
-    var num = ConvertUtil.GetValueDouble(obj);
-    if (double.IsNaN(num) || double.IsInfinity(num)) {
-      throw new ExcelErrorValueException(eErrorType.Num);
-    }
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DoubleArgumentParser.cs b/EPPlus/FormulaParsing/Excel/Functions/DoubleArgumentParser.cs
deleted file mode 100644
index ed0cec4..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DoubleArgumentParser.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Globalization;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.Exceptions;
-using OfficeOpenXml.FormulaParsing.Utilities;
-using ConvertUtil = OfficeOpenXml.Utils.ConvertUtil;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-public class DoubleArgumentParser : ArgumentParser {
-  public override object Parse(object obj) {
-    Require.That(obj).Named("argument").IsNotNull();
-    if (obj is ExcelDataProvider.IRangeInfo info) {
-      var r = info.FirstOrDefault();
-      return r?.ValueDouble ?? 0;
-    }
-    if (obj is double) {
-      return obj;
-    }
-    if (obj.IsNumeric()) {
-      return ConvertUtil.GetValueDouble(obj);
-    }
-    var str = obj != null ? obj.ToString() : string.Empty;
-    try {
-      return double.Parse(str, CultureInfo.InvariantCulture);
-    } catch // (Exception e)
-    {
-      throw new ExcelErrorValueException(ExcelErrorValue.Create(eErrorType.Value));
-    }
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DoubleEnumerableArgConverter.cs b/EPPlus/FormulaParsing/Excel/Functions/DoubleEnumerableArgConverter.cs
deleted file mode 100644
index 1895872..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/DoubleEnumerableArgConverter.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.Exceptions;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-public class DoubleEnumerableArgConverter : CollectionFlattener<double> {
-  public virtual IEnumerable<double> ConvertArgs(
-      bool ignoreHidden,
-      bool ignoreErrors,
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    return base.FuncArgsToFlatEnumerable(
-        arguments,
-        (arg, argList) => {
-          if (arg.IsExcelRange) {
-            foreach (var cell in arg.ValueAsRangeInfo) {
-              if (!ignoreErrors && cell.IsExcelError) {
-                throw new ExcelErrorValueException(ExcelErrorValue.Parse(cell.Value.ToString()));
-              }
-              if (!CellStateHelper.ShouldIgnore(ignoreHidden, cell, context)
-                  && ConvertUtil.IsNumeric(cell.Value)) {
-                argList.Add(cell.ValueDouble);
-              }
-            }
-          } else {
-            if (!ignoreErrors && arg.ValueIsExcelError) {
-              throw new ExcelErrorValueException(arg.ValueAsExcelErrorValue);
-            }
-            if (ConvertUtil.IsNumeric(arg.Value)
-                && !CellStateHelper.ShouldIgnore(ignoreHidden, arg, context)) {
-              argList.Add(ConvertUtil.GetValueDouble(arg.Value));
-            }
-          }
-        });
-  }
-
-  public virtual IEnumerable<double> ConvertArgsIncludingOtherTypes(
-      IEnumerable<FunctionArgument> arguments) {
-    return base.FuncArgsToFlatEnumerable(
-        arguments,
-        (arg, argList) => {
-          //var cellInfo = arg.Value as EpplusExcelDataProvider.CellInfo;
-          //var value = cellInfo != null ? cellInfo.Value : arg.Value;
-          if (arg.Value is ExcelDataProvider.IRangeInfo info) {
-            foreach (var cell in info) {
-              argList.Add(cell.ValueDoubleLogical);
-            }
-          } else {
-            if (arg.Value is double || arg.Value is int || arg.Value is bool) {
-              argList.Add(Convert.ToDouble(arg.Value));
-            } else if (arg.Value is string) {
-              argList.Add(0d);
-            }
-          }
-        });
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/ErrorHandlingFunction.cs b/EPPlus/FormulaParsing/Excel/Functions/ErrorHandlingFunction.cs
deleted file mode 100644
index fb950a8..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/ErrorHandlingFunction.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-/// <summary>
-/// Base class for functions that handles an error that occurs during the
-/// normal execution of the function.
-/// If an exception occurs during the Execute-call that exception will be
-/// caught by the compiler, then the HandleError-method will be called.
-/// </summary>
-public abstract class ErrorHandlingFunction : ExcelFunction {
-  /// <summary>
-  /// Indicates that the function is an ErrorHandlingFunction.
-  /// </summary>
-  public override bool IsErrorHandlingFunction => true;
-
-  /// <summary>
-  /// Method that should be implemented to handle the error.
-  /// </summary>
-  /// <param name="errorCode"></param>
-  /// <returns></returns>
-  public abstract CompileResult HandleError(string errorCode);
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/ExcelFunction.cs b/EPPlus/FormulaParsing/Excel/Functions/ExcelFunction.cs
deleted file mode 100644
index a1ae44c..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/ExcelFunction.cs
+++ /dev/null
@@ -1,439 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text.RegularExpressions;
-using OfficeOpenXml.FormulaParsing.Exceptions;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-using OfficeOpenXml.FormulaParsing.Utilities;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-/// <summary>
-/// Base class for Excel function implementations.
-/// </summary>
-public abstract class ExcelFunction {
-  public ExcelFunction()
-      : this(new(), new(), new()) {}
-
-  public ExcelFunction(
-      ArgumentCollectionUtil argumentCollectionUtil,
-      ArgumentParsers argumentParsers,
-      CompileResultValidators compileResultValidators) {
-    _argumentCollectionUtil = argumentCollectionUtil;
-    _argumentParsers = argumentParsers;
-    _compileResultValidators = compileResultValidators;
-  }
-
-  private readonly ArgumentCollectionUtil _argumentCollectionUtil;
-  private readonly ArgumentParsers _argumentParsers;
-  private readonly CompileResultValidators _compileResultValidators;
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="arguments">Arguments to the function, each argument can contain primitive types, lists or <see cref="ExcelDataProvider.IRangeInfo">Excel ranges</see></param>
-  /// <param name="context">The <see cref="ParsingContext"/> contains various data that can be useful in functions.</param>
-  /// <returns>A <see cref="CompileResult"/> containing the calculated value</returns>
-  public abstract CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context);
-
-  /// <summary>
-  /// If overridden, this method is called before Execute is called.
-  /// </summary>
-  /// <param name="context"></param>
-  public virtual void BeforeInvoke(ParsingContext context) {}
-
-  public virtual bool IsLookupFuction => false;
-
-  public virtual bool IsErrorHandlingFunction => false;
-
-  /// <summary>
-  /// Used for some Lookupfunctions to indicate that function arguments should
-  /// not be compiled before the function is called.
-  /// </summary>
-  public bool SkipArgumentEvaluation { get; set; }
-
-  protected object GetFirstValue(IEnumerable<FunctionArgument> val) {
-    var arg = val.FirstOrDefault();
-    if (arg.Value is ExcelDataProvider.IRangeInfo) {
-      //var r=((ExcelDataProvider.IRangeInfo)arg);
-      var r = arg.ValueAsRangeInfo;
-      return r.GetValue(r.Address._fromRow, r.Address._fromCol);
-    }
-    return arg?.Value;
-  }
-
-  /// <summary>
-  /// This functions validates that the supplied <paramref name="arguments"/> contains at least
-  /// (the value of) <paramref name="minLength"/> elements. If one of the arguments is an
-  /// <see cref="ExcelDataProvider.IRangeInfo">Excel range</see> the number of cells in
-  /// that range will be counted as well.
-  /// </summary>
-  /// <param name="arguments"></param>
-  /// <param name="minLength"></param>
-  /// <param name="errorTypeToThrow">The <see cref="eErrorType"/> of the <see cref="ExcelErrorValueException"/> that will be thrown if <paramref name="minLength"/> is not met.</param>
-  protected void ValidateArguments(
-      IEnumerable<FunctionArgument> arguments,
-      int minLength,
-      eErrorType errorTypeToThrow) {
-    Require.That(arguments).Named("arguments").IsNotNull();
-    ThrowExcelErrorValueExceptionIf(
-        () => {
-          var nArgs = 0;
-          if (arguments.Any()) {
-            foreach (var arg in arguments) {
-              nArgs++;
-              if (nArgs >= minLength) {
-                return false;
-              }
-              if (arg.IsExcelRange) {
-                nArgs += arg.ValueAsRangeInfo.GetNCells();
-                if (nArgs >= minLength) {
-                  return false;
-                }
-              }
-            }
-          }
-          return true;
-        },
-        errorTypeToThrow);
-  }
-
-  /// <summary>
-  /// This functions validates that the supplied <paramref name="arguments"/> contains at least
-  /// (the value of) <paramref name="minLength"/> elements. If one of the arguments is an
-  /// <see cref="ExcelDataProvider.IRangeInfo">Excel range</see> the number of cells in
-  /// that range will be counted as well.
-  /// </summary>
-  /// <param name="arguments"></param>
-  /// <param name="minLength"></param>
-  /// <exception cref="ArgumentException"></exception>
-  protected void ValidateArguments(IEnumerable<FunctionArgument> arguments, int minLength) {
-    Require.That(arguments).Named("arguments").IsNotNull();
-    ThrowArgumentExceptionIf(
-        () => {
-          var nArgs = 0;
-          if (arguments.Any()) {
-            foreach (var arg in arguments) {
-              nArgs++;
-              if (nArgs >= minLength) {
-                return false;
-              }
-              if (arg.IsExcelRange) {
-                nArgs += arg.ValueAsRangeInfo.GetNCells();
-                if (nArgs >= minLength) {
-                  return false;
-                }
-              }
-            }
-          }
-          return true;
-        },
-        "Expecting at least {0} arguments",
-        minLength.ToString());
-  }
-
-  /// <summary>
-  /// Returns the value of the argument att the position of the 0-based
-  /// <paramref name="index"/> as an integer.
-  /// </summary>
-  /// <param name="arguments"></param>
-  /// <param name="index"></param>
-  /// <returns>Value of the argument as an integer.</returns>
-  /// <exception cref="ExcelErrorValueException"></exception>
-  protected int ArgToInt(IEnumerable<FunctionArgument> arguments, int index) {
-    var val = arguments.ElementAt(index).ValueFirst;
-    return (int)_argumentParsers.GetParser(DataType.Integer).Parse(val);
-  }
-
-  /// <summary>
-  /// Returns the value of the argument att the position of the 0-based
-  /// <paramref name="index"/> as a string.
-  /// </summary>
-  /// <param name="arguments"></param>
-  /// <param name="index"></param>
-  /// <returns>Value of the argument as a string.</returns>
-  protected string ArgToString(IEnumerable<FunctionArgument> arguments, int index) {
-    var obj = arguments.ElementAt(index).ValueFirst;
-    return obj != null ? obj.ToString() : string.Empty;
-  }
-
-  /// <summary>
-  /// Returns the value of the argument att the position of the 0-based
-  /// </summary>
-  /// <param name="obj"></param>
-  /// <returns>Value of the argument as a double.</returns>
-  /// <exception cref="ExcelErrorValueException"></exception>
-  protected double ArgToDecimal(object obj) {
-    return (double)_argumentParsers.GetParser(DataType.Decimal).Parse(obj);
-  }
-
-  /// <summary>
-  /// Returns the value of the argument att the position of the 0-based
-  /// <paramref name="index"/> as a <see cref="System.Double"/>.
-  /// </summary>
-  /// <param name="arguments"></param>
-  /// <param name="index"></param>
-  /// <returns>Value of the argument as an integer.</returns>
-  /// <exception cref="ExcelErrorValueException"></exception>
-  protected double ArgToDecimal(IEnumerable<FunctionArgument> arguments, int index) {
-    return ArgToDecimal(arguments.ElementAt(index).Value);
-  }
-
-  protected double Divide(double left, double right) {
-    if (System.Math.Abs(right - 0d) < double.Epsilon) {
-      throw new ExcelErrorValueException(eErrorType.Div0);
-    }
-    return left / right;
-  }
-
-  protected bool IsNumericString(object value) {
-    if (value == null || string.IsNullOrEmpty(value.ToString())) {
-      return false;
-    }
-    return Regex.IsMatch(value.ToString(), @"^[\d]+(\,[\d])?");
-  }
-
-  /// <summary>
-  /// If the argument is a boolean value its value will be returned.
-  /// If the argument is an integer value, true will be returned if its
-  /// value is not 0, otherwise false.
-  /// </summary>
-  /// <param name="arguments"></param>
-  /// <param name="index"></param>
-  /// <returns></returns>
-  protected bool ArgToBool(IEnumerable<FunctionArgument> arguments, int index) {
-    var obj = arguments.ElementAt(index).Value ?? string.Empty;
-    return (bool)_argumentParsers.GetParser(DataType.Boolean).Parse(obj);
-  }
-
-  /// <summary>
-  /// Throws an <see cref="ArgumentException"/> if <paramref name="condition"/> evaluates to true.
-  /// </summary>
-  /// <param name="condition"></param>
-  /// <param name="message"></param>
-  /// <exception cref="ArgumentException"></exception>
-  protected void ThrowArgumentExceptionIf(Func<bool> condition, string message) {
-    if (condition()) {
-      throw new ArgumentException(message);
-    }
-  }
-
-  /// <summary>
-  /// Throws an <see cref="ArgumentException"/> if <paramref name="condition"/> evaluates to true.
-  /// </summary>
-  /// <param name="condition"></param>
-  /// <param name="message"></param>
-  /// <param name="formats">Formats to the message string.</param>
-  protected void ThrowArgumentExceptionIf(
-      Func<bool> condition,
-      string message,
-      params object[] formats) {
-    message = string.Format(message, formats);
-    ThrowArgumentExceptionIf(condition, message);
-  }
-
-  /// <summary>
-  /// Throws an <see cref="ExcelErrorValueException"/> with the given <paramref name="errorType"/> set.
-  /// </summary>
-  /// <param name="errorType"></param>
-  protected void ThrowExcelErrorValueException(eErrorType errorType) {
-    throw new ExcelErrorValueException(
-        "An excel function error occurred",
-        ExcelErrorValue.Create(errorType));
-  }
-
-  /// <summary>
-  /// Throws an <see cref="ArgumentException"/> if <paramref name="condition"/> evaluates to true.
-  /// </summary>
-  /// <param name="condition"></param>
-  /// <param name="errorType"></param>
-  /// <exception cref="ExcelErrorValueException"></exception>
-  protected void ThrowExcelErrorValueExceptionIf(Func<bool> condition, eErrorType errorType) {
-    if (condition()) {
-      throw new ExcelErrorValueException(
-          "An excel function error occurred",
-          ExcelErrorValue.Create(errorType));
-    }
-  }
-
-  protected bool IsNumeric(object val) {
-    if (val == null) {
-      return false;
-    }
-    return (val.GetType().IsPrimitive
-            || val is double
-            || val is decimal
-            || val is System.DateTime
-            || val is TimeSpan);
-  }
-
-  //protected virtual bool IsNumber(object obj)
-  //{
-  //    if (obj == null) return false;
-  //    return (obj is int || obj is double || obj is short || obj is decimal || obj is long);
-  //}
-
-  /// <summary>
-  /// Helper method for comparison of two doubles.
-  /// </summary>
-  /// <param name="d1"></param>
-  /// <param name="d2"></param>
-  /// <returns></returns>
-  protected bool AreEqual(double d1, double d2) {
-    return System.Math.Abs(d1 - d2) < double.Epsilon;
-  }
-
-  /// <summary>
-  /// Will return the arguments as an enumerable of doubles.
-  /// </summary>
-  /// <param name="arguments"></param>
-  /// <param name="context"></param>
-  /// <returns></returns>
-  protected virtual IEnumerable<double> ArgsToDoubleEnumerable(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    return ArgsToDoubleEnumerable(false, arguments, context);
-  }
-
-  /// <summary>
-  /// Will return the arguments as an enumerable of doubles.
-  /// </summary>
-  /// <param name="ignoreHiddenCells">If a cell is hidden and this value is true the value of that cell will be ignored</param>
-  /// <param name="ignoreErrors">If a cell contains an error, that error will be ignored if this method is set to true</param>
-  /// <param name="arguments"></param>
-  /// <param name="context"></param>
-  /// <returns></returns>
-  protected virtual IEnumerable<double> ArgsToDoubleEnumerable(
-      bool ignoreHiddenCells,
-      bool ignoreErrors,
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    return _argumentCollectionUtil.ArgsToDoubleEnumerable(
-        ignoreHiddenCells,
-        ignoreErrors,
-        arguments,
-        context);
-  }
-
-  /// <summary>
-  /// Will return the arguments as an enumerable of doubles.
-  /// </summary>
-  /// <param name="ignoreHiddenCells">If a cell is hidden and this value is true the value of that cell will be ignored</param>
-  /// <param name="arguments"></param>
-  /// <param name="context"></param>
-  /// <returns></returns>
-  protected virtual IEnumerable<double> ArgsToDoubleEnumerable(
-      bool ignoreHiddenCells,
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    return ArgsToDoubleEnumerable(ignoreHiddenCells, true, arguments, context);
-  }
-
-  /// <summary>
-  /// Will return the arguments as an enumerable of objects.
-  /// </summary>
-  /// <param name="ignoreHiddenCells">If a cell is hidden and this value is true the value of that cell will be ignored</param>
-  /// <param name="arguments"></param>
-  /// <param name="context"></param>
-  /// <returns></returns>
-  protected virtual IEnumerable<object> ArgsToObjectEnumerable(
-      bool ignoreHiddenCells,
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    return _argumentCollectionUtil.ArgsToObjectEnumerable(ignoreHiddenCells, arguments, context);
-  }
-
-  /// <summary>
-  /// Use this method to create a result to return from Excel functions.
-  /// </summary>
-  /// <param name="result"></param>
-  /// <param name="dataType"></param>
-  /// <returns></returns>
-  protected CompileResult CreateResult(object result, DataType dataType) {
-    var validator = _compileResultValidators.GetValidator(dataType);
-    validator.Validate(result);
-    return new(result, dataType);
-  }
-
-  /// <summary>
-  /// Use this method to apply a function on a collection of arguments. The <paramref name="result"/>
-  /// should be modifyed in the supplied <paramref name="action"/> and will contain the result
-  /// after this operation has been performed.
-  /// </summary>
-  /// <param name="collection"></param>
-  /// <param name="result"></param>
-  /// <param name="action"></param>
-  /// <returns></returns>
-  protected virtual double CalculateCollection(
-      IEnumerable<FunctionArgument> collection,
-      double result,
-      Func<FunctionArgument, double, double> action) {
-    return _argumentCollectionUtil.CalculateCollection(collection, result, action);
-  }
-
-  /// <summary>
-  /// if the supplied <paramref name="arg">argument</paramref> contains an Excel error
-  /// an <see cref="ExcelErrorValueException"/> with that errorcode will be thrown
-  /// </summary>
-  /// <param name="arg"></param>
-  /// <exception cref="ExcelErrorValueException"></exception>
-  protected void CheckForAndHandleExcelError(FunctionArgument arg) {
-    if (arg.ValueIsExcelError) {
-      throw (new ExcelErrorValueException(arg.ValueAsExcelErrorValue));
-    }
-  }
-
-  /// <summary>
-  /// If the supplied <paramref name="cell"/> contains an Excel error
-  /// an <see cref="ExcelErrorValueException"/> with that errorcode will be thrown
-  /// </summary>
-  /// <param name="cell"></param>
-  protected void CheckForAndHandleExcelError(ExcelDataProvider.ICellInfo cell) {
-    if (cell.IsExcelError) {
-      throw (new ExcelErrorValueException(ExcelErrorValue.Parse(cell.Value.ToString())));
-    }
-  }
-
-  protected CompileResult GetResultByObject(object result) {
-    if (IsNumeric(result)) {
-      return CreateResult(result, DataType.Decimal);
-    }
-    if (result is string) {
-      return CreateResult(result, DataType.String);
-    }
-    if (ExcelErrorValue.Values.IsErrorValue(result)) {
-      return CreateResult(result, DataType.ExcelAddress);
-    }
-    if (result == null) {
-      return CompileResult.Empty;
-    }
-    return CreateResult(result, DataType.Enumerable);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/FunctionArgument.cs b/EPPlus/FormulaParsing/Excel/Functions/FunctionArgument.cs
deleted file mode 100644
index baa9da7..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/FunctionArgument.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-public class FunctionArgument {
-  public FunctionArgument(object val) {
-    Value = val;
-  }
-
-  private ExcelCellState _excelCellState;
-
-  public void SetExcelStateFlag(ExcelCellState state) {
-    _excelCellState |= state;
-  }
-
-  public bool ExcelStateFlagIsSet(ExcelCellState state) {
-    return (_excelCellState & state) != 0;
-  }
-
-  public object Value { get; private set; }
-
-  public Type Type => Value?.GetType();
-
-  public bool IsExcelRange => Value != null && Value is ExcelDataProvider.IRangeInfo;
-
-  public bool ValueIsExcelError => ExcelErrorValue.Values.IsErrorValue(Value);
-
-  public ExcelErrorValue ValueAsExcelErrorValue => ExcelErrorValue.Parse(Value.ToString());
-
-  public ExcelDataProvider.IRangeInfo ValueAsRangeInfo => Value as ExcelDataProvider.IRangeInfo;
-
-  public object ValueFirst {
-    get {
-      if (Value is ExcelDataProvider.INameInfo info) {
-        Value = info.Value;
-      }
-      var v = Value as ExcelDataProvider.IRangeInfo;
-      if (v == null) {
-        return Value;
-      }
-      return v.GetValue(v.Address._fromRow, v.Address._fromCol);
-    }
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/FunctionNameProvider.cs b/EPPlus/FormulaParsing/Excel/Functions/FunctionNameProvider.cs
deleted file mode 100644
index 012a7c7..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/FunctionNameProvider.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-public class FunctionNameProvider : IFunctionNameProvider {
-  private FunctionNameProvider() {}
-
-  public static FunctionNameProvider Empty => new();
-
-  public virtual bool IsFunctionName(string name) {
-    return false;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/FunctionRepository.cs b/EPPlus/FormulaParsing/Excel/Functions/FunctionRepository.cs
deleted file mode 100644
index fe09617..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/FunctionRepository.cs
+++ /dev/null
@@ -1,121 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using OfficeOpenXml.FormulaParsing.Utilities;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-// Used to report the names of Excel functions that are not supported by EPPlus
-public class FunctionException : SystemException {
-  // Summary:
-  //     Initializes a new instance of the System.FunctionException class.
-  public FunctionException() {}
-
-  //
-  // Summary:
-  //     Initializes a new instance of the System.FunctionException class with a specified
-  //     error message.
-  //
-  // Parameters:
-  //   message:
-  //     The message that describes the error.
-  public FunctionException(string message)
-      : base(message) {}
-}
-
-/// <summary>
-/// This class provides methods for accessing/modifying VBA Functions.
-/// </summary>
-public class FunctionRepository : IFunctionNameProvider {
-  private readonly Dictionary<string, ExcelFunction> _functions = new(
-      StringComparer.InvariantCulture);
-
-  private FunctionRepository() {}
-
-  public static FunctionRepository Create() {
-    var repo = new FunctionRepository();
-    repo.LoadModule(new BuiltInFunctions());
-    return repo;
-  }
-
-  /// <summary>
-  /// Loads a module of <see cref="ExcelFunction"/>s to the function repository.
-  /// </summary>
-  /// <param name="module">A <see cref="IFunctionModule"/> that can be used for adding functions</param>
-  public virtual void LoadModule(IFunctionModule module) {
-    foreach (var key in module.Functions.Keys) {
-      var lowerKey = key.ToLower(CultureInfo.InvariantCulture);
-      _functions[lowerKey] = module.Functions[key];
-    }
-  }
-
-  public virtual ExcelFunction GetFunction(string name) {
-    if (!_functions.ContainsKey(name.ToLower(CultureInfo.InvariantCulture))) {
-      // Report that Excel function is not supported by EPPlus
-      throw new FunctionException(
-          string.Format("Excel function '{0}' is not supported in formulas.", name));
-    }
-    return _functions[name.ToLower(CultureInfo.InvariantCulture)];
-  }
-
-  /// <summary>
-  /// Removes all functions from the repository
-  /// </summary>
-  public virtual void Clear() {
-    _functions.Clear();
-  }
-
-  /// <summary>
-  /// Returns true if the the supplied <paramref name="name"/> exists in the repository.
-  /// </summary>
-  /// <param name="name"></param>
-  /// <returns></returns>
-  public bool IsFunctionName(string name) {
-    return _functions.ContainsKey(name.ToLower(CultureInfo.InvariantCulture));
-  }
-
-  /// <summary>
-  /// Returns the names of all implemented functions.
-  /// </summary>
-  public IEnumerable<string> FunctionNames => _functions.Keys;
-
-  /// <summary>
-  /// Adds or replaces a function.
-  /// </summary>
-  /// <param name="functionName"> Case-insensitive name of the function that should be added or replaced.</param>
-  /// <param name="functionImpl">An implementation of an <see cref="ExcelFunction"/>.</param>
-  public void AddOrReplaceFunction(string functionName, ExcelFunction functionImpl) {
-    Require.That(functionName).Named("functionName").IsNotNullOrEmpty();
-    Require.That(functionImpl).Named("functionImpl").IsNotNull();
-    var fName = functionName.ToLower(CultureInfo.InvariantCulture);
-    if (_functions.ContainsKey(fName)) {
-      _functions.Remove(fName);
-    }
-    _functions[fName] = functionImpl;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/FunctionsModule.cs b/EPPlus/FormulaParsing/Excel/Functions/FunctionsModule.cs
deleted file mode 100644
index 522451a..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/FunctionsModule.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-/// <summary>
-/// Base class
-/// </summary>
-public abstract class FunctionsModule : IFunctionModule {
-  private readonly Dictionary<string, ExcelFunction> _functions = new();
-
-  public IDictionary<string, ExcelFunction> Functions => _functions;
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/HiddenValuesHandlingFunction.cs b/EPPlus/FormulaParsing/Excel/Functions/HiddenValuesHandlingFunction.cs
deleted file mode 100644
index 81b3cc8..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/HiddenValuesHandlingFunction.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-/// <summary>
-/// Base class for functions that needs to handle cells that is not visible.
-/// </summary>
-public abstract class HiddenValuesHandlingFunction : ExcelFunction {
-  /// <summary>
-  /// Set to true or false to indicate whether the function should ignore hidden values.
-  /// </summary>
-  public bool IgnoreHiddenValues { get; set; }
-
-  protected override IEnumerable<double> ArgsToDoubleEnumerable(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    return ArgsToDoubleEnumerable(arguments, context, true);
-  }
-
-  protected IEnumerable<double> ArgsToDoubleEnumerable(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context,
-      bool ignoreErrors) {
-    if (!arguments.Any()) {
-      return Enumerable.Empty<double>();
-    }
-    if (IgnoreHiddenValues) {
-      var nonHidden = arguments.Where(x => !x.ExcelStateFlagIsSet(ExcelCellState.HiddenCell));
-      return base.ArgsToDoubleEnumerable(IgnoreHiddenValues, nonHidden, context);
-    }
-    return base.ArgsToDoubleEnumerable(IgnoreHiddenValues, ignoreErrors, arguments, context);
-  }
-
-  protected bool ShouldIgnore(ExcelDataProvider.ICellInfo c, ParsingContext context) {
-    return CellStateHelper.ShouldIgnore(IgnoreHiddenValues, c, context);
-  }
-
-  protected bool ShouldIgnore(FunctionArgument arg) {
-    if (IgnoreHiddenValues && arg.ExcelStateFlagIsSet(ExcelCellState.HiddenCell)) {
-      return true;
-    }
-    return false;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/IFunctionModule.cs b/EPPlus/FormulaParsing/Excel/Functions/IFunctionModule.cs
deleted file mode 100644
index 6ab248f..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/IFunctionModule.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-public interface IFunctionModule {
-  IDictionary<string, ExcelFunction> Functions { get; }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/IFunctionNameProvider.cs b/EPPlus/FormulaParsing/Excel/Functions/IFunctionNameProvider.cs
deleted file mode 100644
index 5722862..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/IFunctionNameProvider.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-public interface IFunctionNameProvider {
-  bool IsFunctionName(string name);
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/ErrorType.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/ErrorType.cs
deleted file mode 100644
index f68f0f9..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Information/ErrorType.cs
+++ /dev/null
@@ -1,65 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-01-15
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information;
-
-public class ErrorType : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var error = arguments.ElementAt(0);
-    var isErrorFunc = context.Configuration.FunctionRepository.GetFunction("iserror");
-    var isErrorResult = isErrorFunc.Execute(arguments, context);
-    if (!(bool)isErrorResult.Result) {
-      return CreateResult(ExcelErrorValue.Create(eErrorType.Na), DataType.ExcelError);
-    }
-    var errorType = error.ValueAsExcelErrorValue;
-    switch (errorType.Type) {
-      case eErrorType.Null:
-        return CreateResult(1, DataType.Integer);
-      case eErrorType.Div0:
-        return CreateResult(2, DataType.Integer);
-      case eErrorType.Value:
-        return CreateResult(3, DataType.Integer);
-      case eErrorType.Ref:
-        return CreateResult(4, DataType.Integer);
-      case eErrorType.Name:
-        return CreateResult(5, DataType.Integer);
-      case eErrorType.Num:
-        return CreateResult(6, DataType.Integer);
-      case eErrorType.Na:
-        return CreateResult(7, DataType.Integer);
-      // Bug G0004
-      case eErrorType.Error:
-        return CreateResult(8, DataType.Integer);
-    }
-    return CreateResult(ExcelErrorValue.Create(eErrorType.Na), DataType.ExcelError);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/IsBlank.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/IsBlank.cs
deleted file mode 100644
index 8923a4c..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Information/IsBlank.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information;
-
-public class IsBlank : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    if (arguments == null || arguments.Count() == 0) {
-      return CreateResult(true, DataType.Boolean);
-    }
-    var result = true;
-    foreach (var arg in arguments) {
-      if (arg.Value is ExcelDataProvider.IRangeInfo info) {
-        if (info.GetValue(info.Address._fromRow, info.Address._fromCol) != null) {
-          result = false;
-        }
-      } else {
-        if (arg.Value != null && (arg.Value.ToString() != string.Empty)) {
-          result = false;
-          break;
-        }
-      }
-    }
-    return CreateResult(result, DataType.Boolean);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/IsErr.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/IsErr.cs
deleted file mode 100644
index d857231..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Information/IsErr.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information;
-
-public class IsErr : ErrorHandlingFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    var isError = new IsError();
-    var result = isError.Execute(arguments, context);
-    if ((bool)result.Result) {
-      var arg = GetFirstValue(arguments);
-      if (arg is ExcelDataProvider.IRangeInfo info) {
-        var e = info.GetValue(info.Address._fromRow, info.Address._fromCol) as ExcelErrorValue;
-        if (e != null && e.Type == eErrorType.Na) {
-          return CreateResult(false, DataType.Boolean);
-        }
-      } else {
-        if (arg is ExcelErrorValue value && value.Type == eErrorType.Na) {
-          return CreateResult(false, DataType.Boolean);
-        }
-      }
-    }
-    return result;
-  }
-
-  public override CompileResult HandleError(string errorCode) {
-    return CreateResult(true, DataType.Boolean);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/IsError.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/IsError.cs
deleted file mode 100644
index 11aaf0b..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Information/IsError.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information;
-
-public class IsError : ErrorHandlingFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    if (arguments == null || arguments.Count() == 0) {
-      return CreateResult(false, DataType.Boolean);
-    }
-    foreach (var argument in arguments) {
-      if (argument.Value is ExcelDataProvider.IRangeInfo info) {
-        if (ExcelErrorValue.Values.IsErrorValue(
-            info.GetValue(info.Address._fromRow, info.Address._fromCol))) {
-          return CreateResult(true, DataType.Boolean);
-        }
-      } else {
-        if (ExcelErrorValue.Values.IsErrorValue(argument.Value)) {
-          return CreateResult(true, DataType.Boolean);
-        }
-      }
-    }
-    return CreateResult(false, DataType.Boolean);
-  }
-
-  public override CompileResult HandleError(string errorCode) {
-    return CreateResult(true, DataType.Boolean);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/IsEven.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/IsEven.cs
deleted file mode 100644
index af8bf4e..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Information/IsEven.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information;
-
-public class IsEven : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var arg1 = GetFirstValue(arguments); //arguments.ElementAt(0);
-    if (!ConvertUtil.IsNumeric(arg1)) {
-      ThrowExcelErrorValueException(eErrorType.Value);
-    }
-    var number = (int)System.Math.Floor(ConvertUtil.GetValueDouble(arg1));
-    return CreateResult(number % 2 == 0, DataType.Boolean);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/IsLogical.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/IsLogical.cs
deleted file mode 100644
index fbda5d6..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Information/IsLogical.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information;
-
-public class IsLogical : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray();
-    ValidateArguments(functionArguments, 1);
-    var v = GetFirstValue(arguments);
-    return CreateResult(v is bool, DataType.Boolean);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/IsNa.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/IsNa.cs
deleted file mode 100644
index 641ea01..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Information/IsNa.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-01-15
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information;
-
-public class IsNa : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    if (arguments == null || arguments.Count() == 0) {
-      return CreateResult(false, DataType.Boolean);
-    }
-
-    var v = GetFirstValue(arguments);
-
-    if (v is ExcelErrorValue value && value.Type == eErrorType.Na) {
-      return CreateResult(true, DataType.Boolean);
-    }
-    return CreateResult(false, DataType.Boolean);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/IsNonText.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/IsNonText.cs
deleted file mode 100644
index c84008d..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Information/IsNonText.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-01-15
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information;
-
-public class IsNonText : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var firstArg = arguments.ElementAt(0);
-    if (firstArg.Value == null || firstArg.ValueIsExcelError) {
-      return CreateResult(false, DataType.Boolean);
-    }
-    return CreateResult(!(firstArg.Value is string), DataType.Boolean);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/IsNumber.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/IsNumber.cs
deleted file mode 100644
index eac8fdd..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Information/IsNumber.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information;
-
-public class IsNumber : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var arg = GetFirstValue(arguments);
-    return CreateResult(IsNumeric(arg), DataType.Boolean);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/IsOdd.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/IsOdd.cs
deleted file mode 100644
index 1e1af7f..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Information/IsOdd.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-01-15
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information;
-
-public class IsOdd : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var arg1 = GetFirstValue(arguments); //arguments.ElementAt(0);
-    if (!ConvertUtil.IsNumeric(arg1)) {
-      ThrowExcelErrorValueException(eErrorType.Value);
-    }
-    var number = (int)System.Math.Floor(ConvertUtil.GetValueDouble(arg1));
-    return CreateResult(number % 2 == 1, DataType.Boolean);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/IsText.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/IsText.cs
deleted file mode 100644
index b2d288b..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Information/IsText.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information;
-
-public class IsText : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    if (arguments.Count() == 1 && arguments.ElementAt(0).Value != null) {
-      return CreateResult((GetFirstValue(arguments) is string), DataType.Boolean);
-    }
-    return CreateResult(false, DataType.Boolean);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/N.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/N.cs
deleted file mode 100644
index cf3d171..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Information/N.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.Exceptions;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information;
-
-public class N : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var arg = GetFirstValue(arguments);
-
-    if (arg is bool b) {
-      var val = b ? 1d : 0d;
-      return CreateResult(val, DataType.Decimal);
-    }
-    if (IsNumeric(arg)) {
-      var val = ConvertUtil.GetValueDouble(arg);
-      return CreateResult(val, DataType.Decimal);
-    }
-    if (arg is string) {
-      return CreateResult(0d, DataType.Decimal);
-    }
-    if (arg is ExcelErrorValue) {
-      return CreateResult(arg, DataType.ExcelError);
-    }
-    throw new ExcelErrorValueException(eErrorType.Value);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/Na.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/Na.cs
deleted file mode 100644
index 93bfba2..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Information/Na.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information;
-
-public class Na : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    return CreateResult(ExcelErrorValue.Create(eErrorType.Na), DataType.ExcelError);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/IntArgumentParser.cs b/EPPlus/FormulaParsing/Excel/Functions/IntArgumentParser.cs
deleted file mode 100644
index 40a5d21..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/IntArgumentParser.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.Exceptions;
-using OfficeOpenXml.FormulaParsing.Utilities;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-public class IntArgumentParser : ArgumentParser {
-  public override object Parse(object obj) {
-    Require.That(obj).Named("argument").IsNotNull();
-    if (obj is ExcelDataProvider.IRangeInfo info) {
-      var r = info.FirstOrDefault();
-      return r == null ? 0 : Convert.ToInt32(r.ValueDouble);
-    }
-    var objType = obj.GetType();
-    if (objType == typeof(int)) {
-      return (int)obj;
-    }
-    if (objType == typeof(double) || objType == typeof(decimal)) {
-      return Convert.ToInt32(obj);
-    }
-    if (!int.TryParse(obj.ToString(), out var result)) {
-      throw new ExcelErrorValueException(ExcelErrorValue.Create(eErrorType.Value));
-    }
-    return result;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Logical/And.cs b/EPPlus/FormulaParsing/Excel/Functions/Logical/And.cs
deleted file mode 100644
index c483af5..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Logical/And.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Logical;
-
-public class And : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    for (var x = 0; x < arguments.Count(); x++) {
-      if (!ArgToBool(arguments, x)) {
-        return new(false, DataType.Boolean);
-      }
-    }
-    return new(true, DataType.Boolean);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Logical/False.cs b/EPPlus/FormulaParsing/Excel/Functions/Logical/False.cs
deleted file mode 100644
index 176d31a..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Logical/False.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Logical;
-
-public class False : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    return CreateResult(false, DataType.Boolean);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Logical/If.cs b/EPPlus/FormulaParsing/Excel/Functions/Logical/If.cs
deleted file mode 100644
index bc55272..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Logical/If.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Logical;
-
-public class If : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 3);
-    var condition = ArgToBool(arguments, 0);
-    var firstStatement = arguments.ElementAt(1).Value;
-    var secondStatement = arguments.ElementAt(2).Value;
-    var factory = new CompileResultFactory();
-    return condition ? factory.Create(firstStatement) : factory.Create(secondStatement);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Logical/IfError.cs b/EPPlus/FormulaParsing/Excel/Functions/Logical/IfError.cs
deleted file mode 100644
index 8fe9993..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Logical/IfError.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Logical;
-
-public class IfError : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var firstArg = arguments.First();
-    return GetResultByObject(firstArg.Value);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Logical/IfNa.cs b/EPPlus/FormulaParsing/Excel/Functions/Logical/IfNa.cs
deleted file mode 100644
index ec74404..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Logical/IfNa.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Logical;
-
-public class IfNa : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var firstArg = arguments.First();
-    return GetResultByObject(firstArg.Value);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Logical/Not.cs b/EPPlus/FormulaParsing/Excel/Functions/Logical/Not.cs
deleted file mode 100644
index aec7f74..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Logical/Not.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Logical;
-
-public class Not : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var result = !ArgToBool(arguments, 0);
-    return new(result, DataType.Boolean);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Logical/Or.cs b/EPPlus/FormulaParsing/Excel/Functions/Logical/Or.cs
deleted file mode 100644
index bcf6e31..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Logical/Or.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Logical;
-
-public class Or : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    for (var x = 0; x < arguments.Count(); x++) {
-      if (ArgToBool(arguments, x)) {
-        return new(true, DataType.Boolean);
-      }
-    }
-    return new(false, DataType.Boolean);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Logical/True.cs b/EPPlus/FormulaParsing/Excel/Functions/Logical/True.cs
deleted file mode 100644
index bb23a62..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Logical/True.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Logical;
-
-public class True : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    return CreateResult(true, DataType.Boolean);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Abs.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Abs.cs
deleted file mode 100644
index ad29a14..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Abs.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Abs : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var val = ArgToDecimal(arguments, 0);
-    if (val < 0) {
-      val *= -1;
-    }
-    return CreateResult(val, DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Acos.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Acos.cs
deleted file mode 100644
index 077a02e..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Acos.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-01-11
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Acos : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var arg = ArgToDecimal(arguments, 0);
-    return CreateResult(MathHelper.Arccos(arg), DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Acosh.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Acosh.cs
deleted file mode 100644
index cf07e1b..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Acosh.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-01-11
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Acosh : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var arg = ArgToDecimal(arguments, 0);
-    return CreateResult(MathHelper.HArccos(arg), DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Asin.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Asin.cs
deleted file mode 100644
index 288763c..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Asin.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-01-11
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Asin : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var arg = ArgToDecimal(arguments, 0);
-    return CreateResult(System.Math.Asin(arg), DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Asinh.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Asinh.cs
deleted file mode 100644
index 80ebdfa..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Asinh.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-01-11
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Asinh : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var arg = ArgToDecimal(arguments, 0);
-    return CreateResult(MathHelper.HArcsin(arg), DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Atan.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Atan.cs
deleted file mode 100644
index 9cc60b0..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Atan.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Atan : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var arg = ArgToDecimal(arguments, 0);
-    return CreateResult(System.Math.Atan(arg), DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Atan2.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Atan2.cs
deleted file mode 100644
index a490c1d..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Atan2.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Atan2 : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var arg1 = ArgToDecimal(arguments, 0);
-    var arg2 = ArgToDecimal(arguments, 1);
-    // Had to switch order of the arguments to get the same result as in excel /MA
-    return CreateResult(System.Math.Atan2(arg2, arg1), DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Atanh.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Atanh.cs
deleted file mode 100644
index 302c97f..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Atanh.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-01-11
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Atanh : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var arg = ArgToDecimal(arguments, 0);
-    return CreateResult(MathHelper.HArctan(arg), DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Average.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Average.cs
deleted file mode 100644
index b154d24..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Average.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Globalization;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Average : HiddenValuesHandlingFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1, eErrorType.Div0);
-    double nValues = 0d,
-        result = 0d;
-    foreach (var arg in arguments) {
-      Calculate(arg, context, ref result, ref nValues);
-    }
-    return CreateResult(Divide(result, nValues), DataType.Decimal);
-  }
-
-  private void Calculate(
-      FunctionArgument arg,
-      ParsingContext context,
-      ref double retVal,
-      ref double nValues,
-      bool isInArray = false) {
-    if (ShouldIgnore(arg)) {
-      return;
-    }
-    if (arg.Value is IEnumerable<FunctionArgument> value) {
-      foreach (var item in value) {
-        Calculate(item, context, ref retVal, ref nValues, true);
-      }
-    } else if (arg.IsExcelRange) {
-      foreach (var c in arg.ValueAsRangeInfo) {
-        if (ShouldIgnore(c, context)) {
-          continue;
-        }
-        CheckForAndHandleExcelError(c);
-        if (!IsNumeric(c.Value)) {
-          continue;
-        }
-        nValues++;
-        retVal += c.ValueDouble;
-      }
-    } else {
-      var numericValue = GetNumericValue(arg.Value, isInArray);
-      if (numericValue.HasValue) {
-        nValues++;
-        retVal += numericValue.Value;
-      } else if ((arg.Value is string) && !ConvertUtil.IsNumericString(arg.Value)) {
-        if (!isInArray) {
-          ThrowExcelErrorValueException(eErrorType.Value);
-        }
-      }
-    }
-    CheckForAndHandleExcelError(arg);
-  }
-
-  private double? GetNumericValue(object obj, bool isInArray) {
-    if (IsNumeric(obj)) {
-      return ConvertUtil.GetValueDouble(obj);
-    }
-    if ((obj is bool) && !isInArray) {
-      return ConvertUtil.GetValueDouble(obj);
-    }
-    if (ConvertUtil.IsNumericString(obj)) {
-      return double.Parse(obj.ToString(), CultureInfo.InvariantCulture);
-    }
-    return default(double?);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/AverageA.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/AverageA.cs
deleted file mode 100644
index 5cbcdb0..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/AverageA.cs
+++ /dev/null
@@ -1,106 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2014-01-06
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Globalization;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class AverageA : HiddenValuesHandlingFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1, eErrorType.Div0);
-    double nValues = 0d,
-        result = 0d;
-    foreach (var arg in arguments) {
-      Calculate(arg, context, ref result, ref nValues);
-    }
-    return CreateResult(Divide(result, nValues), DataType.Decimal);
-  }
-
-  private void Calculate(
-      FunctionArgument arg,
-      ParsingContext context,
-      ref double retVal,
-      ref double nValues,
-      bool isInArray = false) {
-    if (ShouldIgnore(arg)) {
-      return;
-    }
-    if (arg.Value is IEnumerable<FunctionArgument> value) {
-      foreach (var item in value) {
-        Calculate(item, context, ref retVal, ref nValues, true);
-      }
-    } else if (arg.IsExcelRange) {
-      foreach (var c in arg.ValueAsRangeInfo) {
-        if (ShouldIgnore(c, context)) {
-          continue;
-        }
-        CheckForAndHandleExcelError(c);
-        if (IsNumeric(c.Value)) {
-          nValues++;
-          retVal += c.ValueDouble;
-        } else if (c.Value is bool cValue) {
-          nValues++;
-          retVal += cValue ? 1 : 0;
-        } else if (c.Value is string) {
-          nValues++;
-        }
-      }
-    } else {
-      var numericValue = GetNumericValue(arg.Value, isInArray);
-      if (numericValue.HasValue) {
-        nValues++;
-        retVal += numericValue.Value;
-      } else if ((arg.Value is string) && !ConvertUtil.IsNumericString(arg.Value)) {
-        if (isInArray) {
-          nValues++;
-        } else {
-          ThrowExcelErrorValueException(eErrorType.Value);
-        }
-      }
-    }
-    CheckForAndHandleExcelError(arg);
-  }
-
-  private double? GetNumericValue(object obj, bool isInArray) {
-    if (IsNumeric(obj)) {
-      return ConvertUtil.GetValueDouble(obj);
-    }
-    if (obj is bool) {
-      if (isInArray) {
-        return default(double?);
-      }
-      return ConvertUtil.GetValueDouble(obj);
-    }
-    if (ConvertUtil.IsNumericString(obj)) {
-      return double.Parse(obj.ToString(), CultureInfo.InvariantCulture);
-    }
-    return default(double?);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/AverageIf.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/AverageIf.cs
deleted file mode 100644
index 5568a25..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/AverageIf.cs
+++ /dev/null
@@ -1,128 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExcelUtilities;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-using OfficeOpenXml.FormulaParsing.Utilities;
-using OfficeOpenXml.Utils;
-using Require = OfficeOpenXml.FormulaParsing.Utilities.Require;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class AverageIf : HiddenValuesHandlingFunction {
-  private readonly NumericExpressionEvaluator _numericExpressionEvaluator;
-  private readonly WildCardValueMatcher _wildCardValueMatcher;
-
-  public AverageIf()
-      : this(new(), new()) {}
-
-  public AverageIf(
-      NumericExpressionEvaluator evaluator,
-      WildCardValueMatcher wildCardValueMatcher) {
-    Require.That(evaluator).Named("evaluator").IsNotNull();
-    Require.That(evaluator).Named("wildCardValueMatcher").IsNotNull();
-    _numericExpressionEvaluator = evaluator;
-    _wildCardValueMatcher = wildCardValueMatcher;
-  }
-
-  private bool Evaluate(object obj, string expression) {
-    double? candidate = default(double?);
-    if (IsNumeric(obj)) {
-      candidate = ConvertUtil.GetValueDouble(obj);
-    }
-    if (candidate.HasValue) {
-      return _numericExpressionEvaluator.Evaluate(candidate.Value, expression);
-    }
-    if (obj == null) {
-      return false;
-    }
-    return _wildCardValueMatcher.IsMatch(expression, obj.ToString()) == 0;
-  }
-
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var firstArg = arguments.ElementAt(0);
-    var args = firstArg.Value as IEnumerable<FunctionArgument>;
-    if (args == null && firstArg.IsExcelRange) {
-      args = new List<FunctionArgument> { firstArg };
-    }
-    var criteria = arguments.ElementAt(1).Value;
-    ThrowExcelErrorValueExceptionIf(
-        () => criteria == null || criteria.ToString().Length > 255,
-        eErrorType.Value);
-    double retVal;
-    if (arguments.Count() > 2) {
-      var secondArg = arguments.ElementAt(2);
-      var lookupRange = secondArg.Value as IEnumerable<FunctionArgument>;
-      if (lookupRange == null && secondArg.IsExcelRange) {
-        lookupRange = new List<FunctionArgument> { secondArg };
-      }
-      retVal = CalculateWithLookupRange(args, criteria.ToString(), lookupRange, context);
-    } else {
-      retVal = CalculateSingleRange(args, criteria.ToString(), context);
-    }
-    return CreateResult(retVal, DataType.Decimal);
-  }
-
-  private double CalculateWithLookupRange(
-      IEnumerable<FunctionArgument> range,
-      string criteria,
-      IEnumerable<FunctionArgument> sumRange,
-      ParsingContext context) {
-    var retVal = 0d;
-    var nMatches = 0;
-    var flattenedRange = ArgsToObjectEnumerable(false, range, context);
-    var flattenedSumRange = ArgsToDoubleEnumerable(sumRange, context);
-    for (var x = 0; x < flattenedRange.Count(); x++) {
-      var candidate = flattenedSumRange.ElementAt(x);
-      if (Evaluate(flattenedRange.ElementAt(x), criteria)) {
-        nMatches++;
-        retVal += candidate;
-      }
-    }
-    return Divide(retVal, nMatches);
-  }
-
-  private double CalculateSingleRange(
-      IEnumerable<FunctionArgument> args,
-      string expression,
-      ParsingContext context) {
-    var retVal = 0d;
-    var nMatches = 0;
-    var flattendedRange = ArgsToDoubleEnumerable(args, context);
-    var candidates = flattendedRange as double[] ?? flattendedRange.ToArray();
-    foreach (var candidate in candidates) {
-      if (Evaluate(candidate, expression)) {
-        retVal += candidate;
-        nMatches++;
-      }
-    }
-    return Divide(retVal, nMatches);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/AverageIfs.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/AverageIfs.cs
deleted file mode 100644
index a24266c..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/AverageIfs.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-02-01
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class AverageIfs : MultipleRangeCriteriasFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray();
-    ValidateArguments(functionArguments, 3);
-    var sumRange = ArgsToDoubleEnumerable(
-            true,
-            new List<FunctionArgument> { functionArguments[0] },
-            context)
-        .ToList();
-    var argRanges = new List<ExcelDataProvider.IRangeInfo>();
-    var criterias = new List<object>();
-    for (var ix = 1; ix < 31; ix += 2) {
-      if (functionArguments.Length <= ix) {
-        break;
-      }
-      var rangeInfo = functionArguments[ix].ValueAsRangeInfo;
-      argRanges.Add(rangeInfo);
-      if (ix > 1) {
-        ThrowExcelErrorValueExceptionIf(
-            () => rangeInfo.GetNCells() != argRanges[0].GetNCells(),
-            eErrorType.Value);
-      }
-      criterias.Add(functionArguments[ix + 1].Value);
-    }
-    IEnumerable<int> matchIndexes = GetMatchIndexes(argRanges[0], criterias[0]);
-    var enumerable = matchIndexes as IList<int> ?? matchIndexes.ToList();
-    for (var ix = 1; ix < argRanges.Count && enumerable.Any(); ix++) {
-      var indexes = GetMatchIndexes(argRanges[ix], criterias[ix]);
-      matchIndexes = enumerable.Intersect(indexes);
-    }
-
-    var result = matchIndexes.Average(index => sumRange[index]);
-
-    return CreateResult(result, DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Ceiling.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Ceiling.cs
deleted file mode 100644
index 2140891..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Ceiling.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Ceiling : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var number = ArgToDecimal(arguments, 0);
-    var significance = ArgToDecimal(arguments, 1);
-    ValidateNumberAndSign(number, significance);
-    if (significance < 1 && significance > 0) {
-      var floor = System.Math.Floor(number);
-      var rest = number - floor;
-      var nSign = (int)(rest / significance) + 1;
-      return CreateResult(floor + (nSign * significance), DataType.Decimal);
-    }
-    if (significance == 1) {
-      return CreateResult(System.Math.Ceiling(number), DataType.Decimal);
-    }
-    var result = number - (number % significance) + significance;
-    return CreateResult(result, DataType.Decimal);
-  }
-
-  private void ValidateNumberAndSign(double number, double sign) {
-    if (number > 0d && sign < 0) {
-      var values = string.Format("num: {0}, sign: {1}", number, sign);
-      throw new InvalidOperationException(
-          "Ceiling cannot handle a negative significance when the number is positive" + values);
-    }
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Cos.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Cos.cs
deleted file mode 100644
index a605707..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Cos.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Cos : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var arg = ArgToDecimal(arguments, 0);
-    return CreateResult(System.Math.Cos(arg), DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Cosh.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Cosh.cs
deleted file mode 100644
index bb15381..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Cosh.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Cosh : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var arg = ArgToDecimal(arguments, 0);
-    return CreateResult(System.Math.Cosh(arg), DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Count.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Count.cs
deleted file mode 100644
index c5c42da..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Count.cs
+++ /dev/null
@@ -1,104 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Count : HiddenValuesHandlingFunction {
-  private enum ItemContext {
-    InRange,
-    InArray,
-    SingleArg,
-  }
-
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var nItems = 0d;
-    Calculate(arguments, ref nItems, context, ItemContext.SingleArg);
-    return CreateResult(nItems, DataType.Integer);
-  }
-
-  private void Calculate(
-      IEnumerable<FunctionArgument> items,
-      ref double nItems,
-      ParsingContext context,
-      ItemContext itemContext) {
-    foreach (var item in items) {
-      var cs = item.Value as ExcelDataProvider.IRangeInfo;
-      if (cs != null) {
-        foreach (var c in cs) {
-          _CheckForAndHandleExcelError(c, context);
-          if (ShouldIgnore(c, context) == false && ShouldCount(c.Value, ItemContext.InRange)) {
-            nItems++;
-          }
-        }
-      } else {
-        var value = item.Value as IEnumerable<FunctionArgument>;
-        if (value != null) {
-          Calculate(value, ref nItems, context, ItemContext.InArray);
-        } else {
-          _CheckForAndHandleExcelError(item, context);
-          if (ShouldIgnore(item) == false && ShouldCount(item.Value, itemContext)) {
-            nItems++;
-          }
-        }
-      }
-    }
-  }
-
-  private void _CheckForAndHandleExcelError(FunctionArgument arg, ParsingContext context) {
-    //if (context.Scopes.Current.IsSubtotal)
-    //{
-    //    CheckForAndHandleExcelError(arg);
-    //}
-  }
-
-  private void _CheckForAndHandleExcelError(
-      ExcelDataProvider.ICellInfo cell,
-      ParsingContext context) {
-    //if (context.Scopes.Current.IsSubtotal)
-    //{
-    //    CheckForAndHandleExcelError(cell);
-    //}
-  }
-
-  private bool ShouldCount(object value, ItemContext context) {
-    switch (context) {
-      case ItemContext.SingleArg:
-        return IsNumeric(value) || IsNumericString(value);
-      case ItemContext.InRange:
-        return IsNumeric(value);
-      case ItemContext.InArray:
-        return IsNumeric(value) || IsNumericString(value);
-      default:
-        throw new ArgumentException("Unknown ItemContext:" + context);
-    }
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/CountA.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/CountA.cs
deleted file mode 100644
index a9e3b52..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/CountA.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class CountA : HiddenValuesHandlingFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var nItems = 0d;
-    Calculate(arguments, context, ref nItems);
-    return CreateResult(nItems, DataType.Integer);
-  }
-
-  private void Calculate(
-      IEnumerable<FunctionArgument> items,
-      ParsingContext context,
-      ref double nItems) {
-    foreach (var item in items) {
-      var cs = item.Value as ExcelDataProvider.IRangeInfo;
-      if (cs != null) {
-        foreach (var c in cs) {
-          _CheckForAndHandleExcelError(c, context);
-          if (!ShouldIgnore(c, context) && ShouldCount(c.Value)) {
-            nItems++;
-          }
-        }
-      } else if (item.Value is IEnumerable<FunctionArgument> value) {
-        Calculate(value, context, ref nItems);
-      } else {
-        _CheckForAndHandleExcelError(item, context);
-        if (!ShouldIgnore(item) && ShouldCount(item.Value)) {
-          nItems++;
-        }
-      }
-    }
-  }
-
-  private void _CheckForAndHandleExcelError(FunctionArgument arg, ParsingContext context) {
-    if (context.Scopes.Current.IsSubtotal) {
-      CheckForAndHandleExcelError(arg);
-    }
-  }
-
-  private void _CheckForAndHandleExcelError(
-      ExcelDataProvider.ICellInfo cell,
-      ParsingContext context) {
-    if (context.Scopes.Current.IsSubtotal) {
-      CheckForAndHandleExcelError(cell);
-    }
-  }
-
-  private bool ShouldCount(object value) {
-    if (value == null) {
-      return false;
-    }
-    return (!string.IsNullOrEmpty(value.ToString()));
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/CountBlank.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/CountBlank.cs
deleted file mode 100644
index 23176ae..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/CountBlank.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class CountBlank : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var arg = arguments.First();
-    if (!arg.IsExcelRange) {
-      throw new InvalidOperationException("CountBlank only support ranges as arguments");
-    }
-    var result = arg.ValueAsRangeInfo.GetNCells();
-    foreach (var cell in arg.ValueAsRangeInfo) {
-      if (!(cell.Value == null || cell.Value == string.Empty)) {
-        result--;
-      }
-    }
-    return CreateResult(result, DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/CountIf.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/CountIf.cs
deleted file mode 100644
index 277058c..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/CountIf.cs
+++ /dev/null
@@ -1,66 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExcelUtilities;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-using OfficeOpenXml.FormulaParsing.Utilities;
-using OfficeOpenXml.Utils;
-using Require = OfficeOpenXml.FormulaParsing.Utilities.Require;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class CountIf : ExcelFunction {
-  private readonly NumericExpressionEvaluator _numericExpressionEvaluator;
-  private readonly WildCardValueMatcher _wildCardValueMatcher;
-
-  public CountIf()
-      : this(new(), new()) {}
-
-  public CountIf(NumericExpressionEvaluator evaluator, WildCardValueMatcher wildCardValueMatcher) {
-    Require.That(evaluator).Named("evaluator").IsNotNull();
-    Require.That(wildCardValueMatcher).Named("wildCardValueMatcher").IsNotNull();
-    _numericExpressionEvaluator = evaluator;
-    _wildCardValueMatcher = wildCardValueMatcher;
-  }
-
-  private bool Evaluate(object obj, string expression) {
-    double? candidate = default(double?);
-    if (IsNumeric(obj)) {
-      candidate = ConvertUtil.GetValueDouble(obj);
-    }
-    if (candidate.HasValue) {
-      return _numericExpressionEvaluator.Evaluate(candidate.Value, expression);
-    }
-    if (obj == null) {
-      return false;
-    }
-    return _wildCardValueMatcher.IsMatch(expression, obj.ToString()) == 0;
-  }
-
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray();
-    ValidateArguments(functionArguments, 2);
-    var range = functionArguments.ElementAt(0);
-    var criteria = ArgToString(functionArguments, 1);
-    double result = 0d;
-    if (range.IsExcelRange) {
-      foreach (var cell in range.ValueAsRangeInfo) {
-        if (Evaluate(cell.Value, criteria)) {
-          result++;
-        }
-      }
-    } else if (range.Value is IEnumerable<FunctionArgument> value) {
-      foreach (var arg in value) {
-        if (Evaluate(arg.Value, criteria)) {
-          result++;
-        }
-      }
-    } else {
-      if (Evaluate(range.Value, criteria)) {
-        result++;
-      }
-    }
-    return CreateResult(result, DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/CountIfs.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/CountIfs.cs
deleted file mode 100644
index e4b7418..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/CountIfs.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-01-11
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class CountIfs : MultipleRangeCriteriasFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray();
-    ValidateArguments(functionArguments, 2);
-    var argRanges = new List<ExcelDataProvider.IRangeInfo>();
-    var criterias = new List<object>();
-    for (var ix = 0; ix < 30; ix += 2) {
-      if (functionArguments.Length <= ix) {
-        break;
-      }
-      var rangeInfo = functionArguments[ix].ValueAsRangeInfo;
-      argRanges.Add(rangeInfo);
-      if (ix > 0) {
-        ThrowExcelErrorValueExceptionIf(
-            () => rangeInfo.GetNCells() != argRanges[0].GetNCells(),
-            eErrorType.Value);
-      }
-      criterias.Add(functionArguments[ix + 1].Value);
-    }
-    IEnumerable<int> matchIndexes = GetMatchIndexes(argRanges[0], criterias[0]);
-    var enumerable = matchIndexes as IList<int> ?? matchIndexes.ToList();
-    for (var ix = 1; ix < argRanges.Count && enumerable.Any(); ix++) {
-      var indexes = GetMatchIndexes(argRanges[ix], criterias[ix]);
-      matchIndexes = enumerable.Intersect(indexes);
-    }
-
-    return CreateResult((double)matchIndexes.Count(), DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Degrees.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Degrees.cs
deleted file mode 100644
index 7faae97..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Degrees.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Degrees : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var angle = ArgToDecimal(arguments, 0);
-    var result = (angle * 180) / System.Math.PI;
-    return CreateResult(result, DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Exp.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Exp.cs
deleted file mode 100644
index de88305..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Exp.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Exp : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var number = ArgToDecimal(arguments, 0);
-    return CreateResult(System.Math.Exp(number), DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Fact.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Fact.cs
deleted file mode 100644
index 2bb24f5..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Fact.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Fact : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var number = ArgToDecimal(arguments, 0);
-    ThrowExcelErrorValueExceptionIf(() => number < 0, eErrorType.Na);
-    var result = 1d;
-    for (var x = 1; x < number; x++) {
-      result *= x;
-    }
-    return CreateResult(result, DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Floor.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Floor.cs
deleted file mode 100644
index caa43c5..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Floor.cs
+++ /dev/null
@@ -1,65 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Floor : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var number = ArgToDecimal(arguments, 0);
-    var significance = ArgToDecimal(arguments, 1);
-    ValidateNumberAndSign(number, significance);
-    if (significance < 1 && significance > 0) {
-      var floor = System.Math.Floor(number);
-      var rest = number - floor;
-      var nSign = (int)(rest / significance);
-      return CreateResult(floor + (nSign * significance), DataType.Decimal);
-    }
-    if (significance == 1) {
-      return CreateResult(System.Math.Floor(number), DataType.Decimal);
-    }
-    double result;
-    if (number > 1) {
-      result = number - (number % significance) + significance;
-    } else {
-      result = number - (number % significance);
-    }
-    return CreateResult(result, DataType.Decimal);
-  }
-
-  private void ValidateNumberAndSign(double number, double sign) {
-    if (number > 0d && sign < 0) {
-      var values = string.Format("num: {0}, sign: {1}", number, sign);
-      throw new InvalidOperationException(
-          "Floor cannot handle a negative significance when the number is positive" + values);
-    }
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Large.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Large.cs
deleted file mode 100644
index 025c47f..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Large.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Large : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var args = arguments.ElementAt(0);
-    var index = ArgToInt(arguments, 1) - 1;
-    var values = ArgsToDoubleEnumerable(new List<FunctionArgument> { args }, context);
-    ThrowExcelErrorValueExceptionIf(() => index < 0 || index >= values.Count(), eErrorType.Num);
-    var result = values.OrderByDescending(x => x).ElementAt(index);
-    return CreateResult(result, DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Ln.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Ln.cs
deleted file mode 100644
index e93147f..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Ln.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Ln : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var arg = ArgToDecimal(arguments, 0);
-    return CreateResult(System.Math.Log(arg, System.Math.E), DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Log.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Log.cs
deleted file mode 100644
index c348ecf..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Log.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Log : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var number = ArgToDecimal(arguments, 0);
-    if (arguments.Count() == 1) {
-      return CreateResult(System.Math.Log(number, 10d), DataType.Decimal);
-    }
-    var newBase = ArgToDecimal(arguments, 1);
-    return CreateResult(System.Math.Log(number, newBase), DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Log10.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Log10.cs
deleted file mode 100644
index c9f9431..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Log10.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Log10 : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var number = ArgToDecimal(arguments, 0);
-    return CreateResult(System.Math.Log10(number), DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/MathHelper.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/MathHelper.cs
deleted file mode 100644
index 6b9163a..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/MathHelper.cs
+++ /dev/null
@@ -1,138 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-01-11
- *******************************************************************************/
-
-using MathObj = System.Math;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-/// <summary>
-/// Thanks to the guys in this thread: http://stackoverflow.com/questions/2840798/c-sharp-math-class-question
-/// </summary>
-public static class MathHelper {
-  // Secant
-  public static double Sec(double x) {
-    return 1 / MathObj.Cos(x);
-  }
-
-  // Cosecant
-  public static double Cosec(double x) {
-    return 1 / MathObj.Sin(x);
-  }
-
-  // Cotangent
-  public static double Cotan(double x) {
-    return 1 / MathObj.Tan(x);
-  }
-
-  // Inverse Sine
-  public static double Arcsin(double x) {
-    return MathObj.Atan(x / MathObj.Sqrt(-x * x + 1));
-  }
-
-  // Inverse Cosine
-  public static double Arccos(double x) {
-    return MathObj.Atan(-x / MathObj.Sqrt(-x * x + 1)) + 2 * MathObj.Atan(1);
-  }
-
-  // Inverse Secant
-  public static double Arcsec(double x) {
-    return 2 * MathObj.Atan(1) - MathObj.Atan(MathObj.Sign(x) / MathObj.Sqrt(x * x - 1));
-  }
-
-  // Inverse Cosecant
-  public static double Arccosec(double x) {
-    return MathObj.Atan(MathObj.Sign(x) / MathObj.Sqrt(x * x - 1));
-  }
-
-  // Inverse Cotangent
-  public static double Arccotan(double x) {
-    return 2 * MathObj.Atan(1) - MathObj.Atan(x);
-  }
-
-  // Hyperbolic Sine
-  public static double HSin(double x) {
-    return (MathObj.Exp(x) - MathObj.Exp(-x)) / 2;
-  }
-
-  // Hyperbolic Cosine
-  public static double HCos(double x) {
-    return (MathObj.Exp(x) + MathObj.Exp(-x)) / 2;
-  }
-
-  // Hyperbolic Tangent
-  public static double HTan(double x) {
-    return (MathObj.Exp(x) - MathObj.Exp(-x)) / (MathObj.Exp(x) + MathObj.Exp(-x));
-  }
-
-  // Hyperbolic Secant
-  public static double HSec(double x) {
-    return 2 / (MathObj.Exp(x) + MathObj.Exp(-x));
-  }
-
-  // Hyperbolic Cosecant
-  public static double HCosec(double x) {
-    return 2 / (MathObj.Exp(x) - MathObj.Exp(-x));
-  }
-
-  // Hyperbolic Cotangent
-  public static double HCotan(double x) {
-    return (MathObj.Exp(x) + MathObj.Exp(-x)) / (MathObj.Exp(x) - MathObj.Exp(-x));
-  }
-
-  // Inverse Hyperbolic Sine
-  public static double HArcsin(double x) {
-    return MathObj.Log(x + MathObj.Sqrt(x * x + 1));
-  }
-
-  // Inverse Hyperbolic Cosine
-  public static double HArccos(double x) {
-    return MathObj.Log(x + MathObj.Sqrt(x * x - 1));
-  }
-
-  // Inverse Hyperbolic Tangent
-  public static double HArctan(double x) {
-    return MathObj.Log((1 + x) / (1 - x)) / 2;
-  }
-
-  // Inverse Hyperbolic Secant
-  public static double HArcsec(double x) {
-    return MathObj.Log((MathObj.Sqrt(-x * x + 1) + 1) / x);
-  }
-
-  // Inverse Hyperbolic Cosecant
-  public static double HArccosec(double x) {
-    return MathObj.Log((MathObj.Sign(x) * MathObj.Sqrt(x * x + 1) + 1) / x);
-  }
-
-  // Inverse Hyperbolic Cotangent
-  public static double HArccotan(double x) {
-    return MathObj.Log((x + 1) / (x - 1)) / 2;
-  }
-
-  // Logarithm to base N
-  public static double LogN(double x, double n) {
-    return MathObj.Log(x) / MathObj.Log(n);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Max.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Max.cs
deleted file mode 100644
index c6ddf8f..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Max.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Max : HiddenValuesHandlingFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var values = ArgsToDoubleEnumerable(IgnoreHiddenValues, false, arguments, context);
-    return CreateResult(values.Max(), DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Maxa.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Maxa.cs
deleted file mode 100644
index 1ef491a..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Maxa.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-using OfficeOpenXml.FormulaParsing.Utilities;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Maxa : ExcelFunction {
-  private readonly DoubleEnumerableArgConverter _argConverter;
-
-  public Maxa()
-      : this(new()) {}
-
-  public Maxa(DoubleEnumerableArgConverter argConverter) {
-    Require.That(argConverter).Named("argConverter").IsNotNull();
-    _argConverter = argConverter;
-  }
-
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var values = _argConverter.ConvertArgsIncludingOtherTypes(arguments);
-    return CreateResult(values.Max(), DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Median.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Median.cs
deleted file mode 100644
index 6edc020..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Median.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-01-10
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Median : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    var nums = ArgsToDoubleEnumerable(arguments, context);
-    var arr = nums.ToArray();
-    Array.Sort(arr);
-    ThrowExcelErrorValueExceptionIf(() => arr.Length == 0, eErrorType.Num);
-    double result;
-    if (arr.Length % 2 == 1) {
-      result = arr[arr.Length / 2];
-    } else {
-      var startIndex = arr.Length / 2 - 1;
-      result = (arr[startIndex] + arr[startIndex + 1]) / 2d;
-    }
-    return CreateResult(result, DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Min.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Min.cs
deleted file mode 100644
index f2b5fdf..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Min.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Min : HiddenValuesHandlingFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var values = ArgsToDoubleEnumerable(IgnoreHiddenValues, false, arguments, context);
-    return CreateResult(values.Min(), DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Mina.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Mina.cs
deleted file mode 100644
index a93424f..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Mina.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-using OfficeOpenXml.FormulaParsing.Utilities;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Mina : ExcelFunction {
-  private readonly DoubleEnumerableArgConverter _argConverter;
-
-  public Mina()
-      : this(new()) {}
-
-  public Mina(DoubleEnumerableArgConverter argConverter) {
-    Require.That(argConverter).Named("argConverter").IsNotNull();
-    _argConverter = argConverter;
-  }
-
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var values = _argConverter.ConvertArgsIncludingOtherTypes(arguments);
-    return CreateResult(values.Min(), DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Mod.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Mod.cs
deleted file mode 100644
index 968e1c8..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Mod.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Mod : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var n1 = ArgToDecimal(arguments, 0);
-    var n2 = ArgToDecimal(arguments, 1);
-    return new(n1 % n2, DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/MultipleRangeCriteriasFunction.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/MultipleRangeCriteriasFunction.cs
deleted file mode 100644
index 5efe6f0..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/MultipleRangeCriteriasFunction.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-01-15
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExcelUtilities;
-using OfficeOpenXml.FormulaParsing.Utilities;
-using OfficeOpenXml.Utils;
-using Require = OfficeOpenXml.FormulaParsing.Utilities.Require;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public abstract class MultipleRangeCriteriasFunction : ExcelFunction {
-  private readonly NumericExpressionEvaluator _numericExpressionEvaluator;
-  private readonly WildCardValueMatcher _wildCardValueMatcher;
-
-  protected MultipleRangeCriteriasFunction()
-      : this(new(), new()) {}
-
-  protected MultipleRangeCriteriasFunction(
-      NumericExpressionEvaluator evaluator,
-      WildCardValueMatcher wildCardValueMatcher) {
-    Require.That(evaluator).Named("evaluator").IsNotNull();
-    Require.That(wildCardValueMatcher).Named("wildCardValueMatcher").IsNotNull();
-    _numericExpressionEvaluator = evaluator;
-    _wildCardValueMatcher = wildCardValueMatcher;
-  }
-
-  protected bool Evaluate(object obj, object expression) {
-    double? candidate = default(double?);
-    if (IsNumeric(obj)) {
-      candidate = ConvertUtil.GetValueDouble(obj);
-    }
-    if (candidate.HasValue && expression is string) {
-      return _numericExpressionEvaluator.Evaluate(candidate.Value, expression.ToString());
-    }
-    if (obj == null) {
-      return false;
-    }
-    return _wildCardValueMatcher.IsMatch(expression, obj.ToString()) == 0;
-  }
-
-  protected List<int> GetMatchIndexes(ExcelDataProvider.IRangeInfo rangeInfo, object searched) {
-    var result = new List<int>();
-    var internalIndex = 0;
-    for (var row = rangeInfo.Address._fromRow; row <= rangeInfo.Address._toRow; row++) {
-      for (var col = rangeInfo.Address._fromCol; col <= rangeInfo.Address._toCol; col++) {
-        var candidate = rangeInfo.GetValue(row, col);
-        if (Evaluate(candidate, searched)) {
-          result.Add(internalIndex);
-        }
-        internalIndex++;
-      }
-    }
-    return result;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Pi.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Pi.cs
deleted file mode 100644
index c606b48..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Pi.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Pi : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    var result = System.Math.Round(System.Math.PI, 14);
-    return CreateResult(result, DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Power.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Power.cs
deleted file mode 100644
index f0fd0a6..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Power.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Power : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var number = ArgToDecimal(arguments, 0);
-    var power = ArgToDecimal(arguments, 1);
-    var result = System.Math.Pow(number, power);
-    return CreateResult(result, DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Product.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Product.cs
deleted file mode 100644
index 5414558..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Product.cs
+++ /dev/null
@@ -1,89 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Product : HiddenValuesHandlingFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var result = 0d;
-    var index = 0;
-    while (AreEqual(result, 0d) && index < arguments.Count()) {
-      result = CalculateFirstItem(arguments, index++, context);
-    }
-    result = CalculateCollection(
-        arguments.Skip(index),
-        result,
-        (arg, current) => {
-          if (ShouldIgnore(arg)) {
-            return current;
-          }
-          if (arg.ValueIsExcelError) {
-            ThrowExcelErrorValueException(arg.ValueAsExcelErrorValue.Type);
-          }
-          if (arg.IsExcelRange) {
-            foreach (var cell in arg.ValueAsRangeInfo) {
-              if (ShouldIgnore(cell, context)) {
-                return current;
-              }
-              current *= cell.ValueDouble;
-            }
-            return current;
-          }
-          var obj = arg.Value;
-          if (obj != null && IsNumeric(obj)) {
-            var val = Convert.ToDouble(obj);
-            current *= val;
-          }
-          return current;
-        });
-    return CreateResult(result, DataType.Decimal);
-  }
-
-  private double CalculateFirstItem(
-      IEnumerable<FunctionArgument> arguments,
-      int index,
-      ParsingContext context) {
-    var element = arguments.ElementAt(index);
-    var argList = new List<FunctionArgument> { element };
-    var valueList = ArgsToDoubleEnumerable(false, false, argList, context);
-    var result = 0d;
-    foreach (var value in valueList) {
-      if (result == 0d && value > 0d) {
-        result = value;
-      } else {
-        result *= value;
-      }
-    }
-    return result;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Quotient.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Quotient.cs
deleted file mode 100644
index 866ddd9..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Quotient.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Quotient : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var num = ArgToDecimal(arguments, 0);
-    var denom = ArgToDecimal(arguments, 1);
-    ThrowExcelErrorValueExceptionIf(() => (int)denom == 0, eErrorType.Div0);
-    var result = (int)(num / denom);
-    return CreateResult(result, DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Rand.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Rand.cs
deleted file mode 100644
index 9beb787..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Rand.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System;
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Rand : ExcelFunction {
-  private static int Seed { get; set; }
-
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    Seed = Seed > 50 ? 0 : Seed + 5;
-    var val = new Random(System.DateTime.Now.Millisecond + Seed).NextDouble();
-    return CreateResult(val, DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/RandBetween.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/RandBetween.cs
deleted file mode 100644
index 5bb9e8a..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/RandBetween.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class RandBetween : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var low = ArgToDecimal(arguments, 0);
-    var high = ArgToDecimal(arguments, 1);
-    var rand = new Rand().Execute(new FunctionArgument[0], context).Result;
-    var randPart = (CalulateDiff(high, low) * (double)rand) + 1;
-    randPart = System.Math.Floor(randPart);
-    return CreateResult(low + randPart, DataType.Integer);
-  }
-
-  private double CalulateDiff(double high, double low) {
-    if (high > 0 && low < 0) {
-      return high + low * -1;
-    }
-    if (high < 0 && low < 0) {
-      return high * -1 - low * -1;
-    }
-    return high - low;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Round.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Round.cs
deleted file mode 100644
index 1bda92d..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Round.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Round : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var number = ArgToDecimal(arguments, 0);
-    var nDigits = ArgToInt(arguments, 1);
-    if (nDigits < 0) {
-      nDigits *= -1;
-      return CreateResult(number - (number % (System.Math.Pow(10, nDigits))), DataType.Integer);
-    }
-    return CreateResult(System.Math.Round(number, nDigits), DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Rounddown.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Rounddown.cs
deleted file mode 100644
index 396c355..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Rounddown.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2014-01-06
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Rounddown : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var number = ArgToDecimal(arguments, 0);
-    var nDecimals = ArgToInt(arguments, 1);
-
-    var nFactor = number < 0 ? -1 : 1;
-    number *= nFactor;
-
-    double result;
-    if (nDecimals > 0) {
-      result = RoundDownDecimalNumber(number, nDecimals);
-    } else {
-      result = (int)System.Math.Floor(number);
-      result = result - (result % System.Math.Pow(10, (nDecimals * -1)));
-    }
-    return CreateResult(result * nFactor, DataType.Decimal);
-  }
-
-  private static double RoundDownDecimalNumber(double number, int nDecimals) {
-    var integerPart = System.Math.Floor(number);
-    var decimalPart = number - integerPart;
-    decimalPart = System.Math.Pow(10d, nDecimals) * decimalPart;
-    decimalPart = System.Math.Truncate(decimalPart) / System.Math.Pow(10d, nDecimals);
-    var result = integerPart + decimalPart;
-    return result;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Roundup.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Roundup.cs
deleted file mode 100644
index d411ce6..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Roundup.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2014-01-06
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Roundup : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var number = ArgToDecimal(arguments, 0);
-    var nDigits = ArgToInt(arguments, 1);
-    double result =
-        (number >= 0)
-            ? System.Math.Ceiling(number * System.Math.Pow(10, nDigits))
-                / System.Math.Pow(10, nDigits)
-            : System.Math.Floor(number * System.Math.Pow(10, nDigits))
-                / System.Math.Pow(10, nDigits);
-    return CreateResult(result, DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Sign.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Sign.cs
deleted file mode 100644
index e09a919..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Sign.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Sign : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var result = 0d;
-    var val = ArgToDecimal(arguments, 0);
-    if (val < 0) {
-      result = -1;
-    } else if (val > 0) {
-      result = 1;
-    }
-    return CreateResult(result, DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Sin.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Sin.cs
deleted file mode 100644
index 5b55efa..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Sin.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Sin : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var arg = ArgToDecimal(arguments, 0);
-    return CreateResult(System.Math.Sin(arg), DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Sinh.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Sinh.cs
deleted file mode 100644
index 5cf3d88..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Sinh.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Sinh : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var arg = ArgToDecimal(arguments, 0);
-    return CreateResult(System.Math.Sinh(arg), DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Small.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Small.cs
deleted file mode 100644
index f22e9fa..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Small.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Small : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var args = arguments.ElementAt(0);
-    var index = ArgToInt(arguments, 1) - 1;
-    var values = ArgsToDoubleEnumerable(new List<FunctionArgument> { args }, context);
-    ThrowExcelErrorValueExceptionIf(() => index < 0 || index >= values.Count(), eErrorType.Num);
-    var result = values.OrderBy(x => x).ElementAt(index);
-    return CreateResult(result, DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Sqrt.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Sqrt.cs
deleted file mode 100644
index 61dff82..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Sqrt.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Sqrt : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var arg = ArgToDecimal(arguments, 0);
-    var result = System.Math.Sqrt(arg);
-    return CreateResult(result, DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/SqrtPi.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/SqrtPi.cs
deleted file mode 100644
index cea3e32..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/SqrtPi.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class SqrtPi : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var number = ArgToDecimal(arguments, 0);
-    return CreateResult(System.Math.Sqrt(number * System.Math.PI), DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Stdev.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Stdev.cs
deleted file mode 100644
index 62831fb..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Stdev.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.Exceptions;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-using MathObj = System.Math;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Stdev : HiddenValuesHandlingFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var values = ArgsToDoubleEnumerable(arguments, context, false);
-    return CreateResult(StandardDeviation(values), DataType.Decimal);
-  }
-
-  private double StandardDeviation(IEnumerable<double> values) {
-    double ret = 0;
-    if (values.Any()) {
-      var nValues = values.Count();
-      if (nValues == 1) {
-        throw new ExcelErrorValueException(eErrorType.Div0);
-      }
-      //Compute the Average
-      double avg = values.Average();
-      //Perform the Sum of (value-avg)_2_2
-      double sum = values.Sum(d => MathObj.Pow(d - avg, 2));
-      //Put it all together
-      ret = MathObj.Sqrt(Divide(sum, (values.Count() - 1)));
-    }
-    return ret;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/StdevP.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/StdevP.cs
deleted file mode 100644
index 16e7b7a..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/StdevP.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-using MathObj = System.Math;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class StdevP : HiddenValuesHandlingFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    var args = ArgsToDoubleEnumerable(IgnoreHiddenValues, false, arguments, context);
-    return CreateResult(StandardDeviation(args), DataType.Decimal);
-  }
-
-  private static double StandardDeviation(IEnumerable<double> values) {
-    double avg = values.Average();
-    return MathObj.Sqrt(values.Average(v => MathObj.Pow(v - avg, 2)));
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Subtotal.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Subtotal.cs
deleted file mode 100644
index 17d8586..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Subtotal.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Subtotal : ExcelFunction {
-  private readonly Dictionary<int, HiddenValuesHandlingFunction> _functions = new();
-
-  public Subtotal() {
-    Initialize();
-  }
-
-  private void Initialize() {
-    _functions[1] = new Average();
-    _functions[2] = new Count();
-    _functions[3] = new CountA();
-    _functions[4] = new Max();
-    _functions[5] = new Min();
-    _functions[6] = new Product();
-    _functions[7] = new Stdev();
-    _functions[8] = new StdevP();
-    _functions[9] = new Sum();
-    _functions[10] = new Var();
-    _functions[11] = new VarP();
-
-    AddHiddenValueHandlingFunction(new Average(), 101);
-    AddHiddenValueHandlingFunction(new Count(), 102);
-    AddHiddenValueHandlingFunction(new CountA(), 103);
-    AddHiddenValueHandlingFunction(new Max(), 104);
-    AddHiddenValueHandlingFunction(new Min(), 105);
-    AddHiddenValueHandlingFunction(new Product(), 106);
-    AddHiddenValueHandlingFunction(new Stdev(), 107);
-    AddHiddenValueHandlingFunction(new StdevP(), 108);
-    AddHiddenValueHandlingFunction(new Sum(), 109);
-    AddHiddenValueHandlingFunction(new Var(), 110);
-    AddHiddenValueHandlingFunction(new VarP(), 111);
-  }
-
-  private void AddHiddenValueHandlingFunction(HiddenValuesHandlingFunction func, int funcNum) {
-    func.IgnoreHiddenValues = true;
-    _functions[funcNum] = func;
-  }
-
-  public override void BeforeInvoke(ParsingContext context) {
-    base.BeforeInvoke(context);
-    context.Scopes.Current.IsSubtotal = true;
-  }
-
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var funcNum = ArgToInt(arguments, 0);
-    if (context.Scopes.Current.Parent != null && context.Scopes.Current.Parent.IsSubtotal) {
-      return CreateResult(0d, DataType.Decimal);
-    }
-    var actualArgs = arguments.Skip(1);
-    var function = GetFunctionByCalcType(funcNum);
-    var compileResult = function.Execute(actualArgs, context);
-    compileResult.IsResultOfSubtotal = true;
-    return compileResult;
-  }
-
-  private ExcelFunction GetFunctionByCalcType(int funcNum) {
-    if (!_functions.ContainsKey(funcNum)) {
-      ThrowExcelErrorValueException(eErrorType.Value);
-      //throw new ArgumentException("Invalid funcNum " + funcNum + ", valid ranges are 1-11 and 101-111");
-    }
-    return _functions[funcNum];
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Sum.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Sum.cs
deleted file mode 100644
index b9b6850..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Sum.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Sum : HiddenValuesHandlingFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    var retVal = 0d;
-    if (arguments != null) {
-      foreach (var arg in arguments) {
-        retVal += Calculate(arg, context);
-      }
-    }
-    return CreateResult(retVal, DataType.Decimal);
-  }
-
-  private double Calculate(FunctionArgument arg, ParsingContext context) {
-    var retVal = 0d;
-    if (ShouldIgnore(arg)) {
-      return retVal;
-    }
-    if (arg.Value is IEnumerable<FunctionArgument> value) {
-      foreach (var item in value) {
-        retVal += Calculate(item, context);
-      }
-    } else if (arg.Value is ExcelDataProvider.IRangeInfo info) {
-      foreach (var c in info) {
-        if (ShouldIgnore(c, context) == false) {
-          CheckForAndHandleExcelError(c);
-          retVal += c.ValueDouble;
-        }
-      }
-    } else {
-      CheckForAndHandleExcelError(arg);
-      retVal += ConvertUtil.GetValueDouble(arg.Value, true);
-    }
-    return retVal;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/SumIf.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/SumIf.cs
deleted file mode 100644
index 8d8d61b..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/SumIf.cs
+++ /dev/null
@@ -1,150 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExcelUtilities;
-using OfficeOpenXml.FormulaParsing.Exceptions;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-using OfficeOpenXml.FormulaParsing.Utilities;
-using Util = OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class SumIf : HiddenValuesHandlingFunction {
-  private readonly NumericExpressionEvaluator _evaluator;
-
-  public SumIf()
-      : this(new()) {}
-
-  public SumIf(NumericExpressionEvaluator evaluator) {
-    Require.That(evaluator).Named("evaluator").IsNotNull();
-    _evaluator = evaluator;
-  }
-
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var args = arguments.ElementAt(0).Value as ExcelDataProvider.IRangeInfo; //IEnumerable<FunctionArgument>;
-    var criteria = arguments.ElementAt(1).Value;
-    ThrowExcelErrorValueExceptionIf(
-        () => criteria == null || criteria.ToString().Length > 255,
-        eErrorType.Value);
-    double retVal;
-    if (arguments.Count() > 2) {
-      var sumRange = arguments.ElementAt(2).Value as ExcelDataProvider.IRangeInfo; //IEnumerable<FunctionArgument>;
-      retVal = CalculateWithSumRange(args, criteria.ToString(), sumRange, context);
-    } else {
-      if (args != null) {
-        retVal = CalculateSingleRange(args, criteria.ToString(), context);
-      } else {
-        retVal = CalculateSingleRange(
-            (arguments.ElementAt(0).Value as IEnumerable<FunctionArgument>),
-            criteria.ToString(),
-            context);
-      }
-    }
-    return CreateResult(retVal, DataType.Decimal);
-  }
-
-  private double CalculateWithSumRange(
-      ExcelDataProvider.IRangeInfo range,
-      string criteria,
-      ExcelDataProvider.IRangeInfo sumRange,
-      ParsingContext context) {
-    var retVal = 0d;
-    foreach (var cell in range) {
-      if (_evaluator.Evaluate(cell.Value, criteria)) {
-        var or = cell.Row - range.Address._fromRow;
-        var oc = cell.Column - range.Address._fromCol;
-        if (sumRange.Address._fromRow + or <= sumRange.Address._toRow
-            && sumRange.Address._fromCol + oc <= sumRange.Address._toCol) {
-          var v = sumRange.GetOffset(or, oc);
-          if (v is ExcelErrorValue value) {
-            throw (new ExcelErrorValueException(value));
-          }
-          retVal += Util.ConvertUtil.GetValueDouble(v, true);
-        }
-      }
-    }
-    return retVal;
-  }
-
-  private double CalculateSingleRange(
-      IEnumerable<FunctionArgument> args,
-      string expression,
-      ParsingContext context) {
-    var retVal = 0d;
-    var flattendedRange = ArgsToDoubleEnumerable(args, context);
-    foreach (var candidate in flattendedRange) {
-      if (_evaluator.Evaluate(candidate, expression)) {
-        retVal += candidate;
-      }
-    }
-    return retVal;
-  }
-
-  private double CalculateSingleRange(
-      ExcelDataProvider.IRangeInfo range,
-      string expression,
-      ParsingContext context) {
-    var retVal = 0d;
-    foreach (var candidate in range) {
-      if (_evaluator.Evaluate(candidate.Value, expression)) {
-        if (candidate.IsExcelError) {
-          throw (new ExcelErrorValueException((ExcelErrorValue)candidate.Value));
-        }
-        retVal += candidate.ValueDouble;
-      }
-    }
-    return retVal;
-  }
-
-  //private double Calculate(FunctionArgument arg, string expression)
-  //{
-  //    var retVal = 0d;
-  //    if (ShouldIgnore(arg) || !_evaluator.Evaluate(arg.Value, expression))
-  //    {
-  //        return retVal;
-  //    }
-  //    if (arg.Value is double || arg.Value is int)
-  //    {
-  //        retVal += Convert.ToDouble(arg.Value);
-  //    }
-  //    else if (arg.Value is System.DateTime)
-  //    {
-  //        retVal += Convert.ToDateTime(arg.Value).ToOADate();
-  //    }
-  //    else if (arg.Value is IEnumerable<FunctionArgument>)
-  //    {
-  //        foreach (var item in (IEnumerable<FunctionArgument>)arg.Value)
-  //        {
-  //            retVal += Calculate(item, expression);
-  //        }
-  //    }
-  //    return retVal;
-  //}
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/SumIfs.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/SumIfs.cs
deleted file mode 100644
index 72ed696..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/SumIfs.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-01-15
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class SumIfs : MultipleRangeCriteriasFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray();
-    ValidateArguments(functionArguments, 3);
-    var sumRange = ArgsToDoubleEnumerable(
-            true,
-            new List<FunctionArgument> { functionArguments[0] },
-            context)
-        .ToList();
-    var argRanges = new List<ExcelDataProvider.IRangeInfo>();
-    var criterias = new List<object>();
-    for (var ix = 1; ix < 31; ix += 2) {
-      if (functionArguments.Length <= ix) {
-        break;
-      }
-      var rangeInfo = functionArguments[ix].ValueAsRangeInfo;
-      argRanges.Add(rangeInfo);
-      if (ix > 1) {
-        ThrowExcelErrorValueExceptionIf(
-            () => rangeInfo.GetNCells() != argRanges[0].GetNCells(),
-            eErrorType.Value);
-      }
-      criterias.Add(functionArguments[ix + 1].Value);
-    }
-    IEnumerable<int> matchIndexes = GetMatchIndexes(argRanges[0], criterias[0]);
-    var enumerable = matchIndexes as IList<int> ?? matchIndexes.ToList();
-    for (var ix = 1; ix < argRanges.Count && enumerable.Any(); ix++) {
-      var indexes = GetMatchIndexes(argRanges[ix], criterias[ix]);
-      matchIndexes = enumerable.Intersect(indexes);
-    }
-
-    var result = matchIndexes.Sum(index => sumRange[index]);
-
-    return CreateResult(result, DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/SumProduct.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/SumProduct.cs
deleted file mode 100644
index 0ee2d19..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/SumProduct.cs
+++ /dev/null
@@ -1,86 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.Exceptions;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class SumProduct : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    double result = 0d;
-    List<List<double>> results = new List<List<double>>();
-    foreach (var arg in arguments) {
-      results.Add(new());
-      var currentResult = results.Last();
-      if (arg.Value is IEnumerable<FunctionArgument> value) {
-        foreach (var val in value) {
-          AddValue(val.Value, currentResult);
-        }
-      } else if (arg.Value is FunctionArgument) {
-        AddValue(arg.Value, currentResult);
-      } else if (arg.IsExcelRange) {
-        var r = arg.ValueAsRangeInfo;
-        for (int col = r.Address._fromCol; col <= r.Address._toCol; col++) {
-          for (int row = r.Address._fromRow; row <= r.Address._toRow; row++) {
-            AddValue(r.GetValue(row, col), currentResult);
-          }
-        }
-      }
-    }
-    // Validate that all supplied lists have the same length
-    var arrayLength = results.First().Count;
-    foreach (var list in results) {
-      if (list.Count != arrayLength) {
-        throw new ExcelErrorValueException(ExcelErrorValue.Create(eErrorType.Value));
-        //throw new ExcelFunctionException("All supplied arrays must have the same length", ExcelErrorCodes.Value);
-      }
-    }
-    for (var rowIndex = 0; rowIndex < arrayLength; rowIndex++) {
-      double rowResult = 1;
-      for (var colIndex = 0; colIndex < results.Count; colIndex++) {
-        rowResult *= results[colIndex][rowIndex];
-      }
-      result += rowResult;
-    }
-    return CreateResult(result, DataType.Decimal);
-  }
-
-  private void AddValue(object convertVal, List<double> currentResult) {
-    if (IsNumeric(convertVal)) {
-      currentResult.Add(Convert.ToDouble(convertVal));
-    } else if (convertVal is ExcelErrorValue val) {
-      throw (new ExcelErrorValueException(val));
-    } else {
-      currentResult.Add(0d);
-    }
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Sumsq.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Sumsq.cs
deleted file mode 100644
index cb18398..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Sumsq.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Sumsq : HiddenValuesHandlingFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    var retVal = 0d;
-    if (arguments != null) {
-      foreach (var arg in arguments) {
-        retVal += Calculate(arg, context);
-      }
-    }
-    return CreateResult(retVal, DataType.Decimal);
-  }
-
-  private double Calculate(FunctionArgument arg, ParsingContext context, bool isInArray = false) {
-    var retVal = 0d;
-    if (ShouldIgnore(arg)) {
-      return retVal;
-    }
-    if (arg.Value is IEnumerable<FunctionArgument> arguments) {
-      foreach (var item in arguments) {
-        retVal += Calculate(item, context, true);
-      }
-    } else {
-      var cs = arg.Value as ExcelDataProvider.IRangeInfo;
-      if (cs != null) {
-        foreach (var c in cs) {
-          if (ShouldIgnore(c, context) == false) {
-            CheckForAndHandleExcelError(c);
-            retVal += System.Math.Pow(c.ValueDouble, 2);
-          }
-        }
-      } else {
-        CheckForAndHandleExcelError(arg);
-        if (IsNumericString(arg.Value) && !isInArray) {
-          var value = ConvertUtil.GetValueDouble(arg.Value);
-          return System.Math.Pow(value, 2);
-        }
-        var ignoreBool = isInArray;
-        retVal += System.Math.Pow(ConvertUtil.GetValueDouble(arg.Value, ignoreBool), 2);
-      }
-    }
-    return retVal;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Tan.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Tan.cs
deleted file mode 100644
index dd85652..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Tan.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Tan : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var arg = ArgToDecimal(arguments, 0);
-    return CreateResult(System.Math.Tan(arg), DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Tanh.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Tanh.cs
deleted file mode 100644
index e2e4f14..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Tanh.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Tanh : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var arg = ArgToDecimal(arguments, 0);
-    return CreateResult(System.Math.Tanh(arg), DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Trunc.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Trunc.cs
deleted file mode 100644
index 3730382..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Trunc.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2014-01-06
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Trunc : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var number = ArgToDecimal(arguments, 0);
-    if (arguments.Count() == 1) {
-      return CreateResult(System.Math.Truncate(number), DataType.Decimal);
-    }
-    var nDigits = ArgToInt(arguments, 1);
-    var func = context.Configuration.FunctionRepository.GetFunction("rounddown");
-    return func.Execute(arguments, context);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Var.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Var.cs
deleted file mode 100644
index b32b165..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Var.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class Var : HiddenValuesHandlingFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var args = ArgsToDoubleEnumerable(IgnoreHiddenValues, false, arguments, context);
-    return new(VarMethods.Var(args), DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/VarMethods.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/VarMethods.cs
deleted file mode 100644
index 6061b74..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/VarMethods.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-04-19
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.Exceptions;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-internal static class VarMethods {
-  private static double Divide(double left, double right) {
-    if (System.Math.Abs(right - 0d) < double.Epsilon) {
-      throw new ExcelErrorValueException(eErrorType.Div0);
-    }
-    return left / right;
-  }
-
-  public static double Var(IEnumerable<double> args) {
-    double avg = args.Average();
-    double d = args.Aggregate(0.0, (total, next) => total + System.Math.Pow(next - avg, 2));
-    return Divide(d, (args.Count() - 1));
-  }
-
-  public static double VarP(IEnumerable<double> args) {
-    double avg = args.Average();
-    double d = args.Aggregate(0.0, (total, next) => total + System.Math.Pow(next - avg, 2));
-    return Divide(d, args.Count());
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/VarP.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/VarP.cs
deleted file mode 100644
index 1afab92..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/VarP.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-public class VarP : HiddenValuesHandlingFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var args = ArgsToDoubleEnumerable(IgnoreHiddenValues, false, arguments, context);
-    return new(VarMethods.VarP(args), DataType.Decimal);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Numeric/CInt.cs b/EPPlus/FormulaParsing/Excel/Functions/Numeric/CInt.cs
deleted file mode 100644
index 0482de8..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Numeric/CInt.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Numeric;
-
-public class CInt : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var num = ArgToDecimal(arguments, 0);
-    return CreateResult((int)System.Math.Floor(num), DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/ObjectEnumerableArgConverter.cs b/EPPlus/FormulaParsing/Excel/Functions/ObjectEnumerableArgConverter.cs
deleted file mode 100644
index 6e56c59..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/ObjectEnumerableArgConverter.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-public class ObjectEnumerableArgConverter : CollectionFlattener<object> {
-  public virtual IEnumerable<object> ConvertArgs(
-      bool ignoreHidden,
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    return base.FuncArgsToFlatEnumerable(
-        arguments,
-        (arg, argList) => {
-          if (arg.Value is ExcelDataProvider.IRangeInfo info) {
-            foreach (var cell in info) {
-              if (!CellStateHelper.ShouldIgnore(ignoreHidden, cell, context)) {
-                argList.Add(cell.Value);
-              }
-            }
-          } else {
-            argList.Add(arg.Value);
-          }
-        });
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Address.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Address.cs
deleted file mode 100644
index b0ce169..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Address.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExcelUtilities;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
-
-public class Address : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var row = ArgToInt(arguments, 0);
-    var col = ArgToInt(arguments, 1);
-    ThrowExcelErrorValueExceptionIf(() => row < 0 && col < 0, eErrorType.Value);
-    var referenceType = ExcelReferenceType.AbsoluteRowAndColumn;
-    var worksheetSpec = string.Empty;
-    if (arguments.Count() > 2) {
-      var arg3 = ArgToInt(arguments, 2);
-      ThrowExcelErrorValueExceptionIf(() => arg3 < 1 || arg3 > 4, eErrorType.Value);
-      referenceType = (ExcelReferenceType)ArgToInt(arguments, 2);
-    }
-    if (arguments.Count() > 3) {
-      var fourthArg = arguments.ElementAt(3).Value;
-      if (fourthArg is bool arg && !arg) {
-        throw new InvalidOperationException("Excelformulaparser does not support the R1C1 format!");
-      }
-    }
-    if (arguments.Count() > 4) {
-      var fifthArg = arguments.ElementAt(4).Value;
-      if (fifthArg is string && !string.IsNullOrEmpty(fifthArg.ToString())) {
-        worksheetSpec = fifthArg + "!";
-      }
-    }
-    var translator = new IndexToAddressTranslator(context.ExcelDataProvider, referenceType);
-    return CreateResult(worksheetSpec + translator.ToAddress(col, row), DataType.ExcelAddress);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/ArrayLookupNavigator.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/ArrayLookupNavigator.cs
deleted file mode 100644
index e558462..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/ArrayLookupNavigator.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.Exceptions;
-using OfficeOpenXml.FormulaParsing.Utilities;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
-
-public class ArrayLookupNavigator : LookupNavigator {
-  private readonly FunctionArgument[] _arrayData;
-  private int _index;
-  private object _currentValue;
-
-  public ArrayLookupNavigator(
-      LookupDirection direction,
-      LookupArguments arguments,
-      ParsingContext parsingContext)
-      : base(direction, arguments, parsingContext) {
-    Require.That(arguments).Named("arguments").IsNotNull();
-    Require.That(arguments.DataArray).Named("arguments.DataArray").IsNotNull();
-    _arrayData = arguments.DataArray.ToArray();
-    Initialize();
-  }
-
-  private void Initialize() {
-    if (Arguments.LookupIndex >= _arrayData.Length) {
-      throw new ExcelErrorValueException(eErrorType.Ref);
-    }
-    SetCurrentValue();
-  }
-
-  public override int Index => _index;
-
-  private void SetCurrentValue() {
-    _currentValue = _arrayData[_index];
-  }
-
-  private bool HasNext() {
-    if (Direction == LookupDirection.Vertical) {
-      return _index < (_arrayData.Length - 1);
-    }
-    return false;
-  }
-
-  public override bool MoveNext() {
-    if (!HasNext()) {
-      return false;
-    }
-    if (Direction == LookupDirection.Vertical) {
-      _index++;
-    }
-    SetCurrentValue();
-    return true;
-  }
-
-  public override object CurrentValue => _arrayData[_index].Value;
-
-  public override object GetLookupValue() {
-    return _arrayData[_index].Value;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Choose.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Choose.cs
deleted file mode 100644
index 599467b..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Choose.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
-
-public class Choose : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var index = ArgToInt(arguments, 0);
-    var items = new List<string>();
-    for (int x = 0; x < arguments.Count(); x++) {
-      items.Add(arguments.ElementAt(x).ValueFirst.ToString());
-    }
-    return CreateResult(items[index], DataType.String);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Column.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Column.cs
deleted file mode 100644
index c2b4366..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Column.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExcelUtilities;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
-
-public class Column : LookupFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    if (arguments == null || arguments.Count() == 0) {
-      return CreateResult(context.Scopes.Current.Address.FromCol, DataType.Integer);
-    }
-    var rangeAddress = ArgToString(arguments, 0);
-    if (!ExcelAddressUtil.IsValidAddress(rangeAddress)) {
-      throw new ArgumentException("An invalid argument was supplied");
-    }
-    var factory = new RangeAddressFactory(context.ExcelDataProvider);
-    var address = factory.Create(rangeAddress);
-    return CreateResult(address.FromCol, DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Columns.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Columns.cs
deleted file mode 100644
index 27864bb..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Columns.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExcelUtilities;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
-
-public class Columns : LookupFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var r = arguments.ElementAt(0).ValueAsRangeInfo;
-    if (r != null) {
-      return CreateResult(r.Address._toCol - r.Address._fromCol + 1, DataType.Integer);
-    }
-    var range = ArgToString(arguments, 0);
-    if (ExcelAddressUtil.IsValidAddress(range)) {
-      var factory = new RangeAddressFactory(context.ExcelDataProvider);
-      var address = factory.Create(range);
-      return CreateResult(address.ToCol - address.FromCol + 1, DataType.Integer);
-    }
-    throw new ArgumentException("Invalid range supplied");
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/ExcelLookupNavigator.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/ExcelLookupNavigator.cs
deleted file mode 100644
index 124fb3e..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/ExcelLookupNavigator.cs
+++ /dev/null
@@ -1,106 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using OfficeOpenXml.FormulaParsing.ExcelUtilities;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
-
-public class ExcelLookupNavigator : LookupNavigator {
-  private int _currentRow;
-  private int _currentCol;
-  private object _currentValue;
-  private RangeAddress _rangeAddress;
-  private int _index;
-
-  public ExcelLookupNavigator(
-      LookupDirection direction,
-      LookupArguments arguments,
-      ParsingContext parsingContext)
-      : base(direction, arguments, parsingContext) {
-    Initialize();
-  }
-
-  private void Initialize() {
-    _index = 0;
-    var factory = new RangeAddressFactory(ParsingContext.ExcelDataProvider);
-    if (Arguments.RangeInfo == null) {
-      _rangeAddress = factory.Create(
-          ParsingContext.Scopes.Current.Address.Worksheet,
-          Arguments.RangeAddress);
-    } else {
-      _rangeAddress = factory.Create(
-          Arguments.RangeInfo.Address.WorkSheet,
-          Arguments.RangeInfo.Address.Address);
-    }
-    _currentCol = _rangeAddress.FromCol;
-    _currentRow = _rangeAddress.FromRow;
-    SetCurrentValue();
-  }
-
-  private void SetCurrentValue() {
-    _currentValue = ParsingContext.ExcelDataProvider.GetCellValue(
-        _rangeAddress.Worksheet,
-        _currentRow,
-        _currentCol);
-  }
-
-  private bool HasNext() {
-    if (Direction == LookupDirection.Vertical) {
-      return _currentRow < _rangeAddress.ToRow;
-    }
-    return _currentCol < _rangeAddress.ToCol;
-  }
-
-  public override int Index => _index;
-
-  public override bool MoveNext() {
-    if (!HasNext()) {
-      return false;
-    }
-    if (Direction == LookupDirection.Vertical) {
-      _currentRow++;
-    } else {
-      _currentCol++;
-    }
-    _index++;
-    SetCurrentValue();
-    return true;
-  }
-
-  public override object CurrentValue => _currentValue;
-
-  public override object GetLookupValue() {
-    var row = _currentRow;
-    var col = _currentCol;
-    if (Direction == LookupDirection.Vertical) {
-      col += Arguments.LookupIndex - 1;
-      row += Arguments.LookupOffset;
-    } else {
-      row += Arguments.LookupIndex - 1;
-      col += Arguments.LookupOffset;
-    }
-    return ParsingContext.ExcelDataProvider.GetCellValue(_rangeAddress.Worksheet, row, col);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/HLookup.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/HLookup.cs
deleted file mode 100644
index a2ec6a3..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/HLookup.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
-
-public class HLookup : LookupFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 3);
-    var lookupArgs = new LookupArguments(arguments);
-    ThrowExcelErrorValueExceptionIf(() => lookupArgs.LookupIndex < 1, eErrorType.Value);
-    var navigator = LookupNavigatorFactory.Create(LookupDirection.Horizontal, lookupArgs, context);
-    return Lookup(navigator, lookupArgs);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Index.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Index.cs
deleted file mode 100644
index 7c8431d..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Index.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.Exceptions;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
-
-public class Index : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var arg1 = arguments.ElementAt(0);
-    var args = arg1.Value as IEnumerable<FunctionArgument>;
-    var crf = new CompileResultFactory();
-    if (args != null) {
-      var index = ArgToInt(arguments, 1);
-      if (index > args.Count()) {
-        throw new ExcelErrorValueException(eErrorType.Ref);
-      }
-      var candidate = args.ElementAt(index - 1);
-      //Commented JK-Can be any data type
-      //if (!IsNumber(candidate.Value))
-      //{
-      //    throw new ExcelErrorValueException(eErrorType.Value);
-      //}
-      //return CreateResult(ConvertUtil.GetValueDouble(candidate.Value), DataType.Decimal);
-      return crf.Create(candidate.Value);
-    }
-    if (arg1.IsExcelRange) {
-      var row = ArgToInt(arguments, 1);
-      var col = arguments.Count() > 2 ? ArgToInt(arguments, 2) : 1;
-      var ri = arg1.ValueAsRangeInfo;
-      if (row > ri.Address._toRow - ri.Address._fromRow + 1
-          || col > ri.Address._toCol - ri.Address._fromCol + 1) {
-        ThrowExcelErrorValueException(eErrorType.Ref);
-      }
-      var candidate = ri.GetOffset(row - 1, col - 1);
-      //Commented JK-Can be any data type
-      //if (!IsNumber(candidate.Value))
-      //{
-      //    throw new ExcelErrorValueException(eErrorType.Value);
-      //}
-      return crf.Create(candidate);
-    }
-    throw new NotImplementedException();
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Indirect.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Indirect.cs
deleted file mode 100644
index ae80178..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Indirect.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2014-04-13
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
-
-public class Indirect : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var address = ArgToString(arguments, 0);
-    var adr = new ExcelAddress(address);
-    var ws = adr.WorkSheet;
-    if (string.IsNullOrEmpty(ws)) {
-      ws = context.Scopes.Current.Address.Worksheet;
-    }
-    var result = context.ExcelDataProvider.GetRange(ws, adr._fromRow, adr._fromCol, address);
-    if (result.IsEmpty) {
-      // Bug 15290
-      var namedValueExpr = new NamedValueExpression(address, context);
-      return namedValueExpr.Compile();
-    }
-    return new(result, DataType.Enumerable);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Lookup.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Lookup.cs
deleted file mode 100644
index 8fee752..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Lookup.cs
+++ /dev/null
@@ -1,100 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExcelUtilities;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-using OfficeOpenXml.FormulaParsing.Utilities;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
-
-public class Lookup : LookupFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    if (HaveTwoRanges(arguments)) {
-      return HandleTwoRanges(arguments, context);
-    }
-    return HandleSingleRange(arguments, context);
-  }
-
-  private bool HaveTwoRanges(IEnumerable<FunctionArgument> arguments) {
-    if (arguments.Count() == 2) {
-      return false;
-    }
-    return (ExcelAddressUtil.IsValidAddress(arguments.ElementAt(2).Value.ToString()));
-  }
-
-  private CompileResult HandleSingleRange(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    var searchedValue = arguments.ElementAt(0).Value;
-    Require.That(arguments.ElementAt(1).Value).Named("firstAddress").IsNotNull();
-    var firstAddress = ArgToString(arguments, 1);
-    var rangeAddressFactory = new RangeAddressFactory(context.ExcelDataProvider);
-    var address = rangeAddressFactory.Create(firstAddress);
-    var nRows = address.ToRow - address.FromRow;
-    var nCols = address.ToCol - address.FromCol;
-    var lookupIndex = nCols + 1;
-    var lookupDirection = LookupDirection.Vertical;
-    if (nCols > nRows) {
-      lookupIndex = nRows + 1;
-      lookupDirection = LookupDirection.Horizontal;
-    }
-    var lookupArgs = new LookupArguments(searchedValue, firstAddress, lookupIndex, 0, true);
-    var navigator = LookupNavigatorFactory.Create(lookupDirection, lookupArgs, context);
-    return Lookup(navigator, lookupArgs);
-  }
-
-  private CompileResult HandleTwoRanges(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    var searchedValue = arguments.ElementAt(0).Value;
-    Require.That(arguments.ElementAt(1).Value).Named("firstAddress").IsNotNull();
-    Require.That(arguments.ElementAt(2).Value).Named("secondAddress").IsNotNull();
-    var firstAddress = ArgToString(arguments, 1);
-    var secondAddress = ArgToString(arguments, 2);
-    var rangeAddressFactory = new RangeAddressFactory(context.ExcelDataProvider);
-    var address1 = rangeAddressFactory.Create(firstAddress);
-    var address2 = rangeAddressFactory.Create(secondAddress);
-    var lookupIndex = (address2.FromCol - address1.FromCol) + 1;
-    var lookupOffset = address2.FromRow - address1.FromRow;
-    var lookupDirection = GetLookupDirection(address1);
-    if (lookupDirection == LookupDirection.Horizontal) {
-      lookupIndex = (address2.FromRow - address1.FromRow) + 1;
-      lookupOffset = address2.FromCol - address1.FromCol;
-    }
-    var lookupArgs = new LookupArguments(
-        searchedValue,
-        firstAddress,
-        lookupIndex,
-        lookupOffset,
-        true);
-    var navigator = LookupNavigatorFactory.Create(lookupDirection, lookupArgs, context);
-    return Lookup(navigator, lookupArgs);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupArguments.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupArguments.cs
deleted file mode 100644
index 8bed82d..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupArguments.cs
+++ /dev/null
@@ -1,103 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
-
-public class LookupArguments {
-  public enum LookupArgumentDataType {
-    ExcelRange,
-    DataArray,
-  }
-
-  public LookupArguments(IEnumerable<FunctionArgument> arguments)
-      : this(arguments, new()) {}
-
-  public LookupArguments(IEnumerable<FunctionArgument> arguments, ArgumentParsers argumentParsers) {
-    _argumentParsers = argumentParsers;
-    SearchedValue = arguments.ElementAt(0).Value;
-    var arg1 = arguments.ElementAt(1).Value;
-    var dataArray = arg1 as IEnumerable<FunctionArgument>;
-    if (dataArray != null) {
-      DataArray = dataArray;
-      ArgumentDataType = LookupArgumentDataType.DataArray;
-    } else {
-      //if (arg1 is ExcelDataProvider.INameInfo) arg1 = ((ExcelDataProvider.INameInfo) arg1).Value;
-      var rangeInfo = arg1 as ExcelDataProvider.IRangeInfo;
-      if (rangeInfo != null) {
-        RangeAddress = string.IsNullOrEmpty(rangeInfo.Address.WorkSheet)
-            ? rangeInfo.Address.Address
-            : "'" + rangeInfo.Address.WorkSheet + "'!" + rangeInfo.Address.Address;
-        RangeInfo = rangeInfo;
-        ArgumentDataType = LookupArgumentDataType.ExcelRange;
-      } else {
-        RangeAddress = arg1.ToString();
-        ArgumentDataType = LookupArgumentDataType.ExcelRange;
-      }
-    }
-    LookupIndex = (int)
-      _argumentParsers.GetParser(DataType.Integer).Parse(arguments.ElementAt(2).Value);
-    if (arguments.Count() > 3) {
-      RangeLookup = (bool)
-        _argumentParsers.GetParser(DataType.Boolean).Parse(arguments.ElementAt(3).Value);
-    } else {
-      RangeLookup = true;
-    }
-  }
-
-  public LookupArguments(
-      object searchedValue,
-      string rangeAddress,
-      int lookupIndex,
-      int lookupOffset,
-      bool rangeLookup) {
-    SearchedValue = searchedValue;
-    RangeAddress = rangeAddress;
-    LookupIndex = lookupIndex;
-    LookupOffset = lookupOffset;
-    RangeLookup = rangeLookup;
-  }
-
-  private readonly ArgumentParsers _argumentParsers;
-
-  public object SearchedValue { get; private set; }
-
-  public string RangeAddress { get; private set; }
-
-  public int LookupIndex { get; private set; }
-
-  public int LookupOffset { get; private set; }
-
-  public bool RangeLookup { get; private set; }
-
-  public IEnumerable<FunctionArgument> DataArray { get; private set; }
-
-  public ExcelDataProvider.IRangeInfo RangeInfo { get; private set; }
-
-  public LookupArgumentDataType ArgumentDataType { get; private set; }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupDirection.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupDirection.cs
deleted file mode 100644
index abb564c..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupDirection.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
-
-public enum LookupDirection {
-  Vertical,
-  Horizontal,
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupFunction.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupFunction.cs
deleted file mode 100644
index 84f20d8..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupFunction.cs
+++ /dev/null
@@ -1,90 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using OfficeOpenXml.FormulaParsing.ExcelUtilities;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
-
-public abstract class LookupFunction : ExcelFunction {
-  private readonly ValueMatcher _valueMatcher;
-  private readonly CompileResultFactory _compileResultFactory;
-
-  public LookupFunction()
-      : this(new LookupValueMatcher(), new()) {}
-
-  public LookupFunction(ValueMatcher valueMatcher, CompileResultFactory compileResultFactory) {
-    _valueMatcher = valueMatcher;
-    _compileResultFactory = compileResultFactory;
-  }
-
-  public override bool IsLookupFuction => true;
-
-  protected int IsMatch(object o1, object o2) {
-    return _valueMatcher.IsMatch(o1, o2);
-  }
-
-  protected LookupDirection GetLookupDirection(RangeAddress rangeAddress) {
-    var nRows = rangeAddress.ToRow - rangeAddress.FromRow;
-    var nCols = rangeAddress.ToCol - rangeAddress.FromCol;
-    return nCols > nRows ? LookupDirection.Horizontal : LookupDirection.Vertical;
-  }
-
-  protected CompileResult Lookup(LookupNavigator navigator, LookupArguments lookupArgs) {
-    object lastValue = null;
-    object lastLookupValue = null;
-    int? lastMatchResult = null;
-    if (lookupArgs.SearchedValue == null) {
-      return new(ExcelErrorValue.Create(eErrorType.Na), DataType.ExcelError);
-    }
-    do {
-      var matchResult = IsMatch(navigator.CurrentValue, lookupArgs.SearchedValue);
-      if (matchResult != 0) {
-        if (lastValue != null && navigator.CurrentValue == null) {
-          break;
-        }
-
-        if (lookupArgs.RangeLookup) {
-          if (lastValue == null && matchResult > 0) {
-            ThrowExcelErrorValueException(eErrorType.Na);
-          }
-          if (lastValue != null && matchResult > 0 && lastMatchResult < 0) {
-            return _compileResultFactory.Create(lastLookupValue);
-          }
-          lastMatchResult = matchResult;
-          lastValue = navigator.CurrentValue;
-          lastLookupValue = navigator.GetLookupValue();
-        }
-      } else {
-        return _compileResultFactory.Create(navigator.GetLookupValue());
-      }
-    } while (navigator.MoveNext());
-
-    if (lookupArgs.RangeLookup) {
-      return _compileResultFactory.Create(lastLookupValue);
-    }
-    return new(ExcelErrorValue.Create(eErrorType.Na), DataType.ExcelError);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupNavigator.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupNavigator.cs
deleted file mode 100644
index f93cfbe..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupNavigator.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using OfficeOpenXml.FormulaParsing.Utilities;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
-
-public abstract class LookupNavigator {
-  protected readonly LookupDirection Direction;
-  protected readonly LookupArguments Arguments;
-  protected readonly ParsingContext ParsingContext;
-
-  public LookupNavigator(
-      LookupDirection direction,
-      LookupArguments arguments,
-      ParsingContext parsingContext) {
-    Require.That(arguments).Named("arguments").IsNotNull();
-    Require.That(parsingContext).Named("parsingContext").IsNotNull();
-    Require
-        .That(parsingContext.ExcelDataProvider)
-        .Named("parsingContext.ExcelDataProvider")
-        .IsNotNull();
-    Direction = direction;
-    Arguments = arguments;
-    ParsingContext = parsingContext;
-  }
-
-  public abstract int Index { get; }
-
-  public abstract bool MoveNext();
-
-  public abstract object CurrentValue { get; }
-
-  public abstract object GetLookupValue();
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupNavigatorFactory.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupNavigatorFactory.cs
deleted file mode 100644
index d444525..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupNavigatorFactory.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using System;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
-
-public static class LookupNavigatorFactory {
-  public static LookupNavigator Create(
-      LookupDirection direction,
-      LookupArguments args,
-      ParsingContext parsingContext) {
-    if (args.ArgumentDataType == LookupArguments.LookupArgumentDataType.ExcelRange) {
-      return new ExcelLookupNavigator(direction, args, parsingContext);
-    }
-    if (args.ArgumentDataType == LookupArguments.LookupArgumentDataType.DataArray) {
-      return new ArrayLookupNavigator(direction, args, parsingContext);
-    }
-    throw new NotSupportedException("Invalid argument datatype");
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Match.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Match.cs
deleted file mode 100644
index 36f24fc..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Match.cs
+++ /dev/null
@@ -1,90 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExcelUtilities;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
-
-public class Match : LookupFunction {
-  private enum MatchType {
-    ClosestAbove = -1,
-    ExactMatch = 0,
-    ClosestBelow = 1,
-  }
-
-  public Match()
-      : base(new WildCardValueMatcher(), new()) {}
-
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-
-    var searchedValue = arguments.ElementAt(0).Value;
-    var address = ArgToString(arguments, 1);
-    var rangeAddressFactory = new RangeAddressFactory(context.ExcelDataProvider);
-    var rangeAddress = rangeAddressFactory.Create(address);
-    var matchType = GetMatchType(arguments);
-    var args = new LookupArguments(searchedValue, address, 0, 0, false);
-    var lookupDirection = GetLookupDirection(rangeAddress);
-    var navigator = LookupNavigatorFactory.Create(lookupDirection, args, context);
-    int? lastMatchResult = default(int?);
-    do {
-      var matchResult = IsMatch(navigator.CurrentValue, searchedValue);
-      if (matchType == MatchType.ClosestBelow && matchResult >= 0) {
-        if (!lastMatchResult.HasValue && matchResult > 0) {
-          // TODO: error handling. This happens only if the first item is
-          // below the searched value.
-        }
-        var index = matchResult == 0 ? navigator.Index + 1 : navigator.Index;
-        return CreateResult(index, DataType.Integer);
-      }
-      if (matchType == MatchType.ClosestAbove && matchResult <= 0) {
-        if (!lastMatchResult.HasValue && matchResult < 0) {
-          // TODO: error handling. This happens only if the first item is
-          // above the searched value
-        }
-        var index = matchResult == 0 ? navigator.Index + 1 : navigator.Index;
-        return CreateResult(index, DataType.Integer);
-      }
-      if (matchType == MatchType.ExactMatch && matchResult == 0) {
-        return CreateResult(navigator.Index + 1, DataType.Integer);
-      }
-      lastMatchResult = matchResult;
-    } while (navigator.MoveNext());
-    return CreateResult(null, DataType.Integer);
-  }
-
-  private MatchType GetMatchType(IEnumerable<FunctionArgument> arguments) {
-    var matchType = MatchType.ClosestBelow;
-    if (arguments.Count() > 2) {
-      matchType = (MatchType)ArgToInt(arguments, 2);
-    }
-    return matchType;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Offset.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Offset.cs
deleted file mode 100644
index 8a16080..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Offset.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-01-11
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
-
-public class Offset : LookupFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray();
-    ValidateArguments(functionArguments, 3);
-    var startRange = ArgToString(functionArguments, 0);
-    var rowOffset = ArgToInt(functionArguments, 1);
-    var colOffset = ArgToInt(functionArguments, 2);
-    int width = 0,
-        height = 0;
-    if (functionArguments.Length > 3) {
-      height = ArgToInt(functionArguments, 3);
-      ThrowExcelErrorValueExceptionIf(() => height == 0, eErrorType.Ref);
-    }
-    if (functionArguments.Length > 4) {
-      width = ArgToInt(functionArguments, 4);
-      ThrowExcelErrorValueExceptionIf(() => width == 0, eErrorType.Ref);
-    }
-
-    var adr = new ExcelAddress(startRange);
-    var ws = adr.WorkSheet;
-
-    var fromRow = adr._fromRow + rowOffset;
-    var fromCol = adr._fromCol + colOffset;
-    var toRow = (height != 0 ? height : adr._toRow) + rowOffset;
-    var toCol = (width != 0 ? width : adr._toCol) + colOffset;
-
-    var newRange = context.ExcelDataProvider.GetRange(ws, fromRow, fromCol, toRow, toCol);
-    if (!newRange.IsMulti) {
-      if (newRange.IsEmpty) {
-        return CompileResult.Empty;
-      }
-      var val = newRange.GetValue(fromRow, fromCol);
-      if (IsNumeric(val)) {
-        return CreateResult(val, DataType.Decimal);
-      }
-      if (val is ExcelErrorValue) {
-        return CreateResult(val, DataType.ExcelError);
-      }
-      return CreateResult(val, DataType.String);
-    }
-    return CreateResult(newRange, DataType.Enumerable);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Row.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Row.cs
deleted file mode 100644
index 5b20a5b..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Row.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExcelUtilities;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
-
-public class Row : LookupFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    if (arguments == null || arguments.Count() == 0) {
-      return CreateResult(context.Scopes.Current.Address.FromRow, DataType.Integer);
-    }
-    var rangeAddress = ArgToString(arguments, 0);
-    if (!ExcelAddressUtil.IsValidAddress(rangeAddress)) {
-      throw new ArgumentException("An invalid argument was supplied");
-    }
-    var factory = new RangeAddressFactory(context.ExcelDataProvider);
-    var address = factory.Create(rangeAddress);
-    return CreateResult(address.FromRow, DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Rows.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Rows.cs
deleted file mode 100644
index 94f5203..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Rows.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExcelUtilities;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
-
-public class Rows : LookupFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var r = arguments.ElementAt(0).ValueAsRangeInfo;
-    if (r != null) {
-      return CreateResult(r.Address._toRow - r.Address._fromRow + 1, DataType.Integer);
-    }
-    var range = ArgToString(arguments, 0);
-    if (ExcelAddressUtil.IsValidAddress(range)) {
-      var factory = new RangeAddressFactory(context.ExcelDataProvider);
-      var address = factory.Create(range);
-      return CreateResult(address.ToRow - address.FromRow + 1, DataType.Integer);
-    }
-    throw new ArgumentException("Invalid range supplied");
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/VLookup.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/VLookup.cs
deleted file mode 100644
index 559715a..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/VLookup.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Diagnostics;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
-
-public class VLookup : LookupFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    Stopwatch sw = null;
-    if (context.Debug) {
-      sw = new();
-      sw.Start();
-    }
-    ValidateArguments(arguments, 3);
-    var lookupArgs = new LookupArguments(arguments);
-    var navigator = LookupNavigatorFactory.Create(LookupDirection.Vertical, lookupArgs, context);
-    var result = Lookup(navigator, lookupArgs);
-    if (context.Debug) {
-      sw.Stop();
-      context.Configuration.Logger.LogFunction("VLOOKUP", sw.ElapsedMilliseconds);
-    }
-    return result;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/CStr.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/CStr.cs
deleted file mode 100644
index 2350c6c..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Text/CStr.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
-
-public class CStr : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    return CreateResult(ArgToString(arguments, 0), DataType.String);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/CharFunction.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/CharFunction.cs
deleted file mode 100644
index 231479a..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Text/CharFunction.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
-
-public class CharFunction : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var number = ArgToInt(arguments, 0);
-    ThrowExcelErrorValueExceptionIf(() => number < 1 || number > 255, eErrorType.Value);
-    return CreateResult(((char)number).ToString(), DataType.String);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Concatenate.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Concatenate.cs
deleted file mode 100644
index 9a22422..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Text/Concatenate.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Text;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
-
-public class Concatenate : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    if (arguments == null) {
-      return CreateResult(string.Empty, DataType.String);
-    }
-    var sb = new StringBuilder();
-    foreach (var arg in arguments) {
-      var v = arg.ValueFirst;
-      if (v != null) {
-        sb.Append(v);
-      }
-    }
-    return CreateResult(sb.ToString(), DataType.String);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Exact.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Exact.cs
deleted file mode 100644
index 41d6a3e..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Text/Exact.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
-
-public class Exact : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var val1 = arguments.ElementAt(0).ValueFirst;
-    var val2 = arguments.ElementAt(1).ValueFirst;
-
-    if (val1 == null && val2 == null) {
-      return CreateResult(true, DataType.Boolean);
-    }
-    if ((val1 == null && val2 != null) || (val1 != null && val2 == null)) {
-      return CreateResult(false, DataType.Boolean);
-    }
-
-    var result = string.Compare(
-        val1.ToString(),
-        val2.ToString(),
-        StringComparison.InvariantCulture);
-    return CreateResult(result == 0, DataType.Boolean);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Find.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Find.cs
deleted file mode 100644
index 1a8c255..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Text/Find.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.Exceptions;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
-
-public class Find : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray();
-    ValidateArguments(functionArguments, 2);
-    var search = ArgToString(functionArguments, 0);
-    var searchIn = ArgToString(functionArguments, 1);
-    var startIndex = 0;
-    if (functionArguments.Count() > 2) {
-      startIndex = ArgToInt(functionArguments, 2);
-    }
-    var result = searchIn.IndexOf(search, startIndex, StringComparison.Ordinal);
-    if (result == -1) {
-      throw new ExcelErrorValueException(ExcelErrorValue.Create(eErrorType.Value));
-    }
-    // Adding 1 because Excel uses 1-based index
-    return CreateResult(result + 1, DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Fixed.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Fixed.cs
deleted file mode 100644
index 4eab700..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Text/Fixed.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
-
-public class Fixed : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var number = ArgToDecimal(arguments, 0);
-    var nDecimals = 2;
-    var noCommas = false;
-    if (arguments.Count() > 1) {
-      nDecimals = ArgToInt(arguments, 1);
-    }
-    if (arguments.Count() > 2) {
-      noCommas = ArgToBool(arguments, 2);
-    }
-    var format = (noCommas ? "F" : "N") + nDecimals.ToString(CultureInfo.InvariantCulture);
-    if (nDecimals < 0) {
-      number = number - (number % (System.Math.Pow(10, nDecimals * -1)));
-      number = System.Math.Floor(number);
-      format = noCommas ? "F0" : "N0";
-    }
-    var retVal = number.ToString(format);
-    return CreateResult(retVal, DataType.String);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Hyperlink.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Hyperlink.cs
deleted file mode 100644
index 1635f43..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Text/Hyperlink.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-01-10
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
-
-public class Hyperlink : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    if (arguments.Count() > 1) {
-      return CreateResult(ArgToString(arguments, 1), DataType.String);
-    }
-    return CreateResult(ArgToString(arguments, 0), DataType.String);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Left.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Left.cs
deleted file mode 100644
index bdbbc74..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Text/Left.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
-
-public class Left : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var str = ArgToString(arguments, 0);
-    var length = ArgToInt(arguments, 1);
-    return CreateResult(str.Substring(0, length), DataType.String);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Len.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Len.cs
deleted file mode 100644
index d5ce785..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Text/Len.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
-
-public class Len : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var length = arguments.First().ValueFirst.ToString().Length;
-    return CreateResult(Convert.ToDouble(length), DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Lower.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Lower.cs
deleted file mode 100644
index b9e51e2..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Text/Lower.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
-
-public class Lower : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    return CreateResult(arguments.First().ValueFirst.ToString().ToLower(), DataType.String);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Mid.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Mid.cs
deleted file mode 100644
index 8bbd0e6..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Text/Mid.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
-
-public class Mid : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 3);
-    var text = ArgToString(arguments, 0);
-    var startIx = ArgToInt(arguments, 1);
-    var length = ArgToInt(arguments, 2);
-    if (startIx <= 0) {
-      throw (new ArgumentException("Argument start can't be less than 1"));
-    }
-    //Allow overflowing start and length
-    if (startIx > text.Length) {
-      return CreateResult("", DataType.String);
-    }
-    var result = text.Substring(
-        startIx - 1,
-        startIx - 1 + length < text.Length ? length : text.Length - startIx + 1);
-    return CreateResult(result, DataType.String);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Proper.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Proper.cs
deleted file mode 100644
index a336746..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Text/Proper.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Globalization;
-using System.Text;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
-
-public class Proper : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var text = ArgToString(arguments, 0).ToLower(CultureInfo.InvariantCulture);
-    var sb = new StringBuilder();
-    var previousChar = '.';
-    foreach (var ch in text) {
-      if (!char.IsLetter(previousChar)) {
-        sb.Append(ch.ToString(CultureInfo.InvariantCulture).ToUpperInvariant());
-      } else {
-        sb.Append(ch);
-      }
-      previousChar = ch;
-    }
-    return CreateResult(sb.ToString(), DataType.String);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Replace.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Replace.cs
deleted file mode 100644
index 37ccc2c..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Text/Replace.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
-
-public class Replace : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 4);
-    var oldText = ArgToString(arguments, 0);
-    var startPos = ArgToInt(arguments, 1);
-    var nCharsToReplace = ArgToInt(arguments, 2);
-    var newText = ArgToString(arguments, 3);
-    var firstPart = GetFirstPart(oldText, startPos);
-    var lastPart = GetLastPart(oldText, startPos, nCharsToReplace);
-    var result = string.Concat(firstPart, newText, lastPart);
-    return CreateResult(result, DataType.String);
-  }
-
-  private string GetFirstPart(string text, int startPos) {
-    return text.Substring(0, startPos - 1);
-  }
-
-  private string GetLastPart(string text, int startPos, int nCharactersToReplace) {
-    int startIx = startPos - 1;
-    startIx += nCharactersToReplace;
-    return text.Substring(startIx, text.Length - startIx);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Rept.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Rept.cs
deleted file mode 100644
index 1f7cc5c..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Text/Rept.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2015-01-10
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Text;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
-
-public class Rept : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var str = ArgToString(arguments, 0);
-    var n = ArgToInt(arguments, 1);
-    var sb = new StringBuilder();
-    for (var x = 0; x < n; x++) {
-      sb.Append(str);
-    }
-    return CreateResult(sb.ToString(), DataType.String);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Right.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Right.cs
deleted file mode 100644
index f78efd9..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Text/Right.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
-
-public class Right : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var str = ArgToString(arguments, 0);
-    var length = ArgToInt(arguments, 1);
-    var startIx = str.Length - length;
-    return CreateResult(str.Substring(startIx, str.Length - startIx), DataType.String);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Search.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Search.cs
deleted file mode 100644
index a6d38ba..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Text/Search.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2016-03-28
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
-
-public class Search : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray();
-    ValidateArguments(functionArguments, 2);
-    var search = ArgToString(functionArguments, 0);
-    var searchIn = ArgToString(functionArguments, 1);
-    var startIndex = 0;
-    if (functionArguments.Count() > 2) {
-      startIndex = ArgToInt(functionArguments, 2);
-    }
-    var result = searchIn.IndexOf(search, startIndex, StringComparison.OrdinalIgnoreCase);
-    if (result == -1) {
-      return CreateResult(ExcelErrorValue.Create(eErrorType.Value), DataType.ExcelError);
-    }
-    // Adding 1 because Excel uses 1-based index
-    return CreateResult(result + 1, DataType.Integer);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Substitute.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Substitute.cs
deleted file mode 100644
index 22d887e..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Text/Substitute.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
-
-public class Substitute : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 3);
-    var text = ArgToString(arguments, 0);
-    var find = ArgToString(arguments, 1);
-    var replaceWith = ArgToString(arguments, 2);
-    var result = text.Replace(find, replaceWith);
-    return CreateResult(result, DataType.String);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/T.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/T.cs
deleted file mode 100644
index 646b90b..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Text/T.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
-
-public class T : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var val = arguments.ElementAt(0).ValueFirst;
-    if (val is string) {
-      return CreateResult(val, DataType.String);
-    }
-    return CreateResult(string.Empty, DataType.String);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Text.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Text.cs
deleted file mode 100644
index 00ae7fc..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Text/Text.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Jan Källman   		            Added		                2014-01-17
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
-
-public class Text : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 2);
-    var value = arguments.First().ValueFirst;
-    var format = ArgToString(arguments, 1);
-    format = format.Replace(CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator, ".");
-    format = format.Replace(
-        CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator.Replace((char)160, ' '),
-        ","); //Special handling for No-Break Space
-
-    var result = context.ExcelDataProvider.GetFormat(value, format);
-
-    return CreateResult(result, DataType.String);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Upper.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Upper.cs
deleted file mode 100644
index c40e6f4..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Text/Upper.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Mats Alm   		                Added		                2013-12-03
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
-
-public class Upper : ExcelFunction {
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    return CreateResult(arguments.First().ValueFirst.ToString().ToUpper(), DataType.String);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Value.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Value.cs
deleted file mode 100644
index e5ee106..0000000
--- a/EPPlus/FormulaParsing/Excel/Functions/Text/Value.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-using System.Collections.Generic;
-using System.Globalization;
-using System.Text.RegularExpressions;
-using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
-
-public class Value : ExcelFunction {
-  private readonly string _groupSeparator = CultureInfo
-      .CurrentCulture
-      .NumberFormat
-      .NumberGroupSeparator;
-  private readonly string _decimalSeparator = CultureInfo
-      .CurrentCulture
-      .NumberFormat
-      .NumberDecimalSeparator;
-  private readonly string _timeSeparator = CultureInfo.CurrentCulture.DateTimeFormat.TimeSeparator;
-  private readonly DateValue _dateValueFunc = new();
-  private readonly TimeValue _timeValueFunc = new();
-
-  public override CompileResult Execute(
-      IEnumerable<FunctionArgument> arguments,
-      ParsingContext context) {
-    ValidateArguments(arguments, 1);
-    var val = ArgToString(arguments, 0).TrimEnd(' ');
-    double result;
-    if (Regex.IsMatch(
-        val,
-        $"^[\\d]*({Regex.Escape(_groupSeparator)}?[\\d]*)?({Regex.Escape(_decimalSeparator)
-        }[\\d]*)?[ ?% ?]?$")) {
-      if (val.EndsWith("%")) {
-        val = val.TrimEnd('%');
-        result = double.Parse(val) / 100;
-      } else {
-        result = double.Parse(val);
-      }
-      return CreateResult(result, DataType.Decimal);
-    }
-    if (double.TryParse(val, NumberStyles.Float, CultureInfo.CurrentCulture, out result)) {
-      return CreateResult(result, DataType.Decimal);
-    }
-    var timeSeparator = Regex.Escape(_timeSeparator);
-    if (Regex.IsMatch(
-        val,
-        @"^[\d]{1,2}" + timeSeparator + @"[\d]{2}(" + timeSeparator + @"[\d]{2})?$")) {
-      var timeResult = _timeValueFunc.Execute(val);
-      if (timeResult.DataType == DataType.Date) {
-        return timeResult;
-      }
-    }
-    var dateResult = _dateValueFunc.Execute(val);
-    if (dateResult.DataType == DataType.Date) {
-      return dateResult;
-    }
-    return CreateResult(ExcelErrorValue.Create(eErrorType.Value), DataType.ExcelError);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Operators/IOperator.cs b/EPPlus/FormulaParsing/Excel/Operators/IOperator.cs
deleted file mode 100644
index 7975cc1..0000000
--- a/EPPlus/FormulaParsing/Excel/Operators/IOperator.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Operators;
-
-public interface IOperator {
-  Operators Operator { get; }
-
-  CompileResult Apply(CompileResult left, CompileResult right);
-
-  int Precedence { get; }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Operators/Operator.cs b/EPPlus/FormulaParsing/Excel/Operators/Operator.cs
deleted file mode 100644
index e6d25e2..0000000
--- a/EPPlus/FormulaParsing/Excel/Operators/Operator.cs
+++ /dev/null
@@ -1,390 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Operators;
-
-public class Operator : IOperator {
-  private const int _precedencePercent = 2;
-  private const int _precedenceExp = 4;
-  private const int _precedenceMultiplyDevide = 6;
-  private const int _precedenceAddSubtract = 12;
-  private const int _precedenceConcat = 15;
-  private const int _precedenceComparison = 25;
-
-  private Operator(
-      Operators @operator,
-      int precedence,
-      Func<CompileResult, CompileResult, CompileResult> implementation) {
-    _implementation = implementation;
-    _precedence = precedence;
-    _operator = @operator;
-  }
-
-  private readonly Func<CompileResult, CompileResult, CompileResult> _implementation;
-  private readonly int _precedence;
-  private readonly Operators _operator;
-
-  int IOperator.Precedence => _precedence;
-
-  Operators IOperator.Operator => _operator;
-
-  public CompileResult Apply(CompileResult left, CompileResult right) {
-    if (left.Result is ExcelErrorValue) {
-      return new(left.Result, DataType.ExcelError);
-      //throw(new ExcelErrorValueException((ExcelErrorValue)left.Result));
-    }
-    if (right.Result is ExcelErrorValue) {
-      return new(right.Result, DataType.ExcelError);
-      //throw(new ExcelErrorValueException((ExcelErrorValue)right.Result));
-    }
-    return _implementation(left, right);
-  }
-
-  public override string ToString() {
-    return "Operator: " + _operator;
-  }
-
-  private static IOperator _plus;
-
-  public static IOperator Plus {
-    get {
-      return _plus
-          ?? (_plus = new Operator(
-                  Operators.Plus,
-                  _precedenceAddSubtract,
-                  (l, r) => {
-                    l = l == null || l.Result == null ? new(0, DataType.Integer) : l;
-                    r = r == null || r.Result == null ? new(0, DataType.Integer) : r;
-                    if (EitherIsError(l, r, out var errorVal)) {
-                      return new(errorVal);
-                    }
-                    if (l.DataType == DataType.Integer && r.DataType == DataType.Integer) {
-                      return new(l.ResultNumeric + r.ResultNumeric, DataType.Integer);
-                    }
-                    if ((l.IsNumeric
-                                || l.IsNumericString
-                                || l.Result is ExcelDataProvider.IRangeInfo)
-                        && (r.IsNumeric
-                                || r.IsNumericString
-                                || r.Result is ExcelDataProvider.IRangeInfo)) {
-                      return new(l.ResultNumeric + r.ResultNumeric, DataType.Decimal);
-                    }
-                    return new(eErrorType.Value);
-                  }));
-    }
-  }
-
-  private static IOperator _minus;
-
-  public static IOperator Minus {
-    get {
-      return _minus
-          ?? (_minus = new Operator(
-                  Operators.Minus,
-                  _precedenceAddSubtract,
-                  (l, r) => {
-                    l = l == null || l.Result == null ? new(0, DataType.Integer) : l;
-                    r = r == null || r.Result == null ? new(0, DataType.Integer) : r;
-                    if (l.DataType == DataType.Integer && r.DataType == DataType.Integer) {
-                      return new(l.ResultNumeric - r.ResultNumeric, DataType.Integer);
-                    }
-                    if ((l.IsNumeric
-                                || l.IsNumericString
-                                || l.Result is ExcelDataProvider.IRangeInfo)
-                        && (r.IsNumeric
-                                || r.IsNumericString
-                                || r.Result is ExcelDataProvider.IRangeInfo)) {
-                      return new(l.ResultNumeric - r.ResultNumeric, DataType.Decimal);
-                    }
-
-                    return new(eErrorType.Value);
-                  }));
-    }
-  }
-
-  private static IOperator _multiply;
-
-  public static IOperator Multiply {
-    get {
-      return _multiply
-          ?? (_multiply = new Operator(
-                  Operators.Multiply,
-                  _precedenceMultiplyDevide,
-                  (l, r) => {
-                    l = l ?? new CompileResult(0, DataType.Integer);
-                    r = r ?? new CompileResult(0, DataType.Integer);
-                    if (l.DataType == DataType.Integer && r.DataType == DataType.Integer) {
-                      return new(l.ResultNumeric * r.ResultNumeric, DataType.Integer);
-                    }
-                    if ((l.IsNumeric
-                                || l.IsNumericString
-                                || l.Result is ExcelDataProvider.IRangeInfo)
-                        && (r.IsNumeric
-                                || r.IsNumericString
-                                || r.Result is ExcelDataProvider.IRangeInfo)) {
-                      return new(l.ResultNumeric * r.ResultNumeric, DataType.Decimal);
-                    }
-                    return new(eErrorType.Value);
-                  }));
-    }
-  }
-
-  private static IOperator _divide;
-
-  public static IOperator Divide {
-    get {
-      return _divide
-          ?? (_divide = new Operator(
-                  Operators.Divide,
-                  _precedenceMultiplyDevide,
-                  (l, r) => {
-                    if (!(l.IsNumeric
-                                || l.IsNumericString
-                                || l.Result is ExcelDataProvider.IRangeInfo)
-                        || !(r.IsNumeric
-                                || r.IsNumericString
-                                || r.Result is ExcelDataProvider.IRangeInfo)) {
-                      return new(eErrorType.Value);
-                    }
-                    var left = l.ResultNumeric;
-                    var right = r.ResultNumeric;
-                    if (Math.Abs(right - 0d) < double.Epsilon) {
-                      return new(eErrorType.Div0);
-                    }
-                    if ((l.IsNumeric
-                                || l.IsNumericString
-                                || l.Result is ExcelDataProvider.IRangeInfo)
-                        && (r.IsNumeric
-                                || r.IsNumericString
-                                || r.Result is ExcelDataProvider.IRangeInfo)) {
-                      return new(left / right, DataType.Decimal);
-                    }
-                    return new(eErrorType.Value);
-                  }));
-    }
-  }
-
-  public static IOperator Exp {
-    get {
-      return new Operator(
-          Operators.Exponentiation,
-          _precedenceExp,
-          (l, r) => {
-            if (l == null && r == null) {
-              return new(eErrorType.Value);
-            }
-            l = l ?? new CompileResult(0, DataType.Integer);
-            r = r ?? new CompileResult(0, DataType.Integer);
-            if ((l.IsNumeric || l.Result is ExcelDataProvider.IRangeInfo)
-                && (r.IsNumeric || r.Result is ExcelDataProvider.IRangeInfo)) {
-              return new(Math.Pow(l.ResultNumeric, r.ResultNumeric), DataType.Decimal);
-            }
-            return new(0d, DataType.Decimal);
-          });
-    }
-  }
-
-  public static IOperator Concat {
-    get {
-      return new Operator(
-          Operators.Concat,
-          _precedenceConcat,
-          (l, r) => {
-            l = l ?? new CompileResult(string.Empty, DataType.String);
-            r = r ?? new CompileResult(string.Empty, DataType.String);
-            var lStr = l.Result != null ? l.ResultValue.ToString() : string.Empty;
-            var rStr = r.Result != null ? r.ResultValue.ToString() : string.Empty;
-            return new(string.Concat(lStr, rStr), DataType.String);
-          });
-    }
-  }
-
-  private static IOperator _greaterThan;
-
-  public static IOperator GreaterThan {
-    get {
-      //return new Operator(Operators.GreaterThan, PrecedenceComparison, (l, r) => new CompileResult(Compare(l, r) > 0, DataType.Boolean));
-      return _greaterThan
-          ?? (_greaterThan = new Operator(
-                  Operators.LessThanOrEqual,
-                  _precedenceComparison,
-                  (l, r) => Compare(l, r, compRes => compRes > 0)));
-    }
-  }
-
-  private static IOperator _eq;
-
-  public static IOperator Eq {
-    get {
-      //return new Operator(Operators.Equals, PrecedenceComparison, (l, r) => new CompileResult(Compare(l, r) == 0, DataType.Boolean));
-      return _eq
-          ?? (_eq = new Operator(
-                  Operators.LessThanOrEqual,
-                  _precedenceComparison,
-                  (l, r) => Compare(l, r, compRes => compRes == 0)));
-    }
-  }
-
-  private static IOperator _notEqualsTo;
-
-  public static IOperator NotEqualsTo {
-    get {
-      //return new Operator(Operators.NotEqualTo, PrecedenceComparison, (l, r) => new CompileResult(Compare(l, r) != 0, DataType.Boolean));
-      return _notEqualsTo
-          ?? (_notEqualsTo = new Operator(
-                  Operators.LessThanOrEqual,
-                  _precedenceComparison,
-                  (l, r) => Compare(l, r, compRes => compRes != 0)));
-    }
-  }
-
-  private static IOperator _greaterThanOrEqual;
-
-  public static IOperator GreaterThanOrEqual {
-    get {
-      //return new Operator(Operators.GreaterThanOrEqual, PrecedenceComparison, (l, r) => new CompileResult(Compare(l, r) >= 0, DataType.Boolean));
-      return _greaterThanOrEqual
-          ?? (_greaterThanOrEqual = new Operator(
-                  Operators.LessThanOrEqual,
-                  _precedenceComparison,
-                  (l, r) => Compare(l, r, compRes => compRes >= 0)));
-    }
-  }
-
-  private static IOperator _lessThan;
-
-  public static IOperator LessThan {
-    get {
-      //return new Operator(Operators.LessThan, PrecedenceComparison, (l, r) => new CompileResult(Compare(l, r) < 0, DataType.Boolean));
-      return _lessThan
-          ?? (_lessThan = new Operator(
-                  Operators.LessThanOrEqual,
-                  _precedenceComparison,
-                  (l, r) => Compare(l, r, compRes => compRes < 0)));
-    }
-  }
-
-  public static IOperator LessThanOrEqual {
-    get {
-      //return new Operator(Operators.LessThanOrEqual, PrecedenceComparison, (l, r) => new CompileResult(Compare(l, r) <= 0, DataType.Boolean));
-      return new Operator(
-          Operators.LessThanOrEqual,
-          _precedenceComparison,
-          (l, r) => Compare(l, r, compRes => compRes <= 0));
-    }
-  }
-
-  private static IOperator _percent;
-
-  public static IOperator Percent {
-    get {
-      if (_percent == null) {
-        _percent = new Operator(
-            Operators.Percent,
-            _precedencePercent,
-            (l, r) => {
-              l = l ?? new CompileResult(0, DataType.Integer);
-              r = r ?? new CompileResult(0, DataType.Integer);
-              if (l.DataType == DataType.Integer && r.DataType == DataType.Integer) {
-                return new(l.ResultNumeric * r.ResultNumeric, DataType.Integer);
-              }
-              if ((l.IsNumeric || l.Result is ExcelDataProvider.IRangeInfo)
-                  && (r.IsNumeric || r.Result is ExcelDataProvider.IRangeInfo)) {
-                return new(l.ResultNumeric * r.ResultNumeric, DataType.Decimal);
-              }
-              return new(eErrorType.Value);
-            });
-      }
-      return _percent;
-    }
-  }
-
-  private static object GetObjFromOther(CompileResult obj, CompileResult other) {
-    if (obj.Result == null) {
-      if (other.DataType == DataType.String) {
-        return string.Empty;
-      }
-      return 0d;
-    }
-    return obj.ResultValue;
-  }
-
-  private static CompileResult Compare(
-      CompileResult l,
-      CompileResult r,
-      Func<int, bool> comparison) {
-    if (EitherIsError(l, r, out var errorVal)) {
-      return new(errorVal);
-    }
-    object left,
-        right;
-    left = GetObjFromOther(l, r);
-    right = GetObjFromOther(r, l);
-    if (ConvertUtil.IsNumeric(left) && ConvertUtil.IsNumeric(right)) {
-      var lnum = ConvertUtil.GetValueDouble(left);
-      var rnum = ConvertUtil.GetValueDouble(right);
-      if (Math.Abs(lnum - rnum) < double.Epsilon) {
-        return new(comparison(0), DataType.Boolean);
-      }
-      var comparisonResult = lnum.CompareTo(rnum);
-      return new(comparison(comparisonResult), DataType.Boolean);
-    } else {
-      var comparisonResult = CompareString(left, right);
-      return new(comparison(comparisonResult), DataType.Boolean);
-    }
-  }
-
-  private static int CompareString(object l, object r) {
-    var sl = (l ?? "").ToString();
-    var sr = (r ?? "").ToString();
-    return String.Compare(sl, sr, StringComparison.Ordinal);
-  }
-
-  private static bool EitherIsError(
-      CompileResult l,
-      CompileResult r,
-      out ExcelErrorValue errorVal) {
-    if (l.DataType == DataType.ExcelError) {
-      errorVal = (ExcelErrorValue)l.Result;
-      return true;
-    }
-    if (r.DataType == DataType.ExcelError) {
-      errorVal = (ExcelErrorValue)r.Result;
-      return true;
-    }
-    errorVal = null;
-    return false;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Excel/Operators/Operators.cs b/EPPlus/FormulaParsing/Excel/Operators/Operators.cs
deleted file mode 100644
index 04c07e5..0000000
--- a/EPPlus/FormulaParsing/Excel/Operators/Operators.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Operators;
-
-public enum Operators {
-  Undefined,
-  Concat,
-  Plus,
-  Minus,
-  Multiply,
-  Divide,
-  Modulus,
-  Percent,
-  Equals,
-  GreaterThan,
-  GreaterThanOrEqual,
-  LessThan,
-  LessThanOrEqual,
-  NotEqualTo,
-  IntegerDivision,
-  Exponentiation,
-}
diff --git a/EPPlus/FormulaParsing/Excel/Operators/OperatorsDict.cs b/EPPlus/FormulaParsing/Excel/Operators/OperatorsDict.cs
deleted file mode 100644
index 2f1cf99..0000000
--- a/EPPlus/FormulaParsing/Excel/Operators/OperatorsDict.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.FormulaParsing.Excel.Operators;
-
-public class OperatorsDict : Dictionary<string, IOperator> {
-  public OperatorsDict() {
-    Add("+", Operator.Plus);
-    Add("-", Operator.Minus);
-    Add("*", Operator.Multiply);
-    Add("/", Operator.Divide);
-    Add("^", Operator.Exp);
-    Add("=", Operator.Eq);
-    Add(">", Operator.GreaterThan);
-    Add(">=", Operator.GreaterThanOrEqual);
-    Add("<", Operator.LessThan);
-    Add("<=", Operator.LessThanOrEqual);
-    Add("<>", Operator.NotEqualsTo);
-    Add("&", Operator.Concat);
-  }
-
-  private static IDictionary<string, IOperator> _instance;
-
-  public static IDictionary<string, IOperator> Instance {
-    get {
-      if (_instance == null) {
-        _instance = new OperatorsDict();
-      }
-      return _instance;
-    }
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExcelCalculationOption.cs b/EPPlus/FormulaParsing/ExcelCalculationOption.cs
deleted file mode 100644
index 79d03bc..0000000
--- a/EPPlus/FormulaParsing/ExcelCalculationOption.cs
+++ /dev/null
@@ -1,5 +0,0 @@
-namespace OfficeOpenXml.FormulaParsing;
-
-public class ExcelCalculationOption {
-  public bool AllowCirculareReferences { get; set; } = false;
-}
diff --git a/EPPlus/FormulaParsing/ExcelDataProvider.cs b/EPPlus/FormulaParsing/ExcelDataProvider.cs
deleted file mode 100644
index 2c33ece..0000000
--- a/EPPlus/FormulaParsing/ExcelDataProvider.cs
+++ /dev/null
@@ -1,153 +0,0 @@
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-
-namespace OfficeOpenXml.FormulaParsing;
-
-/// <summary>
-/// This class should be implemented to be able to deliver excel data
-/// to the formula parser.
-/// </summary>
-public abstract class ExcelDataProvider {
-  /// <summary>
-  /// A range of cells in a worksheet.
-  /// </summary>
-  public interface IRangeInfo : IEnumerator<ICellInfo>, IEnumerable<ICellInfo> {
-    bool IsEmpty { get; }
-
-    bool IsMulti { get; }
-
-    int GetNCells();
-
-    ExcelAddressBase Address { get; }
-
-    object GetValue(int row, int col);
-
-    object GetOffset(int rowOffset, int colOffset);
-
-    ExcelWorksheet Worksheet { get; }
-  }
-
-  /// <summary>
-  /// Information and help methods about a cell
-  /// </summary>
-  public interface ICellInfo {
-    string Address { get; }
-
-    int Row { get; }
-
-    int Column { get; }
-
-    string Formula { get; }
-
-    object Value { get; }
-
-    double ValueDouble { get; }
-
-    double ValueDoubleLogical { get; }
-
-    bool IsHiddenRow { get; }
-
-    bool IsExcelError { get; }
-
-    IList<Token> Tokens { get; }
-  }
-
-  public interface INameInfo {
-    ulong Id { get; set; }
-
-    string Worksheet { get; set; }
-
-    string Name { get; set; }
-
-    string Formula { get; set; }
-
-    IList<Token> Tokens { get; }
-
-    object Value { get; set; }
-  }
-
-  /// <summary>
-  /// Returns the names of all worksheet names
-  /// </summary>
-  /// <returns></returns>
-  public abstract ExcelNamedRangeCollection GetWorksheetNames(string worksheet);
-
-  /// <summary>
-  /// Returns all defined names in a workbook
-  /// </summary>
-  /// <returns></returns>
-  public abstract ExcelNamedRangeCollection GetWorkbookNameValues();
-
-  /// <summary>
-  /// Returns values from the required range.
-  /// </summary>
-  /// <param name="worksheetName">The name of the worksheet</param>
-  /// <param name="row">Row</param>
-  /// <param name="column">Column</param>
-  /// <param name="address">The reference address</param>
-  /// <returns></returns>
-  public abstract IRangeInfo GetRange(string worksheetName, int row, int column, string address);
-
-  public abstract INameInfo GetName(string worksheet, string name);
-
-  public abstract IEnumerable<object> GetRangeValues(string address);
-
-  public abstract string GetRangeFormula(string worksheetName, int row, int column);
-
-  public abstract List<Token> GetRangeFormulaTokens(string worksheetName, int row, int column);
-
-  public abstract bool IsRowHidden(string worksheetName, int row);
-
-  ///// <summary>
-  ///// Returns a single cell value
-  ///// </summary>
-  ///// <param name="address"></param>
-  ///// <returns></returns>
-  //public abstract object GetCellValue(int sheetID, string address);
-
-  /// <summary>
-  /// Returns a single cell value
-  /// </summary>
-  /// <param name="sheetName"></param>
-  /// <param name="row"></param>
-  /// <param name="col"></param>
-  /// <returns></returns>
-  public abstract object GetCellValue(string sheetName, int row, int col);
-
-  ///// <summary>
-  ///// Sets the value on the cell
-  ///// </summary>
-  ///// <param name="address"></param>
-  ///// <param name="value"></param>
-  //public abstract void SetCellValue(string address, object value);
-
-  /// <summary>
-  /// Returns the address of the lowest rightmost cell on the worksheet.
-  /// </summary>
-  /// <param name="worksheet"></param>
-  /// <returns></returns>
-  public abstract ExcelCellAddress GetDimensionEnd(string worksheet);
-
-  /// <summary>
-  /// Max number of columns in a worksheet that the Excel data provider can handle.
-  /// </summary>
-  public abstract int ExcelMaxColumns { get; }
-
-  /// <summary>
-  /// Max number of rows in a worksheet that the Excel data provider can handle
-  /// </summary>
-  public abstract int ExcelMaxRows { get; }
-
-  public abstract object GetRangeValue(string worksheetName, int row, int column);
-
-  public abstract string GetFormat(object value, string format);
-
-  public abstract void Reset();
-
-  public abstract IRangeInfo GetRange(
-      string worksheet,
-      int fromRow,
-      int fromCol,
-      int toRow,
-      int toCol);
-}
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/AddressTranslator.cs b/EPPlus/FormulaParsing/ExcelUtilities/AddressTranslator.cs
deleted file mode 100644
index 7816854..0000000
--- a/EPPlus/FormulaParsing/ExcelUtilities/AddressTranslator.cs
+++ /dev/null
@@ -1,116 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Globalization;
-using System.Text.RegularExpressions;
-using OfficeOpenXml.FormulaParsing.Utilities;
-
-namespace OfficeOpenXml.FormulaParsing.ExcelUtilities;
-
-/// <summary>
-/// Handles translations from Spreadsheet addresses to 0-based numeric index.
-/// </summary>
-public class AddressTranslator {
-  public enum RangeCalculationBehaviour {
-    FirstPart,
-    LastPart,
-  }
-
-  private readonly ExcelDataProvider _excelDataProvider;
-
-  public AddressTranslator(ExcelDataProvider excelDataProvider) {
-    Require.That(excelDataProvider).Named("excelDataProvider").IsNotNull();
-    _excelDataProvider = excelDataProvider;
-  }
-
-  /// <summary>
-  /// Translates an address in format "A1" to col- and rowindex.
-  ///
-  /// If the supplied address is a range, the address of the first part will be calculated.
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="col"></param>
-  /// <param name="row"></param>
-  public virtual void ToColAndRow(string address, out int col, out int row) {
-    ToColAndRow(address, out col, out row, RangeCalculationBehaviour.FirstPart);
-  }
-
-  /// <summary>
-  /// Translates an address in format "A1" to col- and rowindex.
-  /// </summary>
-  /// <param name="address"></param>
-  /// <param name="col"></param>
-  /// <param name="row"></param>
-  /// <param name="behaviour"></param>
-  public virtual void ToColAndRow(
-      string address,
-      out int col,
-      out int row,
-      RangeCalculationBehaviour behaviour) {
-    address = address.ToUpper(CultureInfo.InvariantCulture);
-    var alphaPart = GetAlphaPart(address);
-    col = 0;
-    var nLettersInAlphabet = 26;
-    for (int x = 0; x < alphaPart.Length; x++) {
-      var pos = alphaPart.Length - x - 1;
-      var currentNumericValue = GetNumericAlphaValue(alphaPart[x]);
-      col += (nLettersInAlphabet * pos * currentNumericValue);
-      if (pos == 0) {
-        col += currentNumericValue;
-      }
-    }
-    //col--;
-    //row = GetIntPart(address) - 1 ?? GetRowIndexByBehaviour(behaviour);
-    row = GetIntPart(address) ?? GetRowIndexByBehaviour(behaviour);
-  }
-
-  private int GetRowIndexByBehaviour(RangeCalculationBehaviour behaviour) {
-    if (behaviour == RangeCalculationBehaviour.FirstPart) {
-      return 1;
-    }
-    return _excelDataProvider.ExcelMaxRows;
-  }
-
-  private int GetNumericAlphaValue(char c) {
-    return c - 64;
-  }
-
-  private string GetAlphaPart(string address) {
-    return Regex.Match(address, "[A-Z]+").Value;
-  }
-
-  private int? GetIntPart(string address) {
-    if (Regex.IsMatch(address, "[0-9]+")) {
-      return int.Parse(Regex.Match(address, "[0-9]+").Value);
-    }
-    return null;
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/CellReferenceProvider.cs b/EPPlus/FormulaParsing/ExcelUtilities/CellReferenceProvider.cs
deleted file mode 100644
index 590d3e0..0000000
--- a/EPPlus/FormulaParsing/ExcelUtilities/CellReferenceProvider.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-
-namespace OfficeOpenXml.FormulaParsing.ExcelUtilities;
-
-public class CellReferenceProvider {
-  public virtual IEnumerable<string> GetReferencedAddresses(
-      string cellFormula,
-      ParsingContext context) {
-    var resultCells = new List<string>();
-    var r = context.Configuration.Lexer.Tokenize(
-        cellFormula,
-        context.Scopes.Current.Address.Worksheet);
-    var toAddresses = r.Where(x => x.TokenType == TokenType.ExcelAddress);
-    foreach (var toAddress in toAddresses) {
-      var rangeAddress = context.RangeAddressFactory.Create(toAddress.Value);
-      var rangeCells = new List<string>();
-      if (rangeAddress.FromRow < rangeAddress.ToRow || rangeAddress.FromCol < rangeAddress.ToCol) {
-        for (var col = rangeAddress.FromCol; col <= rangeAddress.ToCol; col++) {
-          for (var row = rangeAddress.FromRow; row <= rangeAddress.ToRow; row++) {
-            resultCells.Add(context.RangeAddressFactory.Create(col, row).Address);
-          }
-        }
-      } else {
-        rangeCells.Add(toAddress.Value);
-      }
-      resultCells.AddRange(rangeCells);
-    }
-    return resultCells;
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/ExcelAddressInfo.cs b/EPPlus/FormulaParsing/ExcelUtilities/ExcelAddressInfo.cs
deleted file mode 100644
index c7dd453..0000000
--- a/EPPlus/FormulaParsing/ExcelUtilities/ExcelAddressInfo.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using OfficeOpenXml.FormulaParsing.Utilities;
-
-namespace OfficeOpenXml.FormulaParsing.ExcelUtilities;
-
-public class ExcelAddressInfo {
-  private ExcelAddressInfo(string address) {
-    var addressOnSheet = address;
-    if (address.Contains("!")) {
-      var worksheetArr = address.Split('!');
-      Worksheet = worksheetArr[0];
-      addressOnSheet = worksheetArr[1];
-    }
-    if (addressOnSheet.Contains(":")) {
-      var rangeArr = addressOnSheet.Split(':');
-      StartCell = rangeArr[0];
-      EndCell = rangeArr[1];
-    } else {
-      StartCell = addressOnSheet;
-    }
-    AddressOnSheet = addressOnSheet;
-  }
-
-  public static ExcelAddressInfo Parse(string address) {
-    Require.That(address).Named("address").IsNotNullOrEmpty();
-    return new(address);
-  }
-
-  public string Worksheet { get; private set; } = string.Empty;
-
-  public bool WorksheetIsSpecified => !string.IsNullOrEmpty(Worksheet);
-
-  public bool IsMultipleCells => !string.IsNullOrEmpty(EndCell);
-
-  public string StartCell { get; private set; }
-
-  public string EndCell { get; private set; }
-
-  public string AddressOnSheet { get; private set; }
-}
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/ExcelAddressUtil.cs b/EPPlus/FormulaParsing/ExcelUtilities/ExcelAddressUtil.cs
deleted file mode 100644
index 03373ce..0000000
--- a/EPPlus/FormulaParsing/ExcelUtilities/ExcelAddressUtil.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.ExcelUtilities;
-
-public static class ExcelAddressUtil {
-  private static readonly char[] SheetNameInvalidChars = { '?', ':', '*', '/', '\\' };
-
-  public static bool IsValidAddress(string token) {
-    int ix;
-    if (token[0] == '\'') {
-      ix = token.LastIndexOf('\'');
-      if (ix > 0 && ix < token.Length - 1 && token[ix + 1] == '!') {
-        if (token.IndexOfAny(SheetNameInvalidChars, 1, ix - 1) > 0) {
-          return false;
-        }
-        token = token.Substring(ix + 2);
-      } else {
-        return false;
-      }
-    } else if ((ix = token.IndexOf('!')) > 1) {
-      if (token.IndexOfAny(SheetNameInvalidChars, 0, token.IndexOf('!')) > 0) {
-        return false;
-      }
-      token = token.Substring(token.IndexOf('!') + 1);
-    }
-    return ExcelCellBase.IsValidAddress(token);
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/ExcelReferenceType.cs b/EPPlus/FormulaParsing/ExcelUtilities/ExcelReferenceType.cs
deleted file mode 100644
index 9651a35..0000000
--- a/EPPlus/FormulaParsing/ExcelUtilities/ExcelReferenceType.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.ExcelUtilities;
-
-public enum ExcelReferenceType {
-  AbsoluteRowAndColumn = 1,
-  AbsoluteRowRelativeColumn = 2,
-  RelativeRowAbsolutColumn = 3,
-  RelativeRowAndColumn = 4,
-}
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/ExpressionEvaluator.cs b/EPPlus/FormulaParsing/ExcelUtilities/ExpressionEvaluator.cs
deleted file mode 100644
index df05bb4..0000000
--- a/EPPlus/FormulaParsing/ExcelUtilities/ExpressionEvaluator.cs
+++ /dev/null
@@ -1,124 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System;
-using System.Text.RegularExpressions;
-using OfficeOpenXml.FormulaParsing.Excel.Operators;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.ExcelUtilities;
-
-public class ExpressionEvaluator {
-  private readonly WildCardValueMatcher _wildCardValueMatcher;
-  private readonly CompileResultFactory _compileResultFactory;
-
-  public ExpressionEvaluator()
-      : this(new(), new()) {}
-
-  public ExpressionEvaluator(
-      WildCardValueMatcher wildCardValueMatcher,
-      CompileResultFactory compileResultFactory) {
-    _wildCardValueMatcher = wildCardValueMatcher;
-    _compileResultFactory = compileResultFactory;
-  }
-
-  private string GetNonAlphanumericStartChars(string expression) {
-    if (!string.IsNullOrEmpty(expression)) {
-      if (Regex.IsMatch(expression, "^([^a-zA-Z0-9]{2})")) {
-        return expression.Substring(0, 2);
-      }
-      if (Regex.IsMatch(expression, "^([^a-zA-Z0-9]{1})")) {
-        return expression.Substring(0, 1);
-      }
-    }
-    return null;
-  }
-
-  private bool EvaluateOperator(object left, object right, IOperator op) {
-    var leftResult = _compileResultFactory.Create(left);
-    var rightResult = _compileResultFactory.Create(right);
-    var result = op.Apply(leftResult, rightResult);
-    if (result.DataType != DataType.Boolean) {
-      throw new ArgumentException("Illegal operator in expression");
-    }
-    return (bool)result.Result;
-  }
-
-  public bool TryConvertToDouble(object op, out double d) {
-    if (op is double || op is int) {
-      d = Convert.ToDouble(op);
-      return true;
-    }
-    if (op is DateTime time) {
-      d = time.ToOADate();
-      return true;
-    }
-    if (op != null) {
-      if (double.TryParse(op.ToString(), out d)) {
-        return true;
-      }
-    }
-    d = 0;
-    return false;
-  }
-
-  public bool Evaluate(object left, string expression) {
-    if (expression == string.Empty) {
-      return left == null;
-    }
-    var operatorCandidate = GetNonAlphanumericStartChars(expression);
-    if (!string.IsNullOrEmpty(operatorCandidate) && operatorCandidate != "-") {
-      if (OperatorsDict.Instance.TryGetValue(operatorCandidate, out var op)) {
-        var right = expression.Replace(operatorCandidate, string.Empty);
-        if (left == null && right == string.Empty) {
-          return op.Operator == Operators.Equals;
-        }
-        if (left == null ^ right == string.Empty) {
-          return op.Operator == Operators.NotEqualTo;
-        }
-        bool leftIsNumeric = TryConvertToDouble(left, out var leftNum);
-        bool rightIsNumeric = double.TryParse(right, out var rightNum);
-        bool rightIsDate = DateTime.TryParse(right, out var date);
-        if (leftIsNumeric && rightIsNumeric) {
-          return EvaluateOperator(leftNum, rightNum, op);
-        }
-        if (leftIsNumeric && rightIsDate) {
-          return EvaluateOperator(leftNum, date.ToOADate(), op);
-        }
-        if (leftIsNumeric != rightIsNumeric) {
-          return op.Operator == Operators.NotEqualTo;
-        }
-        return EvaluateOperator(left, right, op);
-      }
-    }
-    return _wildCardValueMatcher.IsMatch(expression, left) == 0;
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/FormulaDependencies.cs b/EPPlus/FormulaParsing/ExcelUtilities/FormulaDependencies.cs
deleted file mode 100644
index b5bc0cf..0000000
--- a/EPPlus/FormulaParsing/ExcelUtilities/FormulaDependencies.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.FormulaParsing.ExcelUtilities;
-
-public class FormulaDependencies {
-  public FormulaDependencies()
-      : this(new()) {}
-
-  public FormulaDependencies(FormulaDependencyFactory formulaDependencyFactory) {
-    _formulaDependencyFactory = formulaDependencyFactory;
-  }
-
-  private readonly FormulaDependencyFactory _formulaDependencyFactory;
-  private readonly Dictionary<string, FormulaDependency> _dependencies = new();
-
-  public IEnumerable<KeyValuePair<string, FormulaDependency>> Dependencies => _dependencies;
-
-  public void AddFormulaScope(ParsingScope parsingScope) {
-    //var dependency = _formulaDependencyFactory.Create(parsingScope);
-    //var address = parsingScope.Address.ToString();
-    //if (!_dependencies.ContainsKey(address))
-    //{
-    //    _dependencies.Add(address, dependency);
-    //}
-    //if (parsingScope.Parent != null)
-    //{
-    //    var parentAddress = parsingScope.Parent.Address.ToString();
-    //    if (_dependencies.ContainsKey(parentAddress))
-    //    {
-    //        var parent = _dependencies[parentAddress];
-    //        parent.AddReferenceTo(parsingScope.Address);
-    //        dependency.AddReferenceFrom(parent.Address);
-    //    }
-    //}
-  }
-
-  public void Clear() {
-    _dependencies.Clear();
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/FormulaDependency.cs b/EPPlus/FormulaParsing/ExcelUtilities/FormulaDependency.cs
deleted file mode 100644
index d46fca9..0000000
--- a/EPPlus/FormulaParsing/ExcelUtilities/FormulaDependency.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.Exceptions;
-
-namespace OfficeOpenXml.FormulaParsing.ExcelUtilities;
-
-public class FormulaDependency {
-  public FormulaDependency(ParsingScope scope) {
-    ScopeId = scope.ScopeId;
-    Address = scope.Address;
-  }
-
-  public Guid ScopeId { get; private set; }
-
-  public RangeAddress Address { get; private set; }
-
-  private readonly List<RangeAddress> _referencedBy = new();
-
-  private readonly List<RangeAddress> _references = new();
-
-  public virtual void AddReferenceFrom(RangeAddress rangeAddress) {
-    if (Address.CollidesWith(rangeAddress)
-        || _references.Exists(x => x.CollidesWith(rangeAddress))) {
-      throw new CircularReferenceException("Circular reference detected at " + rangeAddress);
-    }
-    _referencedBy.Add(rangeAddress);
-  }
-
-  public virtual void AddReferenceTo(RangeAddress rangeAddress) {
-    if (Address.CollidesWith(rangeAddress)
-        || _referencedBy.Exists(x => x.CollidesWith(rangeAddress))) {
-      throw new CircularReferenceException("Circular reference detected at " + rangeAddress);
-    }
-    _references.Add(rangeAddress);
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/FormulaDependencyFactory.cs b/EPPlus/FormulaParsing/ExcelUtilities/FormulaDependencyFactory.cs
deleted file mode 100644
index 9eb1f6d..0000000
--- a/EPPlus/FormulaParsing/ExcelUtilities/FormulaDependencyFactory.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.ExcelUtilities;
-
-public class FormulaDependencyFactory {
-  public virtual FormulaDependency Create(ParsingScope scope) {
-    return new(scope);
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/IndexToAddressTranslator.cs b/EPPlus/FormulaParsing/ExcelUtilities/IndexToAddressTranslator.cs
deleted file mode 100644
index 238743a..0000000
--- a/EPPlus/FormulaParsing/ExcelUtilities/IndexToAddressTranslator.cs
+++ /dev/null
@@ -1,86 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using OfficeOpenXml.FormulaParsing.Utilities;
-
-namespace OfficeOpenXml.FormulaParsing.ExcelUtilities;
-
-public class IndexToAddressTranslator {
-  public IndexToAddressTranslator(ExcelDataProvider excelDataProvider)
-      : this(excelDataProvider, ExcelReferenceType.AbsoluteRowAndColumn) {}
-
-  public IndexToAddressTranslator(
-      ExcelDataProvider excelDataProvider,
-      ExcelReferenceType referenceType) {
-    Require.That(excelDataProvider).Named("excelDataProvider").IsNotNull();
-    _excelDataProvider = excelDataProvider;
-    _excelReferenceType = referenceType;
-  }
-
-  private readonly ExcelDataProvider _excelDataProvider;
-  private readonly ExcelReferenceType _excelReferenceType;
-
-  protected internal static string GetColumnLetter(int iColumnNumber, bool fixedCol) {
-    if (iColumnNumber < 1) {
-      //throw new Exception("Column number is out of range");
-      return "#REF!";
-    }
-
-    string sCol = "";
-    do {
-      sCol = ((char)('A' + ((iColumnNumber - 1) % 26))) + sCol;
-      iColumnNumber = (iColumnNumber - ((iColumnNumber - 1) % 26)) / 26;
-    } while (iColumnNumber > 0);
-    return fixedCol ? "$" + sCol : sCol;
-  }
-
-  public string ToAddress(int col, int row) {
-    var fixedCol =
-        _excelReferenceType == ExcelReferenceType.AbsoluteRowAndColumn
-            || _excelReferenceType == ExcelReferenceType.RelativeRowAbsolutColumn;
-    var colString = GetColumnLetter(col, fixedCol);
-    return colString + GetRowNumber(row);
-  }
-
-  private string GetRowNumber(int rowNo) {
-    var retVal = rowNo < (_excelDataProvider.ExcelMaxRows) ? rowNo.ToString() : string.Empty;
-    if (!string.IsNullOrEmpty(retVal)) {
-      switch (_excelReferenceType) {
-        case ExcelReferenceType.AbsoluteRowAndColumn:
-        case ExcelReferenceType.AbsoluteRowRelativeColumn:
-          return "$" + retVal;
-        default:
-          return retVal;
-      }
-    }
-    return retVal;
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/LookupValueMatcher.cs b/EPPlus/FormulaParsing/ExcelUtilities/LookupValueMatcher.cs
deleted file mode 100644
index d2e0f3e..0000000
--- a/EPPlus/FormulaParsing/ExcelUtilities/LookupValueMatcher.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace OfficeOpenXml.FormulaParsing.ExcelUtilities;
-
-public class LookupValueMatcher : ValueMatcher {
-  protected override int CompareObjectToString(object o1, string o2) {
-    return IncompatibleOperands;
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/NumericExpressionEvaluator.cs b/EPPlus/FormulaParsing/ExcelUtilities/NumericExpressionEvaluator.cs
deleted file mode 100644
index 174d595..0000000
--- a/EPPlus/FormulaParsing/ExcelUtilities/NumericExpressionEvaluator.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System;
-using System.Text.RegularExpressions;
-using OfficeOpenXml.FormulaParsing.Excel.Operators;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-namespace OfficeOpenXml.FormulaParsing.ExcelUtilities;
-
-public class NumericExpressionEvaluator {
-  private readonly ValueMatcher _valueMatcher;
-  private readonly CompileResultFactory _compileResultFactory;
-
-  public NumericExpressionEvaluator()
-      : this(new(), new()) {}
-
-  public NumericExpressionEvaluator(
-      ValueMatcher valueMatcher,
-      CompileResultFactory compileResultFactory) {
-    _valueMatcher = valueMatcher;
-    _compileResultFactory = compileResultFactory;
-  }
-
-  private string GetNonNumericStartChars(string expression) {
-    if (!string.IsNullOrEmpty(expression)) {
-      if (Regex.IsMatch(expression, @"^([^\d]{2})")) {
-        return expression.Substring(0, 2);
-      }
-      if (Regex.IsMatch(expression, @"^([^\d]{1})")) {
-        return expression.Substring(0, 1);
-      }
-    }
-    return null;
-  }
-
-  public double? OperandAsDouble(object op) {
-    if (op is double || op is int) {
-      return Convert.ToDouble(op);
-    }
-    if (op != null) {
-      if (double.TryParse(op.ToString(), out var output)) {
-        return output;
-      }
-    }
-    return null;
-  }
-
-  public bool Evaluate(object left, string expression) {
-    var operatorCandidate = GetNonNumericStartChars(expression);
-    var leftNum = OperandAsDouble(left);
-    if (!string.IsNullOrEmpty(operatorCandidate) && leftNum != null) {
-      if (OperatorsDict.Instance.TryGetValue(operatorCandidate, out var op)) {
-        var numericCandidate = expression.Replace(operatorCandidate, string.Empty);
-        if (double.TryParse(numericCandidate, out var d)) {
-          var leftResult = _compileResultFactory.Create(leftNum);
-          var rightResult = _compileResultFactory.Create(d);
-          var result = op.Apply(leftResult, rightResult);
-          if (result.DataType != DataType.Boolean) {
-            throw new ArgumentException("Illegal operator in expression");
-          }
-          return (bool)result.Result;
-        }
-      }
-    }
-    return _valueMatcher.IsMatch(left, expression) == 0;
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/RangeAddress.cs b/EPPlus/FormulaParsing/ExcelUtilities/RangeAddress.cs
deleted file mode 100644
index b46145c..0000000
--- a/EPPlus/FormulaParsing/ExcelUtilities/RangeAddress.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.ExcelUtilities;
-
-public class RangeAddress {
-  internal string Address { get; set; } = string.Empty;
-
-  public string Worksheet { get; internal set; }
-
-  public int FromCol { get; internal set; }
-
-  public int ToCol { get; internal set; }
-
-  public int FromRow { get; internal set; }
-
-  public int ToRow { get; internal set; }
-
-  public override string ToString() {
-    return Address;
-  }
-
-  private static readonly RangeAddress _empty = new();
-
-  public static RangeAddress Empty => _empty;
-
-  /// <summary>
-  /// Returns true if this range collides (full or partly) with the supplied range
-  /// </summary>
-  /// <param name="other">The range to check</param>
-  /// <returns></returns>
-  public bool CollidesWith(RangeAddress other) {
-    if (other.Worksheet != Worksheet) {
-      return false;
-    }
-    if (other.FromRow > ToRow
-        || other.FromCol > ToCol
-        || FromRow > other.ToRow
-        || FromCol > other.ToCol) {
-      return false;
-    }
-    return true;
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/RangeAddressFactory.cs b/EPPlus/FormulaParsing/ExcelUtilities/RangeAddressFactory.cs
deleted file mode 100644
index 2ff911b..0000000
--- a/EPPlus/FormulaParsing/ExcelUtilities/RangeAddressFactory.cs
+++ /dev/null
@@ -1,109 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using OfficeOpenXml.FormulaParsing.Utilities;
-
-namespace OfficeOpenXml.FormulaParsing.ExcelUtilities;
-
-public class RangeAddressFactory {
-  private readonly ExcelDataProvider _excelDataProvider;
-  private readonly IndexToAddressTranslator _indexToAddressTranslator;
-
-  public RangeAddressFactory(ExcelDataProvider excelDataProvider)
-      : this(
-          excelDataProvider,
-          new(excelDataProvider),
-          new(excelDataProvider, ExcelReferenceType.RelativeRowAndColumn)) {}
-
-  public RangeAddressFactory(
-      ExcelDataProvider excelDataProvider,
-      AddressTranslator addressTranslator,
-      IndexToAddressTranslator indexToAddressTranslator) {
-    Require.That(excelDataProvider).Named("excelDataProvider").IsNotNull();
-    Require.That(addressTranslator).Named("addressTranslator").IsNotNull();
-    Require.That(indexToAddressTranslator).Named("indexToAddressTranslator").IsNotNull();
-    _excelDataProvider = excelDataProvider;
-    _indexToAddressTranslator = indexToAddressTranslator;
-  }
-
-  public RangeAddress Create(int col, int row) {
-    return Create(string.Empty, col, row);
-  }
-
-  public RangeAddress Create(string worksheetName, int col, int row) {
-    return new() {
-      Address = _indexToAddressTranslator.ToAddress(col, row),
-      Worksheet = worksheetName,
-      FromCol = col,
-      ToCol = col,
-      FromRow = row,
-      ToRow = row,
-    };
-  }
-
-  /// <summary>
-  ///
-  /// </summary>
-  /// <param name="worksheetName">will be used if no worksheet name is specified in <paramref name="address"/></param>
-  /// <param name="address">address of a range</param>
-  /// <returns></returns>
-  public RangeAddress Create(string worksheetName, string address) {
-    Require.That(address).Named("range").IsNotNullOrEmpty();
-    //var addressInfo = ExcelAddressInfo.Parse(address);
-    var adr = new ExcelAddressBase(address);
-    var sheet = string.IsNullOrEmpty(adr.WorkSheet) ? worksheetName : adr.WorkSheet;
-    var dim = _excelDataProvider.GetDimensionEnd(adr.WorkSheet);
-    var rangeAddress = new RangeAddress {
-      Address = adr.Address,
-      Worksheet = sheet,
-      FromRow = adr._fromRow,
-      FromCol = adr._fromCol,
-      ToRow = (dim != null && adr._toRow > dim.Row) ? dim.Row : adr._toRow,
-      ToCol = adr._toCol,
-    };
-    return rangeAddress;
-  }
-
-  public RangeAddress Create(string range) {
-    Require.That(range).Named("range").IsNotNullOrEmpty();
-    //var addressInfo = ExcelAddressInfo.Parse(range);
-    var adr = new ExcelAddressBase(range);
-    var rangeAddress = new RangeAddress {
-      Address = adr.Address,
-      Worksheet = adr.WorkSheet ?? "",
-      FromRow = adr._fromRow,
-      FromCol = adr._fromCol,
-      ToRow = adr._toRow,
-      ToCol = adr._toCol,
-    };
-    return rangeAddress;
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/ValueMatcher.cs b/EPPlus/FormulaParsing/ExcelUtilities/ValueMatcher.cs
deleted file mode 100644
index 0fb50ba..0000000
--- a/EPPlus/FormulaParsing/ExcelUtilities/ValueMatcher.cs
+++ /dev/null
@@ -1,94 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System;
-
-namespace OfficeOpenXml.FormulaParsing.ExcelUtilities;
-
-public class ValueMatcher {
-  public const int IncompatibleOperands = -2;
-
-  public virtual int IsMatch(object o1, object o2) {
-    if (o1 != null && o2 == null) {
-      return 1;
-    }
-    if (o1 == null && o2 != null) {
-      return -1;
-    }
-    if (o1 == null && o2 == null) {
-      return 0;
-    }
-    //Handle ranges and defined names
-    o1 = CheckGetRange(o1);
-    o2 = CheckGetRange(o2);
-
-    if (o1 is string && o2 is string) {
-      return CompareStringToString(o1.ToString().ToLower(), o2.ToString().ToLower());
-    }
-    if (o1.GetType() == typeof(string)) {
-      return CompareStringToObject(o1.ToString(), o2);
-    }
-    if (o2.GetType() == typeof(string)) {
-      return CompareObjectToString(o1, o2.ToString());
-    }
-    return Convert.ToDouble(o1).CompareTo(Convert.ToDouble(o2));
-  }
-
-  private static object CheckGetRange(object v) {
-    if (v is ExcelDataProvider.IRangeInfo info) {
-      if (info.GetNCells() > 1) {
-        v = ExcelErrorValue.Create(eErrorType.Na);
-      }
-      v = info.GetOffset(0, 0);
-    } else if (v is ExcelDataProvider.INameInfo nameInfo) {
-      v = CheckGetRange(nameInfo);
-    }
-    return v;
-  }
-
-  protected virtual int CompareStringToString(string s1, string s2) {
-    return s1.CompareTo(s2);
-  }
-
-  protected virtual int CompareStringToObject(string o1, object o2) {
-    if (double.TryParse(o1, out var d1)) {
-      return d1.CompareTo(Convert.ToDouble(o2));
-    }
-    return IncompatibleOperands;
-  }
-
-  protected virtual int CompareObjectToString(object o1, string o2) {
-    if (double.TryParse(o2, out var d2)) {
-      return Convert.ToDouble(o1).CompareTo(d2);
-    }
-    return IncompatibleOperands;
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/WildCardValueMatcher.cs b/EPPlus/FormulaParsing/ExcelUtilities/WildCardValueMatcher.cs
deleted file mode 100644
index 15a1754..0000000
--- a/EPPlus/FormulaParsing/ExcelUtilities/WildCardValueMatcher.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Text.RegularExpressions;
-
-namespace OfficeOpenXml.FormulaParsing.ExcelUtilities;
-
-public class WildCardValueMatcher : ValueMatcher {
-  protected override int CompareStringToString(string s1, string s2) {
-    if (s1.Contains("*") || s1.Contains("?")) {
-      var regexPattern = Regex.Escape(s1);
-      regexPattern = string.Format("^{0}$", regexPattern);
-      regexPattern = regexPattern.Replace(@"\*", ".*");
-      regexPattern = regexPattern.Replace(@"\?", ".");
-      if (Regex.IsMatch(s2, regexPattern)) {
-        return 0;
-      }
-    }
-    return base.CompareStringToString(s1, s2);
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExcelValues.cs b/EPPlus/FormulaParsing/ExcelValues.cs
deleted file mode 100644
index c15c606..0000000
--- a/EPPlus/FormulaParsing/ExcelValues.cs
+++ /dev/null
@@ -1,206 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// Represents the errortypes in excel
-/// </summary>
-public enum eErrorType {
-  /// <summary>
-  /// Division by zero
-  /// </summary>
-  Div0,
-
-  /// <summary>
-  /// Not applicable
-  /// </summary>
-  Na,
-
-  /// <summary>
-  /// Name error
-  /// </summary>
-  Name,
-
-  /// <summary>
-  /// Null error
-  /// </summary>
-  Null,
-
-  /// <summary>
-  /// Num error
-  /// </summary>
-  Num,
-
-  /// <summary>
-  /// Reference error
-  /// </summary>
-  Ref,
-
-  /// <summary>
-  /// Value error
-  /// </summary>
-  Value,
-
-  // Bug G0004
-  /// <summary>
-  /// Error error  // Google Bug G0004
-  /// </summary>
-  Error,
-
-  // Bug G0005
-  /// <summary>
-  /// ErrorValueIsNullOrEmpty error  // Google Bug G0005
-  /// </summary>
-  ErrorValueIsNullOrEmpty,
-}
-
-/// <summary>
-/// Represents an Excel error.
-/// </summary>
-/// <seealso cref="eErrorType"/>
-public class ExcelErrorValue {
-  /// <summary>
-  /// Handles the convertion between <see cref="eErrorType"/> and the string values
-  /// used by Excel.
-  /// </summary>
-  public static class Values {
-    public const string Div0 = "#DIV/0!";
-    public const string Na = "#N/A";
-    public const string Name = "#NAME?";
-    public const string Null = "#NULL!";
-    public const string Num = "#NUM!";
-    public const string Ref = "#REF!";
-    public const string Value = "#VALUE!";
-    public const string Error = "#ERROR!"; // Bug G0004
-    public const string ErrorValueIsNullOrEmpty = "#ERRORVALUEISNULLOREMPTY!"; // Bug G0005
-
-    private static readonly Dictionary<string, eErrorType> _values = new() {
-      { Div0, eErrorType.Div0 },
-      { Na, eErrorType.Na },
-      { Name, eErrorType.Name },
-      { Null, eErrorType.Null },
-      { Num, eErrorType.Num },
-      { Ref, eErrorType.Ref },
-      { Value, eErrorType.Value },
-      { Error, eErrorType.Error }, // Bug G0004
-      {
-        ErrorValueIsNullOrEmpty,
-        eErrorType.ErrorValueIsNullOrEmpty
-      } // Bug G0005
-      ,
-    };
-
-    /// <summary>
-    /// Returns true if the supplied <paramref name="candidate"/> is an excel error.
-    /// </summary>
-    /// <param name="candidate"></param>
-    /// <returns></returns>
-    public static bool IsErrorValue(object candidate) {
-      if (candidate == null || !(candidate is ExcelErrorValue)) {
-        return false;
-      }
-      var candidateString = candidate.ToString();
-      return (!string.IsNullOrEmpty(candidateString) && _values.ContainsKey(candidateString));
-    }
-
-    /// <summary>
-    /// Returns true if the supplied <paramref name="candidate"/> is an excel error.
-    /// </summary>
-    /// <param name="candidate"></param>
-    /// <returns></returns>
-    public static bool StringIsErrorValue(string candidate) {
-      return (!string.IsNullOrEmpty(candidate) && _values.ContainsKey(candidate));
-    }
-
-    /// <summary>
-    /// Converts a string to an <see cref="eErrorType"/>
-    /// </summary>
-    /// <param name="val"></param>
-    /// <returns></returns>
-    /// <exception cref="ArgumentException">Thrown if the supplied value is not an Excel error</exception>
-    public static eErrorType ToErrorType(string val) {
-      if (string.IsNullOrEmpty(val) || !_values.ContainsKey(val)) {
-        throw new ArgumentException("Invalid error code " + (val ?? "<empty>"));
-      }
-      return _values[val];
-    }
-  }
-
-  internal static ExcelErrorValue Create(eErrorType errorType) {
-    return new(errorType);
-  }
-
-  internal static ExcelErrorValue Parse(string val) {
-    if (string.IsNullOrEmpty(
-        val)) // Google Bug G0005
-    {
-      val = Values.ErrorValueIsNullOrEmpty;
-    }
-
-    if (Values.StringIsErrorValue(val)) {
-      return new(Values.ToErrorType(val));
-    }
-    if (string.IsNullOrEmpty(val)) {
-      throw new ArgumentNullException("val");
-    }
-    throw new ArgumentException("Not a valid error value: " + val);
-  }
-
-  private ExcelErrorValue(eErrorType type) {
-    Type = type;
-  }
-
-  /// <summary>
-  /// The error type
-  /// </summary>
-  public eErrorType Type { get; private set; }
-
-  /// <summary>
-  /// Returns the string representation of the error type
-  /// </summary>
-  /// <returns></returns>
-  public override string ToString() {
-    switch (Type) {
-      case eErrorType.Div0:
-        return Values.Div0;
-      case eErrorType.Na:
-        return Values.Na;
-      case eErrorType.Name:
-        return Values.Name;
-      case eErrorType.Null:
-        return Values.Null;
-      case eErrorType.Num:
-        return Values.Num;
-      case eErrorType.Ref:
-        return Values.Ref;
-      case eErrorType.Value:
-        return Values.Value;
-      case eErrorType.Error: // Bug G0004
-        return Values.Error;
-      case eErrorType.ErrorValueIsNullOrEmpty: // Bug G0005
-        return Values.ErrorValueIsNullOrEmpty;
-      default:
-        throw (new ArgumentException("Invalid errortype"));
-    }
-  }
-
-  public static ExcelErrorValue operator +(object v1, ExcelErrorValue v2) {
-    return v2;
-  }
-
-  public static ExcelErrorValue operator +(ExcelErrorValue v1, ExcelErrorValue v2) {
-    return v1;
-  }
-
-  public override int GetHashCode() {
-    return base.GetHashCode();
-  }
-
-  public override bool Equals(object obj) {
-    if (!(obj is ExcelErrorValue value)) {
-      return false;
-    }
-    return value.ToString() == ToString();
-  }
-}
diff --git a/EPPlus/FormulaParsing/Exceptions/CircularReferenceException.cs b/EPPlus/FormulaParsing/Exceptions/CircularReferenceException.cs
deleted file mode 100644
index 90dad5b..0000000
--- a/EPPlus/FormulaParsing/Exceptions/CircularReferenceException.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System;
-
-namespace OfficeOpenXml.FormulaParsing.Exceptions;
-
-public class CircularReferenceException : Exception {
-  public CircularReferenceException(string message)
-      : base(message) {}
-}
diff --git a/EPPlus/FormulaParsing/Exceptions/ExcelErrorCodes.cs b/EPPlus/FormulaParsing/Exceptions/ExcelErrorCodes.cs
deleted file mode 100644
index 9dc8ea4..0000000
--- a/EPPlus/FormulaParsing/Exceptions/ExcelErrorCodes.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-
-namespace OfficeOpenXml.FormulaParsing.Exceptions;
-
-public class ExcelErrorCodes {
-  private ExcelErrorCodes(string code) {
-    Code = code;
-  }
-
-  public string Code { get; private set; }
-
-  public override int GetHashCode() {
-    return Code.GetHashCode();
-  }
-
-  public override bool Equals(object obj) {
-    if (obj is ExcelErrorCodes codes) {
-      return codes.Code.Equals(Code);
-    }
-    return false;
-  }
-
-  public static bool operator ==(ExcelErrorCodes c1, ExcelErrorCodes c2) {
-    return c1.Code.Equals(c2.Code);
-  }
-
-  public static bool operator !=(ExcelErrorCodes c1, ExcelErrorCodes c2) {
-    return !c1.Code.Equals(c2.Code);
-  }
-
-  private static readonly IEnumerable<string> Codes = new List<string> {
-    Value.Code,
-    Name.Code,
-    NoValueAvaliable.Code,
-  };
-
-  public static bool IsErrorCode(object valueToTest) {
-    if (valueToTest == null) {
-      return false;
-    }
-    var candidate = valueToTest.ToString();
-    if (Codes.FirstOrDefault(x => x == candidate) != null) {
-      return true;
-    }
-    return false;
-  }
-
-  public static ExcelErrorCodes Value => new("#VALUE!");
-
-  public static ExcelErrorCodes Name => new("#NAME?");
-
-  public static ExcelErrorCodes NoValueAvaliable => new("#N/A");
-}
diff --git a/EPPlus/FormulaParsing/Exceptions/ExcelErrorValueException.cs b/EPPlus/FormulaParsing/Exceptions/ExcelErrorValueException.cs
deleted file mode 100644
index 4341ed0..0000000
--- a/EPPlus/FormulaParsing/Exceptions/ExcelErrorValueException.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using System;
-
-namespace OfficeOpenXml.FormulaParsing.Exceptions;
-
-/// <summary>
-/// This Exception represents an Excel error. When this exception is thrown
-/// from an Excel function, the ErrorValue code will be set as the value of the
-/// parsed cell.
-/// </summary>
-/// <seealso cref="ExcelErrorValue"/>
-public class ExcelErrorValueException : Exception {
-  public ExcelErrorValueException(ExcelErrorValue error)
-      : this(error.ToString(), error) {}
-
-  public ExcelErrorValueException(string message, ExcelErrorValue error)
-      : base(message) {
-    ErrorValue = error;
-  }
-
-  public ExcelErrorValueException(eErrorType errorType)
-      : this(ExcelErrorValue.Create(errorType)) {}
-
-  /// <summary>
-  /// The error value
-  /// </summary>
-  public ExcelErrorValue ErrorValue { get; private set; }
-}
diff --git a/EPPlus/FormulaParsing/Exceptions/UnrecognizedTokenException.cs b/EPPlus/FormulaParsing/Exceptions/UnrecognizedTokenException.cs
deleted file mode 100644
index f4852c0..0000000
--- a/EPPlus/FormulaParsing/Exceptions/UnrecognizedTokenException.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System;
-using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-
-namespace OfficeOpenXml.FormulaParsing.Exceptions;
-
-public class UnrecognizedTokenException : Exception {
-  public UnrecognizedTokenException(Token token)
-      : base("Unrecognized token: " + token.Value) {}
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/AtomicExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/AtomicExpression.cs
deleted file mode 100644
index 0ad249e..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/AtomicExpression.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public abstract class AtomicExpression : Expression {
-  public AtomicExpression(string expression)
-      : base(expression) {}
-
-  public override bool IsGroupedExpression => false;
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/BooleanExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/BooleanExpression.cs
deleted file mode 100644
index e61bdf6..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/BooleanExpression.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public class BooleanExpression : AtomicExpression {
-  private readonly bool? _precompiledValue;
-
-  public BooleanExpression(string expression)
-      : base(expression) {}
-
-  public BooleanExpression(bool value)
-      : base(value ? "true" : "false") {
-    _precompiledValue = value;
-  }
-
-  public override CompileResult Compile() {
-    var result = _precompiledValue ?? bool.Parse(ExpressionString);
-    return new(result, DataType.Boolean);
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/CompileResult.cs b/EPPlus/FormulaParsing/ExpressionGraph/CompileResult.cs
deleted file mode 100644
index 90693ee..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/CompileResult.cs
+++ /dev/null
@@ -1,115 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System;
-using System.Globalization;
-using System.Linq;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public class CompileResult {
-  private static readonly CompileResult _empty = new(null, DataType.Empty);
-
-  public static CompileResult Empty => _empty;
-
-  public CompileResult(object result, DataType dataType) {
-    Result = result;
-    DataType = dataType;
-  }
-
-  public CompileResult(eErrorType errorType) {
-    Result = ExcelErrorValue.Create(errorType);
-    DataType = DataType.ExcelError;
-  }
-
-  public CompileResult(ExcelErrorValue errorValue) {
-    Require.Argument(errorValue).IsNotNull("errorValue");
-    Result = errorValue;
-    DataType = DataType.ExcelError;
-  }
-
-  public object Result { get; private set; }
-
-  public object ResultValue {
-    get {
-      var r = Result as ExcelDataProvider.IRangeInfo;
-      if (r == null) {
-        return Result;
-      }
-      return r.GetValue(r.Address._fromRow, r.Address._fromCol);
-    }
-  }
-
-  public double ResultNumeric {
-    get {
-      if (IsNumeric) {
-        return Result == null ? 0 : Convert.ToDouble(Result);
-      }
-      if (Result is DateTime time) {
-        return time.ToOADate();
-      }
-      if (Result is TimeSpan span) {
-        return new DateTime(span.Ticks).ToOADate();
-      }
-      if (IsNumericString) {
-        try {
-          return double.Parse(Result.ToString(), NumberStyles.Float, CultureInfo.InvariantCulture);
-        } catch (Exception) {
-          return 0;
-        }
-      }
-      if (Result is ExcelDataProvider.IRangeInfo info) {
-        var c = info.FirstOrDefault();
-        if (c == null) {
-          return 0;
-        }
-        return c.ValueDoubleLogical;
-      }
-      return 0;
-    }
-  }
-
-  public DataType DataType { get; private set; }
-
-  public bool IsNumeric =>
-    DataType == DataType.Decimal
-        || DataType == DataType.Integer
-        || DataType == DataType.Empty
-        || DataType == DataType.Boolean
-        || DataType == DataType.Date;
-
-  public bool IsNumericString => DataType == DataType.String && ConvertUtil.IsNumericString(Result);
-
-  public bool IsResultOfSubtotal { get; set; }
-
-  public bool IsHiddenCell { get; set; }
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/CompileResultFactory.cs b/EPPlus/FormulaParsing/ExpressionGraph/CompileResultFactory.cs
deleted file mode 100644
index 4434031..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/CompileResultFactory.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public class CompileResultFactory {
-  public virtual CompileResult Create(object obj) {
-    if ((obj is ExcelDataProvider.INameInfo info)) {
-      obj = info.Value;
-    }
-    if (obj is ExcelDataProvider.IRangeInfo rangeInfo) {
-      obj = rangeInfo.GetOffset(0, 0);
-    }
-    if (obj == null) {
-      return new(null, DataType.Empty);
-    }
-    if (obj.GetType().Equals(typeof(string))) {
-      return new(obj, DataType.String);
-    }
-    if (obj.GetType().Equals(typeof(double)) || obj is decimal) {
-      return new(obj, DataType.Decimal);
-    }
-    if (obj.GetType().Equals(typeof(int)) || obj is long || obj is short) {
-      return new(obj, DataType.Integer);
-    }
-    if (obj.GetType().Equals(typeof(bool))) {
-      return new(obj, DataType.Boolean);
-    }
-    if (obj.GetType().Equals(typeof(ExcelErrorValue))) {
-      return new(obj, DataType.ExcelError);
-    }
-    if (obj.GetType().Equals(typeof(DateTime))) {
-      return new(((DateTime)obj).ToOADate(), DataType.Date);
-    }
-    throw new ArgumentException("Non supported type " + obj.GetType().FullName);
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/CompileStrategy.cs b/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/CompileStrategy.cs
deleted file mode 100644
index 0eab4ab..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/CompileStrategy.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.CompileStrategy;
-
-public abstract class CompileStrategy {
-  protected readonly Expression _expression;
-
-  public CompileStrategy(Expression expression) {
-    _expression = expression;
-  }
-
-  public abstract Expression Compile();
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/CompileStrategyFactory.cs b/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/CompileStrategyFactory.cs
deleted file mode 100644
index 944a3bf..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/CompileStrategyFactory.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using OfficeOpenXml.FormulaParsing.Excel.Operators;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.CompileStrategy;
-
-public class CompileStrategyFactory : ICompileStrategyFactory {
-  public CompileStrategy Create(Expression expression) {
-    if (expression.Operator.Operator == Operators.Concat) {
-      return new StringConcatStrategy(expression);
-    }
-    return new DefaultCompileStrategy(expression);
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/DefaultCompileStrategy.cs b/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/DefaultCompileStrategy.cs
deleted file mode 100644
index 27475d1..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/DefaultCompileStrategy.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.CompileStrategy;
-
-public class DefaultCompileStrategy : CompileStrategy {
-  public DefaultCompileStrategy(Expression expression)
-      : base(expression) {}
-
-  public override Expression Compile() {
-    return _expression.MergeWithNext();
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/ICompileStrategyFactory.cs b/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/ICompileStrategyFactory.cs
deleted file mode 100644
index 16a53a4..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/ICompileStrategyFactory.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.CompileStrategy;
-
-public interface ICompileStrategyFactory {
-  CompileStrategy Create(Expression expression);
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/StringConcatStrategy.cs b/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/StringConcatStrategy.cs
deleted file mode 100644
index 4403ab8..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/StringConcatStrategy.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.CompileStrategy;
-
-public class StringConcatStrategy : CompileStrategy {
-  public StringConcatStrategy(Expression expression)
-      : base(expression) {}
-
-  public override Expression Compile() {
-    var newExp =
-        _expression is ExcelAddressExpression
-            ? _expression
-            : ExpressionConverter.Instance.ToStringExpression(_expression);
-    newExp.Prev = _expression.Prev;
-    newExp.Next = _expression.Next;
-    if (_expression.Prev != null) {
-      _expression.Prev.Next = newExp;
-    }
-    if (_expression.Next != null) {
-      _expression.Next.Prev = newExp;
-    }
-    return newExp.MergeWithNext();
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/ConstantExpressions.cs b/EPPlus/FormulaParsing/ExpressionGraph/ConstantExpressions.cs
deleted file mode 100644
index 00fe9c6..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/ConstantExpressions.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public static class ConstantExpressions {
-  public static Expression Percent {
-    get { return new ConstantExpression("Percent", () => new(0.01, DataType.Decimal)); }
-  }
-}
-
-public class ConstantExpression : AtomicExpression {
-  private readonly Func<CompileResult> _factoryMethod;
-
-  public ConstantExpression(string title, Func<CompileResult> factoryMethod)
-      : base(title) {
-    _factoryMethod = factoryMethod;
-  }
-
-  public override CompileResult Compile() {
-    return _factoryMethod();
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/DataType.cs b/EPPlus/FormulaParsing/ExpressionGraph/DataType.cs
deleted file mode 100644
index 4751df3..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/DataType.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public enum DataType {
-  Integer,
-  Decimal,
-  String,
-  Boolean,
-  Date,
-  Time,
-  Enumerable,
-  LookupArray,
-  ExcelAddress,
-  ExcelError,
-  Empty,
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/DateExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/DateExpression.cs
deleted file mode 100644
index 12e9342..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/DateExpression.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System;
-using System.Globalization;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public class DateExpression : AtomicExpression {
-  public DateExpression(string expression)
-      : base(expression) {}
-
-  public override CompileResult Compile() {
-    var date = double.Parse(ExpressionString, CultureInfo.InvariantCulture);
-    return new(DateTime.FromOADate(date), DataType.Date);
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/DecimalExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/DecimalExpression.cs
deleted file mode 100644
index 9d82c5a..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/DecimalExpression.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-using System.Globalization;
-
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public class DecimalExpression : AtomicExpression {
-  private readonly double? _compiledValue;
-  private readonly bool _negate;
-
-  public DecimalExpression(string expression)
-      : this(expression, false) {}
-
-  public DecimalExpression(string expression, bool negate)
-      : base(expression) {
-    _negate = negate;
-  }
-
-  public DecimalExpression(double compiledValue)
-      : base(compiledValue.ToString(CultureInfo.InvariantCulture)) {
-    _compiledValue = compiledValue;
-  }
-
-  public override CompileResult Compile() {
-    double result = _compiledValue ?? double.Parse(ExpressionString, CultureInfo.InvariantCulture);
-    result = _negate ? result * -1 : result;
-    return new(result, DataType.Decimal);
-  }
-
-  public bool IsNegated => _negate;
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/EnumerableExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/EnumerableExpression.cs
deleted file mode 100644
index 56b0fa8..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/EnumerableExpression.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public class EnumerableExpression : Expression {
-  public EnumerableExpression()
-      : this(new ExpressionCompiler()) {}
-
-  public EnumerableExpression(IExpressionCompiler expressionCompiler) {
-    _expressionCompiler = expressionCompiler;
-  }
-
-  private readonly IExpressionCompiler _expressionCompiler;
-
-  public override bool IsGroupedExpression => false;
-
-  public override Expression PrepareForNextChild() {
-    return this;
-  }
-
-  public override CompileResult Compile() {
-    var result = new List<object>();
-    foreach (var childExpression in Children) {
-      result.Add(_expressionCompiler.Compile(new List<Expression> { childExpression }).Result);
-    }
-    return new(result, DataType.Enumerable);
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/ExcelAddressExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/ExcelAddressExpression.cs
deleted file mode 100644
index 8e409b7..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/ExcelAddressExpression.cs
+++ /dev/null
@@ -1,111 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExcelUtilities;
-using OfficeOpenXml.FormulaParsing.Utilities;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public class ExcelAddressExpression : AtomicExpression {
-  private readonly ExcelDataProvider _excelDataProvider;
-  private readonly ParsingContext _parsingContext;
-  private readonly RangeAddressFactory _rangeAddressFactory;
-  private readonly bool _negate;
-
-  public ExcelAddressExpression(
-      string expression,
-      ExcelDataProvider excelDataProvider,
-      ParsingContext parsingContext)
-      : this(expression, excelDataProvider, parsingContext, new(excelDataProvider), false) {}
-
-  public ExcelAddressExpression(
-      string expression,
-      ExcelDataProvider excelDataProvider,
-      ParsingContext parsingContext,
-      bool negate)
-      : this(expression, excelDataProvider, parsingContext, new(excelDataProvider), negate) {}
-
-  public ExcelAddressExpression(
-      string expression,
-      ExcelDataProvider excelDataProvider,
-      ParsingContext parsingContext,
-      RangeAddressFactory rangeAddressFactory,
-      bool negate)
-      : base(expression) {
-    Require.That(excelDataProvider).Named("excelDataProvider").IsNotNull();
-    Require.That(parsingContext).Named("parsingContext").IsNotNull();
-    Require.That(rangeAddressFactory).Named("rangeAddressFactory").IsNotNull();
-    _excelDataProvider = excelDataProvider;
-    _parsingContext = parsingContext;
-    _rangeAddressFactory = rangeAddressFactory;
-    _negate = negate;
-  }
-
-  public override bool IsGroupedExpression => false;
-
-  public override CompileResult Compile() {
-    if (ParentIsLookupFunction) {
-      return new(ExpressionString, DataType.ExcelAddress);
-    }
-    return CompileRangeValues();
-  }
-
-  private CompileResult CompileRangeValues() {
-    var c = _parsingContext.Scopes.Current;
-    var result = _excelDataProvider.GetRange(
-        c.Address.Worksheet,
-        c.Address.FromRow,
-        c.Address.FromCol,
-        ExpressionString);
-
-    if (result == null || result.IsEmpty) {
-      return CompileResult.Empty;
-    }
-    if (result.Address.Rows > 1 || result.Address.Columns > 1) {
-      return new(result, DataType.Enumerable);
-    }
-    return CompileSingleCell(result);
-  }
-
-  private CompileResult CompileSingleCell(ExcelDataProvider.IRangeInfo result) {
-    var cell = result.First();
-    var factory = new CompileResultFactory();
-    var compileResult = factory.Create(cell.Value);
-    if (_negate && compileResult.IsNumeric) {
-      compileResult = new(compileResult.ResultNumeric * -1, compileResult.DataType);
-    }
-    compileResult.IsHiddenCell = cell.IsHiddenRow;
-    return compileResult;
-  }
-
-  public bool IsNegated => _negate;
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/ExcelErrorExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/ExcelErrorExpression.cs
deleted file mode 100644
index 44770f8..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/ExcelErrorExpression.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public class ExcelErrorExpression : Expression {
-  private readonly ExcelErrorValue _error;
-
-  public ExcelErrorExpression(string expression, ExcelErrorValue error)
-      : base(expression) {
-    _error = error;
-  }
-
-  public ExcelErrorExpression(ExcelErrorValue error)
-      : this(error.ToString(), error) {}
-
-  public override bool IsGroupedExpression => false;
-
-  public override CompileResult Compile() {
-    return new(_error, DataType.ExcelError);
-    //if (ParentIsLookupFunction)
-    //{
-    //    return new CompileResult(ExpressionString, DataType.ExcelError);
-    //}
-    //else
-    //{
-    //    return CompileRangeValues();
-    //}
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/Expression.cs b/EPPlus/FormulaParsing/ExpressionGraph/Expression.cs
deleted file mode 100644
index bdab90a..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/Expression.cs
+++ /dev/null
@@ -1,109 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.Excel.Operators;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public abstract class Expression {
-  public string ExpressionString { get; private set; }
-
-  private readonly List<Expression> _children = new();
-
-  public IEnumerable<Expression> Children => _children;
-
-  public Expression Next { get; set; }
-
-  public Expression Prev { get; set; }
-
-  public IOperator Operator { get; set; }
-
-  public abstract bool IsGroupedExpression { get; }
-
-  public Expression() {}
-
-  public Expression(string expression) {
-    ExpressionString = expression;
-    Operator = null;
-  }
-
-  public virtual bool ParentIsLookupFunction { get; set; }
-
-  public virtual bool HasChildren => _children.Any();
-
-  public virtual Expression PrepareForNextChild() {
-    return this;
-  }
-
-  public virtual Expression AddChild(Expression child) {
-    if (_children.Any()) {
-      var last = _children.Last();
-      child.Prev = last;
-      last.Next = child;
-    }
-    _children.Add(child);
-    return child;
-  }
-
-  public virtual Expression MergeWithNext() {
-    Expression expression;
-    if (Next != null && Operator != null) {
-      var result = Operator.Apply(Compile(), Next.Compile());
-      expression = ExpressionConverter.Instance.FromCompileResult(result);
-      if (expression is ExcelErrorExpression) {
-        expression.Next = null;
-        expression.Prev = null;
-        return expression;
-      }
-      if (Next != null) {
-        expression.Operator = Next.Operator;
-      } else {
-        expression.Operator = null;
-      }
-      expression.Next = Next.Next;
-      if (expression.Next != null) {
-        expression.Next.Prev = expression;
-      }
-      expression.Prev = Prev;
-    } else {
-      throw (new FormatException("Invalid formula syntax. Operator missing expression."));
-    }
-    if (Prev != null) {
-      Prev.Next = expression;
-    }
-    return expression;
-  }
-
-  public abstract CompileResult Compile();
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/ExpressionCompiler.cs b/EPPlus/FormulaParsing/ExpressionGraph/ExpressionCompiler.cs
deleted file mode 100644
index e29c4f2..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/ExpressionCompiler.cs
+++ /dev/null
@@ -1,145 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph.CompileStrategy;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public class ExpressionCompiler : IExpressionCompiler {
-  private IEnumerable<Expression> _expressions;
-  private readonly IExpressionConverter _expressionConverter;
-  private readonly ICompileStrategyFactory _compileStrategyFactory;
-
-  public ExpressionCompiler()
-      : this(new ExpressionConverter(), new CompileStrategyFactory()) {}
-
-  public ExpressionCompiler(
-      IExpressionConverter expressionConverter,
-      ICompileStrategyFactory compileStrategyFactory) {
-    _expressionConverter = expressionConverter;
-    _compileStrategyFactory = compileStrategyFactory;
-  }
-
-  public CompileResult Compile(IEnumerable<Expression> expressions) {
-    _expressions = expressions;
-    return PerformCompilation();
-  }
-
-  public CompileResult Compile(
-      string worksheet,
-      int row,
-      int column,
-      IEnumerable<Expression> expressions) {
-    _expressions = expressions;
-    return PerformCompilation(worksheet, row, column);
-  }
-
-  private CompileResult PerformCompilation(string worksheet = "", int row = -1, int column = -1) {
-    var compiledExpressions = HandleGroupedExpressions();
-    while (compiledExpressions.Any(x => x.Operator != null)) {
-      var prec = FindLowestPrecedence();
-      compiledExpressions = HandlePrecedenceLevel(prec);
-    }
-    if (_expressions.Any()) {
-      return compiledExpressions.First().Compile();
-    }
-    return CompileResult.Empty;
-  }
-
-  private IEnumerable<Expression> HandleGroupedExpressions() {
-    if (!_expressions.Any()) {
-      return Enumerable.Empty<Expression>();
-    }
-    var first = _expressions.First();
-    var groupedExpressions = _expressions.Where(x => x.IsGroupedExpression);
-    foreach (var groupedExpression in groupedExpressions) {
-      var result = groupedExpression.Compile();
-      if (result == CompileResult.Empty) {
-        continue;
-      }
-      var newExp = _expressionConverter.FromCompileResult(result);
-      newExp.Operator = groupedExpression.Operator;
-      newExp.Prev = groupedExpression.Prev;
-      newExp.Next = groupedExpression.Next;
-      if (groupedExpression.Prev != null) {
-        groupedExpression.Prev.Next = newExp;
-      }
-      if (groupedExpression.Next != null) {
-        groupedExpression.Next.Prev = newExp;
-      }
-      if (groupedExpression == first) {
-        first = newExp;
-      }
-    }
-    return RefreshList(first);
-  }
-
-  private IEnumerable<Expression> HandlePrecedenceLevel(int precedence) {
-    var first = _expressions.First();
-    var expressionsToHandle = _expressions.Where(x =>
-        x.Operator != null && x.Operator.Precedence == precedence);
-    var last = expressionsToHandle.Last();
-    var expression = expressionsToHandle.First();
-    do {
-      var strategy = _compileStrategyFactory.Create(expression);
-      var compiledExpression = strategy.Compile();
-      if (compiledExpression is ExcelErrorExpression) {
-        return RefreshList(compiledExpression);
-      }
-      if (expression == first) {
-        first = compiledExpression;
-      }
-
-      expression = compiledExpression;
-    } while (expression != null
-            && expression.Operator != null
-            && expression.Operator.Precedence == precedence);
-    return RefreshList(first);
-  }
-
-  private int FindLowestPrecedence() {
-    return _expressions.Where(x => x.Operator != null).Min(x => x.Operator.Precedence);
-  }
-
-  private IEnumerable<Expression> RefreshList(Expression first) {
-    var resultList = new List<Expression>();
-    var exp = first;
-    resultList.Add(exp);
-    while (exp.Next != null) {
-      resultList.Add(exp.Next);
-      exp = exp.Next;
-    }
-    _expressions = resultList;
-    return resultList;
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/ExpressionConverter.cs b/EPPlus/FormulaParsing/ExpressionGraph/ExpressionConverter.cs
deleted file mode 100644
index 339b757..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/ExpressionConverter.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public class ExpressionConverter : IExpressionConverter {
-  public StringExpression ToStringExpression(Expression expression) {
-    var result = expression.Compile();
-    var newExp = new StringExpression(result.Result.ToString());
-    newExp.Operator = expression.Operator;
-    return newExp;
-  }
-
-  public Expression FromCompileResult(CompileResult compileResult) {
-    switch (compileResult.DataType) {
-      case DataType.Integer:
-        return compileResult.Result is string
-            ? new(compileResult.Result.ToString())
-            : new IntegerExpression(Convert.ToDouble(compileResult.Result));
-      case DataType.String:
-        return new StringExpression(compileResult.Result.ToString());
-      case DataType.Decimal:
-        return compileResult.Result is string
-            ? new(compileResult.Result.ToString())
-            : new DecimalExpression(((double)compileResult.Result));
-      case DataType.Boolean:
-        return compileResult.Result is string
-            ? new(compileResult.Result.ToString())
-            : new BooleanExpression((bool)compileResult.Result);
-      //case DataType.Enumerable:
-      //    return
-      case DataType.ExcelError:
-        //throw (new OfficeOpenXml.FormulaParsing.Exceptions.ExcelErrorValueException((ExcelErrorValue)compileResult.Result)); //Added JK
-        return compileResult.Result is string
-            ? new(
-                compileResult.Result.ToString(),
-                ExcelErrorValue.Parse(compileResult.Result.ToString()))
-            : new ExcelErrorExpression((ExcelErrorValue)compileResult.Result);
-      case DataType.Empty:
-        return new IntegerExpression(0); //Added JK
-    }
-    return null;
-  }
-
-  private static IExpressionConverter _instance;
-
-  public static IExpressionConverter Instance {
-    get {
-      if (_instance == null) {
-        _instance = new ExpressionConverter();
-      }
-      return _instance;
-    }
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/ExpressionFactory.cs b/EPPlus/FormulaParsing/ExpressionGraph/ExpressionFactory.cs
deleted file mode 100644
index 742d50c..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/ExpressionFactory.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public class ExpressionFactory : IExpressionFactory {
-  private readonly ExcelDataProvider _excelDataProvider;
-  private readonly ParsingContext _parsingContext;
-
-  public ExpressionFactory(ExcelDataProvider excelDataProvider, ParsingContext context) {
-    _excelDataProvider = excelDataProvider;
-    _parsingContext = context;
-  }
-
-  public Expression Create(Token token) {
-    switch (token.TokenType) {
-      case TokenType.Integer:
-        return new IntegerExpression(token.Value, token.IsNegated);
-      case TokenType.String:
-        return new StringExpression(token.Value);
-      case TokenType.Decimal:
-        return new DecimalExpression(token.Value, token.IsNegated);
-      case TokenType.Boolean:
-        return new BooleanExpression(token.Value);
-      case TokenType.ExcelAddress:
-        return new ExcelAddressExpression(
-            token.Value,
-            _excelDataProvider,
-            _parsingContext,
-            token.IsNegated);
-      case TokenType.InvalidReference:
-        return new ExcelErrorExpression(token.Value, ExcelErrorValue.Create(eErrorType.Ref));
-      case TokenType.NumericError:
-        return new ExcelErrorExpression(token.Value, ExcelErrorValue.Create(eErrorType.Num));
-      case TokenType.ValueDataTypeError:
-        return new ExcelErrorExpression(token.Value, ExcelErrorValue.Create(eErrorType.Value));
-      case TokenType.Null:
-        return new ExcelErrorExpression(token.Value, ExcelErrorValue.Create(eErrorType.Null));
-      case TokenType.NameValue:
-        return new NamedValueExpression(token.Value, _parsingContext);
-      default:
-        return new StringExpression(token.Value);
-    }
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/ExpressionGraph.cs b/EPPlus/FormulaParsing/ExpressionGraph/ExpressionGraph.cs
deleted file mode 100644
index 98fe430..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/ExpressionGraph.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public class ExpressionGraph {
-  private readonly List<Expression> _expressions = new();
-
-  public IEnumerable<Expression> Expressions => _expressions;
-
-  public Expression Current { get; private set; }
-
-  public Expression Add(Expression expression) {
-    _expressions.Add(expression);
-    if (Current != null) {
-      Current.Next = expression;
-      expression.Prev = Current;
-    }
-    Current = expression;
-    return expression;
-  }
-
-  public void Reset() {
-    _expressions.Clear();
-    Current = null;
-  }
-
-  public void Remove(Expression item) {
-    if (item == Current) {
-      Current = item.Prev ?? item.Next;
-    }
-    _expressions.Remove(item);
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/ExpressionGraphBuilder.cs b/EPPlus/FormulaParsing/ExpressionGraph/ExpressionGraphBuilder.cs
deleted file mode 100644
index 156b425..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/ExpressionGraphBuilder.cs
+++ /dev/null
@@ -1,196 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.Excel.Operators;
-using OfficeOpenXml.FormulaParsing.Exceptions;
-using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public class ExpressionGraphBuilder : IExpressionGraphBuilder {
-  private readonly ExpressionGraph _graph = new();
-  private readonly IExpressionFactory _expressionFactory;
-  private readonly ParsingContext _parsingContext;
-  private int _tokenIndex;
-  private bool _negateNextExpression;
-
-  public ExpressionGraphBuilder(ExcelDataProvider excelDataProvider, ParsingContext parsingContext)
-      : this(new ExpressionFactory(excelDataProvider, parsingContext), parsingContext) {}
-
-  public ExpressionGraphBuilder(
-      IExpressionFactory expressionFactory,
-      ParsingContext parsingContext) {
-    _expressionFactory = expressionFactory;
-    _parsingContext = parsingContext;
-  }
-
-  public ExpressionGraph Build(IEnumerable<Token> tokens) {
-    _tokenIndex = 0;
-    _graph.Reset();
-    var tokensArr = tokens != null ? tokens.ToArray() : new Token[0];
-    BuildUp(tokensArr, null);
-    return _graph;
-  }
-
-  private void BuildUp(Token[] tokens, Expression parent) {
-    while (_tokenIndex < tokens.Length) {
-      var token = tokens[_tokenIndex];
-      if (token.TokenType == TokenType.Operator
-          && OperatorsDict.Instance.TryGetValue(token.Value, out var op)) {
-        SetOperatorOnExpression(parent, op);
-      } else if (token.TokenType == TokenType.Function) {
-        BuildFunctionExpression(tokens, parent, token.Value);
-      } else if (token.TokenType == TokenType.OpeningEnumerable) {
-        _tokenIndex++;
-        BuildEnumerableExpression(tokens, parent);
-      } else if (token.TokenType == TokenType.OpeningParenthesis) {
-        _tokenIndex++;
-        BuildGroupExpression(tokens, parent);
-        //if (parent is FunctionExpression)
-        //{
-        //    return;
-        //}
-      } else if (token.TokenType == TokenType.ClosingParenthesis
-          || token.TokenType == TokenType.ClosingEnumerable) {
-        break;
-      } else if (token.TokenType == TokenType.Negator) {
-        _negateNextExpression = true;
-      } else if (token.TokenType == TokenType.Percent) {
-        SetOperatorOnExpression(parent, Operator.Percent);
-        if (parent == null) {
-          _graph.Add(ConstantExpressions.Percent);
-        } else {
-          parent.AddChild(ConstantExpressions.Percent);
-        }
-      } else {
-        CreateAndAppendExpression(ref parent, token);
-      }
-      _tokenIndex++;
-    }
-  }
-
-  private void BuildEnumerableExpression(Token[] tokens, Expression parent) {
-    if (parent == null) {
-      _graph.Add(new EnumerableExpression());
-      BuildUp(tokens, _graph.Current);
-    } else {
-      var enumerableExpression = new EnumerableExpression();
-      parent.AddChild(enumerableExpression);
-      BuildUp(tokens, enumerableExpression);
-    }
-  }
-
-  private void CreateAndAppendExpression(ref Expression parent, Token token) {
-    if (IsWaste(token)) {
-      return;
-    }
-    if (parent != null
-        && (token.TokenType == TokenType.Comma || token.TokenType == TokenType.SemiColon)) {
-      parent = parent.PrepareForNextChild();
-      return;
-    }
-    if (_negateNextExpression) {
-      token.Negate();
-      _negateNextExpression = false;
-    }
-    var expression = _expressionFactory.Create(token);
-    if (parent == null) {
-      _graph.Add(expression);
-    } else {
-      parent.AddChild(expression);
-    }
-  }
-
-  private bool IsWaste(Token token) {
-    if (token.TokenType == TokenType.String) {
-      return true;
-    }
-    return false;
-  }
-
-  private void BuildFunctionExpression(Token[] tokens, Expression parent, string funcName) {
-    if (parent == null) {
-      _graph.Add(new FunctionExpression(funcName, _parsingContext, _negateNextExpression));
-      _negateNextExpression = false;
-      HandleFunctionArguments(tokens, _graph.Current);
-    } else {
-      var func = new FunctionExpression(funcName, _parsingContext, _negateNextExpression);
-      _negateNextExpression = false;
-      parent.AddChild(func);
-      HandleFunctionArguments(tokens, func);
-    }
-  }
-
-  private void HandleFunctionArguments(Token[] tokens, Expression function) {
-    _tokenIndex++;
-    var token = tokens.ElementAt(_tokenIndex);
-    if (token.TokenType != TokenType.OpeningParenthesis) {
-      throw new ExcelErrorValueException(eErrorType.Value);
-    }
-    _tokenIndex++;
-    BuildUp(tokens, function.Children.First());
-  }
-
-  private void BuildGroupExpression(Token[] tokens, Expression parent) {
-    if (parent == null) {
-      _graph.Add(new GroupExpression(_negateNextExpression));
-      _negateNextExpression = false;
-      BuildUp(tokens, _graph.Current);
-    } else {
-      if (parent.IsGroupedExpression || parent is FunctionArgumentExpression) {
-        var newGroupExpression = new GroupExpression(_negateNextExpression);
-        _negateNextExpression = false;
-        parent.AddChild(newGroupExpression);
-        BuildUp(tokens, newGroupExpression);
-      }
-      BuildUp(tokens, parent);
-    }
-  }
-
-  private void SetOperatorOnExpression(Expression parent, IOperator op) {
-    if (parent == null) {
-      _graph.Current.Operator = op;
-    } else {
-      Expression candidate;
-      if (parent is FunctionArgumentExpression) {
-        candidate = parent.Children.Last();
-      } else {
-        candidate = parent.Children.Last();
-        if (candidate is FunctionArgumentExpression) {
-          candidate = candidate.Children.Last();
-        }
-      }
-      candidate.Operator = op;
-    }
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/FunctionArgumentExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/FunctionArgumentExpression.cs
deleted file mode 100644
index 0123e1d..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/FunctionArgumentExpression.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public class FunctionArgumentExpression : GroupExpression {
-  private readonly Expression _function;
-
-  public FunctionArgumentExpression(Expression function)
-      : base(false) {
-    _function = function;
-  }
-
-  public override bool ParentIsLookupFunction {
-    get => base.ParentIsLookupFunction;
-    set {
-      base.ParentIsLookupFunction = value;
-      foreach (var child in Children) {
-        child.ParentIsLookupFunction = value;
-      }
-    }
-  }
-
-  public override bool IsGroupedExpression => false;
-
-  public override Expression PrepareForNextChild() {
-    return _function.PrepareForNextChild();
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/DefaultCompiler.cs b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/DefaultCompiler.cs
deleted file mode 100644
index ebc2918..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/DefaultCompiler.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.Excel;
-using OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers;
-
-public class DefaultCompiler : FunctionCompiler {
-  public DefaultCompiler(ExcelFunction function)
-      : base(function) {}
-
-  public override CompileResult Compile(IEnumerable<Expression> children, ParsingContext context) {
-    var args = new List<FunctionArgument>();
-    Function.BeforeInvoke(context);
-    foreach (var child in children) {
-      var compileResult = child.Compile();
-      if (compileResult.IsResultOfSubtotal) {
-        var arg = new FunctionArgument(compileResult.Result);
-        arg.SetExcelStateFlag(ExcelCellState.IsResultOfSubtotal);
-        args.Add(arg);
-      } else {
-        BuildFunctionArguments(compileResult.Result, args);
-      }
-    }
-    return Function.Execute(args, context);
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/ErrorHandlingFunctionCompiler.cs b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/ErrorHandlingFunctionCompiler.cs
deleted file mode 100644
index f93b6ce..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/ErrorHandlingFunctionCompiler.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.Excel.Functions;
-using OfficeOpenXml.FormulaParsing.Exceptions;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers;
-
-public class ErrorHandlingFunctionCompiler : FunctionCompiler {
-  public ErrorHandlingFunctionCompiler(ExcelFunction function)
-      : base(function) {}
-
-  public override CompileResult Compile(IEnumerable<Expression> children, ParsingContext context) {
-    var args = new List<FunctionArgument>();
-    Function.BeforeInvoke(context);
-    foreach (var child in children) {
-      try {
-        var arg = child.Compile();
-        BuildFunctionArguments(arg?.Result, args);
-      } catch (ExcelErrorValueException efe) {
-        return ((ErrorHandlingFunction)Function).HandleError(efe.ErrorValue.ToString());
-      } catch // (Exception e)
-      {
-        return ((ErrorHandlingFunction)Function).HandleError(ExcelErrorValue.Values.Value);
-      }
-    }
-    return Function.Execute(args, context);
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/FunctionCompiler.cs b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/FunctionCompiler.cs
deleted file mode 100644
index 8be6020..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/FunctionCompiler.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.Excel.Functions;
-using OfficeOpenXml.FormulaParsing.Utilities;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers;
-
-public abstract class FunctionCompiler {
-  protected ExcelFunction Function { get; private set; }
-
-  public FunctionCompiler(ExcelFunction function) {
-    Require.That(function).Named("function").IsNotNull();
-    Function = function;
-  }
-
-  protected void BuildFunctionArguments(object result, List<FunctionArgument> args) {
-    if (result is IEnumerable<object> objects && !(objects is ExcelDataProvider.IRangeInfo)) {
-      var argList = new List<FunctionArgument>();
-      foreach (var arg in objects) {
-        BuildFunctionArguments(arg, argList);
-      }
-      args.Add(new(argList));
-    } else {
-      args.Add(new(result));
-    }
-  }
-
-  public abstract CompileResult Compile(IEnumerable<Expression> children, ParsingContext context);
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/FunctionCompilerFactory.cs b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/FunctionCompilerFactory.cs
deleted file mode 100644
index 0f54dcc..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/FunctionCompilerFactory.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.Excel.Functions;
-using OfficeOpenXml.FormulaParsing.Excel.Functions.Logical;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers;
-
-public class FunctionCompilerFactory {
-  private readonly Dictionary<Type, FunctionCompiler> _specialCompilers = new();
-
-  public FunctionCompilerFactory(FunctionRepository repository) {
-    _specialCompilers.Add(typeof(If), new IfFunctionCompiler(repository.GetFunction("if")));
-    _specialCompilers.Add(
-        typeof(IfError),
-        new IfErrorFunctionCompiler(repository.GetFunction("iferror")));
-    _specialCompilers.Add(typeof(IfNa), new IfNaFunctionCompiler(repository.GetFunction("ifna")));
-  }
-
-  private FunctionCompiler GetCompilerByType(ExcelFunction function) {
-    var funcType = function.GetType();
-    if (_specialCompilers.ContainsKey(funcType)) {
-      return _specialCompilers[funcType];
-    }
-    return new DefaultCompiler(function);
-  }
-
-  public virtual FunctionCompiler Create(ExcelFunction function) {
-    if (function.IsLookupFuction) {
-      return new LookupFunctionCompiler(function);
-    }
-    if (function.IsErrorHandlingFunction) {
-      return new ErrorHandlingFunctionCompiler(function);
-    }
-    return GetCompilerByType(function);
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfErrorFunctionCompiler.cs b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfErrorFunctionCompiler.cs
deleted file mode 100644
index e809ea5..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfErrorFunctionCompiler.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.Excel.Functions;
-using OfficeOpenXml.FormulaParsing.Exceptions;
-using OfficeOpenXml.FormulaParsing.Utilities;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers;
-
-public class IfErrorFunctionCompiler : FunctionCompiler {
-  public IfErrorFunctionCompiler(ExcelFunction function)
-      : base(function) {
-    Require.That(function).Named("function").IsNotNull();
-  }
-
-  public override CompileResult Compile(IEnumerable<Expression> children, ParsingContext context) {
-    if (children.Count() != 2) {
-      throw new ExcelErrorValueException(eErrorType.Value);
-    }
-    var args = new List<FunctionArgument>();
-    Function.BeforeInvoke(context);
-    var firstChild = children.First();
-    var lastChild = children.ElementAt(1);
-    try {
-      var result = firstChild.Compile();
-      if (result.DataType == DataType.ExcelError) {
-        args.Add(new(lastChild.Compile().Result));
-      } else {
-        args.Add(new(result.Result));
-      }
-    } catch (ExcelErrorValueException) {
-      args.Add(new(lastChild.Compile().Result));
-    }
-    return Function.Execute(args, context);
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfFunctionCompiler.cs b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfFunctionCompiler.cs
deleted file mode 100644
index 15d262b..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfFunctionCompiler.cs
+++ /dev/null
@@ -1,103 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2014-01-27
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.Excel.Functions;
-using OfficeOpenXml.FormulaParsing.Excel.Functions.Logical;
-using OfficeOpenXml.FormulaParsing.Exceptions;
-using OfficeOpenXml.FormulaParsing.Utilities;
-using OfficeOpenXml.Utils;
-using Require = OfficeOpenXml.FormulaParsing.Utilities.Require;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers;
-
-/// <summary>
-/// Why do the If function require a compiler of its own you might ask;)
-///
-/// It is because it only needs to evaluate one of the two last expressions. This
-/// compiler handles this - it ignores the irrelevant expression.
-/// </summary>
-public class IfFunctionCompiler : FunctionCompiler {
-  public IfFunctionCompiler(ExcelFunction function)
-      : base(function) {
-    Require.That(function).Named("function").IsNotNull();
-    if (!(function is If)) {
-      throw new ArgumentException("function must be of type If");
-    }
-  }
-
-  public override CompileResult Compile(IEnumerable<Expression> children, ParsingContext context) {
-    if (children.Count() < 3) {
-      throw new ExcelErrorValueException(eErrorType.Value);
-    }
-    var args = new List<FunctionArgument>();
-    Function.BeforeInvoke(context);
-    var firstChild = children.ElementAt(0);
-    var v = firstChild.Compile().Result;
-
-    /****  Handle names and ranges ****/
-    if (v is ExcelDataProvider.INameInfo info) {
-      v = info.Value;
-    }
-
-    if (v is ExcelDataProvider.IRangeInfo rangeInfo) {
-      if (rangeInfo.GetNCells() > 1) {
-        throw (new ArgumentException("Logical can't be more than one cell"));
-      }
-      v = rangeInfo.GetOffset(0, 0);
-    }
-    bool boolVal;
-    if (v is bool b) {
-      boolVal = b;
-    } else {
-      if (ConvertUtil.IsNumeric(v)) {
-        boolVal = ConvertUtil.GetValueDouble(v) != 0;
-      } else {
-        throw (new ArgumentException("Invalid logical test"));
-      }
-    }
-    /****  End Handle names and ranges ****/
-
-    args.Add(new(boolVal));
-    if (boolVal) {
-      var val = children.ElementAt(1).Compile().Result;
-      args.Add(new(val));
-      args.Add(new(null));
-    } else {
-      var val = children.ElementAt(2).Compile().Result;
-      args.Add(new(null));
-      args.Add(new(val));
-    }
-    return Function.Execute(args, context);
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfNaFunctionCompiler.cs b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfNaFunctionCompiler.cs
deleted file mode 100644
index 55f15b2..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfNaFunctionCompiler.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.Excel.Functions;
-using OfficeOpenXml.FormulaParsing.Exceptions;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers;
-
-public class IfNaFunctionCompiler : FunctionCompiler {
-  public IfNaFunctionCompiler(ExcelFunction function)
-      : base(function) {}
-
-  public override CompileResult Compile(IEnumerable<Expression> children, ParsingContext context) {
-    if (children.Count() != 2) {
-      throw new ExcelErrorValueException(eErrorType.Value);
-    }
-    var args = new List<FunctionArgument>();
-    Function.BeforeInvoke(context);
-    var firstChild = children.First();
-    var lastChild = children.ElementAt(1);
-    try {
-      var result = firstChild.Compile();
-      if (result.DataType == DataType.ExcelError
-          && (Equals(result.Result, ExcelErrorValue.Create(eErrorType.Na)))) {
-        args.Add(new(lastChild.Compile().Result));
-      } else {
-        args.Add(new(result.Result));
-      }
-    } catch (ExcelErrorValueException) {
-      args.Add(new(lastChild.Compile().Result));
-    }
-    return Function.Execute(args, context);
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/LookupFunctionCompiler.cs b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/LookupFunctionCompiler.cs
deleted file mode 100644
index de672c1..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/LookupFunctionCompiler.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers;
-
-public class LookupFunctionCompiler : FunctionCompiler {
-  public LookupFunctionCompiler(ExcelFunction function)
-      : base(function) {}
-
-  public override CompileResult Compile(IEnumerable<Expression> children, ParsingContext context) {
-    var args = new List<FunctionArgument>();
-    Function.BeforeInvoke(context);
-    var firstChild = true;
-    foreach (var child in children) {
-      if (!firstChild || Function.SkipArgumentEvaluation) {
-        child.ParentIsLookupFunction = Function.IsLookupFuction;
-      } else {
-        firstChild = false;
-      }
-      var arg = child.Compile();
-      BuildFunctionArguments(arg?.Result, args);
-    }
-    return Function.Execute(args, context);
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/FunctionExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/FunctionExpression.cs
deleted file mode 100644
index 0f39bd5..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/FunctionExpression.cs
+++ /dev/null
@@ -1,110 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.Exceptions;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-/// <summary>
-/// Expression that handles execution of a function.
-/// </summary>
-public class FunctionExpression : AtomicExpression {
-  /// <summary>
-  /// Constructor
-  /// </summary>
-  /// <param name="expression">should be the of the function</param>
-  /// <param name="parsingContext"></param>
-  /// <param name="isNegated">True if the numeric result of the function should be negated.</param>
-  public FunctionExpression(string expression, ParsingContext parsingContext, bool isNegated)
-      : base(expression) {
-    _parsingContext = parsingContext;
-    _functionCompilerFactory = new(parsingContext.Configuration.FunctionRepository);
-    _isNegated = isNegated;
-    base.AddChild(new FunctionArgumentExpression(this));
-  }
-
-  private readonly ParsingContext _parsingContext;
-  private readonly FunctionCompilerFactory _functionCompilerFactory;
-  private readonly bool _isNegated;
-
-  public override CompileResult Compile() {
-    try {
-      var function = _parsingContext.Configuration.FunctionRepository.GetFunction(ExpressionString);
-      if (function == null) {
-        if (_parsingContext.Debug) {
-          _parsingContext.Configuration.Logger.Log(
-              _parsingContext,
-              string.Format("'{0}' is not a supported function", ExpressionString));
-        }
-        return new(ExcelErrorValue.Create(eErrorType.Name), DataType.ExcelError);
-      }
-      if (_parsingContext.Debug) {
-        _parsingContext.Configuration.Logger.LogFunction(ExpressionString);
-      }
-      var compiler = _functionCompilerFactory.Create(function);
-      var result = compiler.Compile(
-          HasChildren ? Children : Enumerable.Empty<Expression>(),
-          _parsingContext);
-      if (_isNegated) {
-        if (!result.IsNumeric) {
-          if (_parsingContext.Debug) {
-            var msg = string.Format(
-                "Trying to negate a non-numeric value ({0}) in function '{1}'",
-                result.Result,
-                ExpressionString);
-            _parsingContext.Configuration.Logger.Log(_parsingContext, msg);
-          }
-          return new(ExcelErrorValue.Create(eErrorType.Value), DataType.ExcelError);
-        }
-        return new(result.ResultNumeric * -1, result.DataType);
-      }
-      return result;
-    } catch (ExcelErrorValueException e) {
-      if (_parsingContext.Debug) {
-        _parsingContext.Configuration.Logger.Log(_parsingContext, e);
-      }
-      return new(e.ErrorValue, DataType.ExcelError);
-    }
-  }
-
-  public override Expression PrepareForNextChild() {
-    return base.AddChild(new FunctionArgumentExpression(this));
-  }
-
-  public override bool HasChildren => (Children.Any() && Children.First().Children.Any());
-
-  public override Expression AddChild(Expression child) {
-    Children.Last().AddChild(child);
-    return child;
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/GroupExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/GroupExpression.cs
deleted file mode 100644
index 54df131..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/GroupExpression.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public class GroupExpression : Expression {
-  public GroupExpression(bool isNegated)
-      : this(isNegated, new ExpressionCompiler()) {}
-
-  public GroupExpression(bool isNegated, IExpressionCompiler expressionCompiler) {
-    _expressionCompiler = expressionCompiler;
-    _isNegated = isNegated;
-  }
-
-  private readonly IExpressionCompiler _expressionCompiler;
-  private readonly bool _isNegated;
-
-  public override CompileResult Compile() {
-    var result = _expressionCompiler.Compile(Children);
-    if (result.IsNumeric && _isNegated) {
-      return new(result.ResultNumeric * -1, result.DataType);
-    }
-    return result;
-  }
-
-  public override bool IsGroupedExpression => true;
-
-  public bool IsNegated => _isNegated;
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/IExpressionCompiler.cs b/EPPlus/FormulaParsing/ExpressionGraph/IExpressionCompiler.cs
deleted file mode 100644
index c7ef8dd..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/IExpressionCompiler.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public interface IExpressionCompiler {
-  CompileResult Compile(IEnumerable<Expression> expressions);
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/IExpressionConverter.cs b/EPPlus/FormulaParsing/ExpressionGraph/IExpressionConverter.cs
deleted file mode 100644
index 0a1b901..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/IExpressionConverter.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public interface IExpressionConverter {
-  StringExpression ToStringExpression(Expression expression);
-
-  Expression FromCompileResult(CompileResult compileResult);
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/IExpressionFactory.cs b/EPPlus/FormulaParsing/ExpressionGraph/IExpressionFactory.cs
deleted file mode 100644
index 2e89b2a..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/IExpressionFactory.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public interface IExpressionFactory {
-  Expression Create(Token token);
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/IExpressionGraphBuilder.cs b/EPPlus/FormulaParsing/ExpressionGraph/IExpressionGraphBuilder.cs
deleted file mode 100644
index 2fad667..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/IExpressionGraphBuilder.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public interface IExpressionGraphBuilder {
-  ExpressionGraph Build(IEnumerable<Token> tokens);
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/IntegerExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/IntegerExpression.cs
deleted file mode 100644
index f24afa0..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/IntegerExpression.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System;
-using System.Globalization;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public class IntegerExpression : AtomicExpression {
-  private readonly double? _compiledValue;
-  private readonly bool _negate;
-
-  public IntegerExpression(string expression)
-      : this(expression, false) {}
-
-  public IntegerExpression(string expression, bool negate)
-      : base(expression) {
-    _negate = negate;
-  }
-
-  public IntegerExpression(double val)
-      : base(val.ToString(CultureInfo.InvariantCulture)) {
-    _compiledValue = Math.Floor(val);
-  }
-
-  public override CompileResult Compile() {
-    double result = _compiledValue ?? double.Parse(ExpressionString, CultureInfo.InvariantCulture);
-    result = _negate ? result * -1 : result;
-    return new(result, DataType.Integer);
-  }
-
-  public bool IsNegated => _negate;
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/NamedValueExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/NamedValueExpression.cs
deleted file mode 100644
index cdf7582..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/NamedValueExpression.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.Exceptions;
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public class NamedValueExpression : AtomicExpression {
-  public NamedValueExpression(string expression, ParsingContext parsingContext)
-      : base(expression) {
-    _parsingContext = parsingContext;
-  }
-
-  private readonly ParsingContext _parsingContext;
-
-  public override CompileResult Compile() {
-    var c = _parsingContext.Scopes.Current;
-    var name = _parsingContext.ExcelDataProvider.GetName(c.Address.Worksheet, ExpressionString);
-    //var result = _parsingContext.Parser.Parse(value.ToString());
-
-    if (name == null) {
-      throw (new ExcelErrorValueException(ExcelErrorValue.Create(eErrorType.Name)));
-    }
-    if (name.Value == null) {
-      return null;
-    }
-    if (name.Value is ExcelDataProvider.IRangeInfo range) {
-      if (range.IsMulti) {
-        return new(range, DataType.Enumerable);
-      }
-      if (range.IsEmpty) {
-        return null;
-      }
-      var factory = new CompileResultFactory();
-      return factory.Create(range.First().Value);
-    }
-    {
-      var factory = new CompileResultFactory();
-      return factory.Create(name.Value);
-    }
-
-    //return new CompileResultFactory().Create(result);
-  }
-}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/StringExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/StringExpression.cs
deleted file mode 100644
index f3b29de..0000000
--- a/EPPlus/FormulaParsing/ExpressionGraph/StringExpression.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.ExpressionGraph;
-
-public class StringExpression : AtomicExpression {
-  public StringExpression(string expression)
-      : base(expression) {}
-
-  public override CompileResult Compile() {
-    return new(ExpressionString, DataType.String);
-  }
-}
diff --git a/EPPlus/FormulaParsing/FormulaParser.cs b/EPPlus/FormulaParsing/FormulaParser.cs
deleted file mode 100644
index 06bd4a6..0000000
--- a/EPPlus/FormulaParsing/FormulaParser.cs
+++ /dev/null
@@ -1,197 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.Excel.Functions;
-using OfficeOpenXml.FormulaParsing.ExcelUtilities;
-using OfficeOpenXml.FormulaParsing.Exceptions;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-using OfficeOpenXml.FormulaParsing.Utilities;
-
-namespace OfficeOpenXml.FormulaParsing;
-
-public class FormulaParser {
-  private readonly ParsingContext _parsingContext;
-  private readonly ExcelDataProvider _excelDataProvider;
-
-  public FormulaParser(ExcelDataProvider excelDataProvider)
-      : this(excelDataProvider, ParsingContext.Create()) {}
-
-  public FormulaParser(ExcelDataProvider excelDataProvider, ParsingContext parsingContext) {
-    parsingContext.Parser = this;
-    parsingContext.ExcelDataProvider = excelDataProvider;
-    parsingContext.NameValueProvider = new EpplusNameValueProvider(excelDataProvider);
-    parsingContext.RangeAddressFactory = new(excelDataProvider);
-    _parsingContext = parsingContext;
-    _excelDataProvider = excelDataProvider;
-    Configure(configuration => {
-      configuration
-          .SetLexer(
-              new Lexer(
-                  _parsingContext.Configuration.FunctionRepository,
-                  _parsingContext.NameValueProvider))
-          .SetGraphBuilder(new ExpressionGraphBuilder(excelDataProvider, _parsingContext))
-          .SetExpresionCompiler(new ExpressionCompiler())
-          .FunctionRepository.LoadModule(new BuiltInFunctions());
-    });
-  }
-
-  public void Configure(Action<ParsingConfiguration> configMethod) {
-    configMethod.Invoke(_parsingContext.Configuration);
-    _lexer = _parsingContext.Configuration.Lexer ?? _lexer;
-    _graphBuilder = _parsingContext.Configuration.GraphBuilder ?? _graphBuilder;
-    _compiler = _parsingContext.Configuration.ExpressionCompiler ?? _compiler;
-  }
-
-  private ILexer _lexer;
-  private IExpressionGraphBuilder _graphBuilder;
-  private IExpressionCompiler _compiler;
-
-  public ILexer Lexer => _lexer;
-
-  public IEnumerable<string> FunctionNames =>
-    _parsingContext.Configuration.FunctionRepository.FunctionNames;
-
-  internal virtual object Parse(string formula, RangeAddress rangeAddress) {
-    using (var scope = _parsingContext.Scopes.NewScope(rangeAddress)) {
-      var tokens = _lexer.Tokenize(formula);
-      var graph = _graphBuilder.Build(tokens);
-      if (graph.Expressions.Count() == 0) {
-        return null;
-      }
-      return _compiler.Compile(graph.Expressions).Result;
-    }
-  }
-
-  internal virtual object Parse(IEnumerable<Token> tokens, string worksheet, string address) {
-    var rangeAddress = _parsingContext.RangeAddressFactory.Create(address);
-    using (var scope = _parsingContext.Scopes.NewScope(rangeAddress)) {
-      var graph = _graphBuilder.Build(tokens);
-      if (graph.Expressions.Count() == 0) {
-        return null;
-      }
-      return _compiler.Compile(graph.Expressions).Result;
-    }
-  }
-
-  internal virtual object ParseCell(
-      IEnumerable<Token> tokens,
-      string worksheet,
-      int row,
-      int column) {
-    var rangeAddress = _parsingContext.RangeAddressFactory.Create(worksheet, column, row);
-    using (var scope = _parsingContext.Scopes.NewScope(rangeAddress)) {
-      //    _parsingContext.Dependencies.AddFormulaScope(scope);
-      var graph = _graphBuilder.Build(tokens);
-      if (graph.Expressions.Count() == 0) {
-        return 0d;
-      }
-      try {
-        var compileResult = _compiler.Compile(graph.Expressions);
-        // quick solution for the fact that an excelrange can be returned.
-        var rangeInfo = compileResult.Result as ExcelDataProvider.IRangeInfo;
-        if (rangeInfo == null) {
-          return compileResult.Result ?? 0d;
-        }
-        if (rangeInfo.IsEmpty) {
-          return 0d;
-        }
-        if (!rangeInfo.IsMulti) {
-          return rangeInfo.First().Value ?? 0d;
-        }
-        // ok to return multicell if it is a workbook scoped name.
-        if (string.IsNullOrEmpty(worksheet)) {
-          return rangeInfo;
-        }
-        if (_parsingContext.Debug) {
-          var msg = string.Format(
-              "A range with multiple cell was returned at row {0}, column {1}",
-              row,
-              column);
-          _parsingContext.Configuration.Logger.Log(_parsingContext, msg);
-        }
-        return ExcelErrorValue.Create(eErrorType.Value);
-      } catch (ExcelErrorValueException ex) {
-        if (_parsingContext.Debug) {
-          _parsingContext.Configuration.Logger.Log(_parsingContext, ex);
-        }
-        return ex.ErrorValue;
-      }
-    }
-  }
-
-  public virtual object Parse(string formula, string address) {
-    return Parse(formula, _parsingContext.RangeAddressFactory.Create(address));
-  }
-
-  public virtual object Parse(string formula) {
-    return Parse(formula, RangeAddress.Empty);
-  }
-
-  public virtual object ParseAt(string address) {
-    Require.That(address).Named("address").IsNotNullOrEmpty();
-    var rangeAddress = _parsingContext.RangeAddressFactory.Create(address);
-    return ParseAt(rangeAddress.Worksheet, rangeAddress.FromRow, rangeAddress.FromCol);
-  }
-
-  public virtual object ParseAt(string worksheetName, int row, int col) {
-    var f = _excelDataProvider.GetRangeFormula(worksheetName, row, col);
-    if (string.IsNullOrEmpty(f)) {
-      return _excelDataProvider.GetRangeValue(worksheetName, row, col);
-    }
-    return Parse(f, _parsingContext.RangeAddressFactory.Create(worksheetName, col, row));
-    //var dataItem = _excelDataProvider.GetRangeValues(address).FirstOrDefault();
-    //if (dataItem == null /*|| (dataItem.Value == null && dataItem.Formula == null)*/) return null;
-    //if (!string.IsNullOrEmpty(dataItem.Formula))
-    //{
-    //    return Parse(dataItem.Formula, _parsingContext.RangeAddressFactory.Create(address));
-    //}
-    //return Parse(dataItem.Value.ToString(), _parsingContext.RangeAddressFactory.Create(address));
-  }
-
-  internal void InitNewCalc() {
-    if (_excelDataProvider != null) {
-      _excelDataProvider.Reset();
-    }
-  }
-
-  // Praveen's Formula Parser
-  public ExpressionGraph.ExpressionGraph ParseToGraph(string formula) {
-    using (var scope = _parsingContext.Scopes.NewScope(RangeAddress.Empty)) {
-      var tokens = _lexer.Tokenize(formula);
-      var graph = _graphBuilder.Build(tokens);
-      return graph;
-    }
-  }
-}
diff --git a/EPPlus/FormulaParsing/FormulaParserManager.cs b/EPPlus/FormulaParsing/FormulaParserManager.cs
deleted file mode 100644
index 9d7dc65..0000000
--- a/EPPlus/FormulaParsing/FormulaParserManager.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.Excel.Functions;
-using OfficeOpenXml.FormulaParsing.Utilities;
-
-namespace OfficeOpenXml.FormulaParsing;
-
-/// <summary>
-/// Provides access to various functionality regarding
-/// excel formula evaluation.
-/// </summary>
-public class FormulaParserManager {
-  private readonly FormulaParser _parser;
-
-  internal FormulaParserManager(FormulaParser parser) {
-    Require.That(parser).Named("parser").IsNotNull();
-    _parser = parser;
-  }
-
-  /// <summary>
-  /// Loads a module containing custom functions to the formula parser. By using
-  /// this method you can add your own implementations of Excel functions, by
-  /// implementing a <see cref="IFunctionModule"/>.
-  /// </summary>
-  /// <param name="module">A <see cref="IFunctionModule"/> containing <see cref="ExcelFunction"/>s.</param>
-  public void LoadFunctionModule(IFunctionModule module) {
-    _parser.Configure(x => x.FunctionRepository.LoadModule(module));
-  }
-
-  /// <summary>
-  /// If the supplied <paramref name="functionName"/> does not exist, the supplied
-  /// <paramref name="functionImpl"/> implementation will be added to the formula parser.
-  /// If it exists, the existing function will be replaced by the supplied <paramref name="functionImpl">function implementation</paramref>
-  /// </summary>
-  /// <param name="functionName"></param>
-  /// <param name="functionImpl"></param>
-  public void AddOrReplaceFunction(string functionName, ExcelFunction functionImpl) {
-    _parser.Configure(x => x.FunctionRepository.AddOrReplaceFunction(functionName, functionImpl));
-  }
-
-  /// <summary>
-  /// Returns an enumeration of all functions implemented, both the built in functions
-  /// and functions added using the LoadFunctionModule method of this class.
-  /// </summary>
-  /// <returns>Function names in lower case</returns>
-  public IEnumerable<string> GetImplementedFunctionNames() {
-    var fnList = _parser.FunctionNames.ToList();
-    fnList.Sort((x, y) => String.Compare(x, y, StringComparison.Ordinal));
-    return fnList;
-  }
-
-  /// <summary>
-  /// Parses the supplied <paramref name="formula"/> and returns the result.
-  /// </summary>
-  /// <param name="formula"></param>
-  /// <returns></returns>
-  public object Parse(string formula) {
-    return _parser.Parse(formula);
-  }
-
-  // Praveen's Parser Support
-  public ExpressionGraph.ExpressionGraph ParseToGraph(string formula) {
-    return _parser.ParseToGraph(formula);
-  }
-}
diff --git a/EPPlus/FormulaParsing/INameValueProvider.cs b/EPPlus/FormulaParsing/INameValueProvider.cs
deleted file mode 100644
index 0a227ae..0000000
--- a/EPPlus/FormulaParsing/INameValueProvider.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace OfficeOpenXml.FormulaParsing;
-
-public interface INameValueProvider {
-  bool IsNamedValue(string key, string worksheet);
-
-  object GetNamedValue(string key);
-
-  void Reload();
-}
diff --git a/EPPlus/FormulaParsing/IParsingLifetimeEventHandler.cs b/EPPlus/FormulaParsing/IParsingLifetimeEventHandler.cs
deleted file mode 100644
index 52fc794..0000000
--- a/EPPlus/FormulaParsing/IParsingLifetimeEventHandler.cs
+++ /dev/null
@@ -1,5 +0,0 @@
-namespace OfficeOpenXml.FormulaParsing;
-
-public interface IParsingLifetimeEventHandler {
-  void ParsingCompleted();
-}
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/ILexer.cs b/EPPlus/FormulaParsing/LexicalAnalysis/ILexer.cs
deleted file mode 100644
index ec3aef5..0000000
--- a/EPPlus/FormulaParsing/LexicalAnalysis/ILexer.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-
-public interface ILexer {
-  IEnumerable<Token> Tokenize(string input);
-
-  IEnumerable<Token> Tokenize(string input, string worksheet);
-}
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/ISourceCodeTokenizer.cs b/EPPlus/FormulaParsing/LexicalAnalysis/ISourceCodeTokenizer.cs
deleted file mode 100644
index 488d4aa..0000000
--- a/EPPlus/FormulaParsing/LexicalAnalysis/ISourceCodeTokenizer.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-
-public interface ISourceCodeTokenizer {
-  IEnumerable<Token> Tokenize(string input, string worksheet);
-}
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/ISyntacticAnalyzer.cs b/EPPlus/FormulaParsing/LexicalAnalysis/ISyntacticAnalyzer.cs
deleted file mode 100644
index 9f73dba..0000000
--- a/EPPlus/FormulaParsing/LexicalAnalysis/ISyntacticAnalyzer.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-
-public interface ISyntacticAnalyzer {
-  void Analyze(IEnumerable<Token> tokens);
-}
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/ITokenFactory.cs b/EPPlus/FormulaParsing/LexicalAnalysis/ITokenFactory.cs
deleted file mode 100644
index ab5b170..0000000
--- a/EPPlus/FormulaParsing/LexicalAnalysis/ITokenFactory.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-
-public interface ITokenFactory {
-  Token Create(IEnumerable<Token> tokens, string token);
-
-  Token Create(IEnumerable<Token> tokens, string token, string worksheet);
-
-  Token Create(string token, TokenType explicitTokenType);
-}
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/ITokenIndexProvider.cs b/EPPlus/FormulaParsing/LexicalAnalysis/ITokenIndexProvider.cs
deleted file mode 100644
index 1028a1c..0000000
--- a/EPPlus/FormulaParsing/LexicalAnalysis/ITokenIndexProvider.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-
-public interface ITokenIndexProvider {
-  int Index { get; }
-
-  void MoveIndexPointerForward();
-}
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/ITokenSeparatorProvider.cs b/EPPlus/FormulaParsing/LexicalAnalysis/ITokenSeparatorProvider.cs
deleted file mode 100644
index 91fb6b9..0000000
--- a/EPPlus/FormulaParsing/LexicalAnalysis/ITokenSeparatorProvider.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-
-public interface ITokenSeparatorProvider {
-  IDictionary<string, Token> Tokens { get; }
-
-  bool IsOperator(string item);
-
-  bool IsPossibleLastPartOfMultipleCharOperator(string part);
-}
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/Lexer.cs b/EPPlus/FormulaParsing/LexicalAnalysis/Lexer.cs
deleted file mode 100644
index 35f4e8f..0000000
--- a/EPPlus/FormulaParsing/LexicalAnalysis/Lexer.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-//using OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-
-public class Lexer : ILexer {
-  public Lexer(FunctionRepository functionRepository, INameValueProvider nameValueProvider)
-      : this(
-          new SourceCodeTokenizer(functionRepository, nameValueProvider),
-          new SyntacticAnalyzer()) {}
-
-  public Lexer(ISourceCodeTokenizer tokenizer, ISyntacticAnalyzer analyzer) {
-    _tokenizer = tokenizer;
-    _analyzer = analyzer;
-  }
-
-  private readonly ISourceCodeTokenizer _tokenizer;
-  private readonly ISyntacticAnalyzer _analyzer;
-
-  public IEnumerable<Token> Tokenize(string input) {
-    return Tokenize(input, null);
-  }
-
-  public IEnumerable<Token> Tokenize(string input, string worksheet) {
-    var tokens = _tokenizer.Tokenize(input, worksheet);
-    _analyzer.Analyze(tokens);
-    return tokens;
-  }
-}
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/SourceCodeTokenizer.cs b/EPPlus/FormulaParsing/LexicalAnalysis/SourceCodeTokenizer.cs
deleted file mode 100644
index 51f6f4b..0000000
--- a/EPPlus/FormulaParsing/LexicalAnalysis/SourceCodeTokenizer.cs
+++ /dev/null
@@ -1,297 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Text.RegularExpressions;
-using OfficeOpenXml.FormulaParsing.Excel.Functions;
-
-namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-
-public class SourceCodeTokenizer : ISourceCodeTokenizer {
-  public static ISourceCodeTokenizer Default =>
-    new SourceCodeTokenizer(FunctionNameProvider.Empty, NameValueProvider.Empty);
-
-  public SourceCodeTokenizer(
-      IFunctionNameProvider functionRepository,
-      INameValueProvider nameValueProvider)
-      : this(
-          new TokenFactory(functionRepository, nameValueProvider),
-          new TokenSeparatorProvider()) {}
-
-  public SourceCodeTokenizer(ITokenFactory tokenFactory, ITokenSeparatorProvider tokenProvider) {
-    _tokenFactory = tokenFactory;
-    _tokenProvider = tokenProvider;
-  }
-
-  private readonly ITokenSeparatorProvider _tokenProvider;
-  private readonly ITokenFactory _tokenFactory;
-
-  public IEnumerable<Token> Tokenize(string input) {
-    return Tokenize(input, null);
-  }
-
-  public IEnumerable<Token> Tokenize(string input, string worksheet) {
-    if (string.IsNullOrEmpty(input)) {
-      return Enumerable.Empty<Token>();
-    }
-    // MA 1401: Ignore leading plus in formula.
-    input = input.TrimStart('+');
-    var context = new TokenizerContext(input);
-
-    bool isSingleQuoteString = false;
-    for (int i = 0; i < context.FormulaChars.Length; i++) {
-      var c = context.FormulaChars[i];
-      if (CharIsTokenSeparator(c, out var tokenSeparator)) {
-        if (context.IsInString) {
-          if (IsDoubleQuote(tokenSeparator, i, context)) {
-            i++;
-            context.AppendToCurrentToken(c);
-            continue;
-          }
-          if (tokenSeparator.TokenType != TokenType.String) {
-            context.AppendToCurrentToken(c);
-            continue;
-          }
-          // CHANGE 2
-          if ((isSingleQuoteString && c != '\'') || (!isSingleQuoteString && c != '"')) {
-            context.AppendToCurrentToken(c);
-            continue;
-          }
-        }
-        if (tokenSeparator.TokenType == TokenType.OpeningBracket) {
-          context.AppendToCurrentToken(c);
-          context.BracketCount++;
-          continue;
-        }
-        if (tokenSeparator.TokenType == TokenType.ClosingBracket) {
-          context.AppendToCurrentToken(c);
-          context.BracketCount--;
-          continue;
-        }
-        if (context.BracketCount > 0) {
-          context.AppendToCurrentToken(c);
-          continue;
-        }
-        // two operators in sequence could be "<=" or ">="
-        if (IsPartOfMultipleCharSeparator(context, c)) {
-          var sOp = context.LastToken.Value + c.ToString(CultureInfo.InvariantCulture);
-          var op = _tokenProvider.Tokens[sOp];
-          context.ReplaceLastToken(op);
-          context.NewToken();
-          continue;
-        }
-        if (tokenSeparator.TokenType == TokenType.String) {
-          // CHANGE3 :
-          isSingleQuoteString = (c == '\'');
-          if (context.LastToken != null
-              && context.LastToken.TokenType == TokenType.OpeningEnumerable) {
-            // context.AppendToCurrentToken(c);  // Praveen's change of 10/28/2015
-            context.ToggleIsInString();
-            continue;
-          }
-          if (context.LastToken != null && context.LastToken.TokenType == TokenType.String) {
-            context.AddToken(
-                !context.CurrentTokenHasValue
-                    ? new(string.Empty, TokenType.StringContent)
-                    : new Token(context.CurrentToken, TokenType.StringContent));
-          }
-          context.AddToken(new("\"", TokenType.String));
-          context.ToggleIsInString();
-          context.NewToken();
-          continue;
-        }
-        if (context.CurrentTokenHasValue) {
-          if (Regex.IsMatch(context.CurrentToken, "^\"*$")) {
-            context.AddToken(_tokenFactory.Create(context.CurrentToken, TokenType.StringContent));
-          } else {
-            context.AddToken(CreateToken(context, worksheet));
-          }
-
-          //If the a next token is an opening parantheses and the previous token is interpeted as an address or name, then the currenct token is a function
-          if (tokenSeparator.TokenType == TokenType.OpeningParenthesis
-              && (context.LastToken.TokenType == TokenType.ExcelAddress
-                      || context.LastToken.TokenType == TokenType.NameValue)) {
-            context.LastToken.TokenType = TokenType.Function;
-          }
-        }
-        if (tokenSeparator.Value == "-") {
-          if (TokenIsNegator(context)) {
-            context.AddToken(new("-", TokenType.Negator));
-            continue;
-          }
-        }
-        context.AddToken(tokenSeparator);
-        context.NewToken();
-        continue;
-      }
-      context.AppendToCurrentToken(c);
-    }
-    if (context.CurrentTokenHasValue) {
-      context.AddToken(CreateToken(context, worksheet));
-    }
-
-    CleanupTokens(context, _tokenProvider.Tokens);
-
-    return context.Result;
-  }
-
-  private static bool IsDoubleQuote(
-      Token tokenSeparator,
-      int formulaCharIndex,
-      TokenizerContext context) {
-    return tokenSeparator.TokenType == TokenType.String
-        && formulaCharIndex + 1 < context.FormulaChars.Length
-        && context.FormulaChars[formulaCharIndex + 1] == '\"';
-  }
-
-  private static void CleanupTokens(TokenizerContext context, IDictionary<string, Token> tokens) {
-    for (int i = 0; i < context.Result.Count; i++) {
-      var token = context.Result[i];
-      if (token.TokenType == TokenType.Unrecognized) {
-        if (i < context.Result.Count - 1) {
-          if (context.Result[i + 1].TokenType == TokenType.OpeningParenthesis) {
-            token.TokenType = TokenType.Function;
-          } else {
-            token.TokenType = TokenType.NameValue;
-          }
-        } else {
-          token.TokenType = TokenType.NameValue;
-        }
-      } else if (token.TokenType == TokenType.Function) {
-        if (i < context.Result.Count - 1) {
-          if (context.Result[i + 1].TokenType == TokenType.OpeningParenthesis) {
-            token.TokenType = TokenType.Function;
-          } else {
-            token.TokenType = TokenType.Unrecognized;
-          }
-        } else {
-          token.TokenType = TokenType.Unrecognized;
-        }
-      } else if ((token.TokenType == TokenType.Operator || token.TokenType == TokenType.Negator)
-          && i < context.Result.Count - 1
-          && (token.Value == "+" || token.Value == "-")) {
-        if (i > 0
-            && token.Value
-                == "+") //Remove any + with an opening parenthesis before.
-        {
-          if (context.Result[i - 1].TokenType == TokenType.OpeningParenthesis) {
-            context.Result.RemoveAt(i);
-            SetNegatorOperator(context, i, tokens);
-            i--;
-            continue;
-          }
-        }
-
-        var nextToken = context.Result[i + 1];
-        if (nextToken.TokenType == TokenType.Operator || nextToken.TokenType == TokenType.Negator) {
-          if (token.Value == "+" && (nextToken.Value == "+" || nextToken.Value == "-")) {
-            //Remove first
-            context.Result.RemoveAt(i);
-            SetNegatorOperator(context, i, tokens);
-            i--;
-          } else if (token.Value == "-" && nextToken.Value == "+") {
-            //Remove second
-            context.Result.RemoveAt(i + 1);
-            SetNegatorOperator(context, i, tokens);
-            i--;
-          } else if (token.Value == "-" && nextToken.Value == "-") {
-            //Remove first and set operator to +
-            context.Result.RemoveAt(i);
-            if (i == 0) {
-              context.Result.RemoveAt(i + 1);
-              i += 2;
-            } else {
-              //context.Result[i].TokenType = TokenType.Operator;
-              //context.Result[i].Value = "+";
-              context.Result[i] = tokens["+"];
-              SetNegatorOperator(context, i, tokens);
-              i--;
-            }
-          }
-        }
-      }
-    }
-  }
-
-  private static void SetNegatorOperator(
-      TokenizerContext context,
-      int i,
-      IDictionary<string, Token> tokens) {
-    if (context.Result[i].Value == "-"
-        && i > 0
-        && (context.Result[i].TokenType == TokenType.Operator
-                || context.Result[i].TokenType == TokenType.Negator)) {
-      if (TokenIsNegator(context.Result[i - 1])) {
-        context.Result[i] = new("-", TokenType.Negator);
-      } else {
-        context.Result[i] = tokens["-"];
-      }
-    }
-  }
-
-  private static bool TokenIsNegator(TokenizerContext context) {
-    return TokenIsNegator(context.LastToken);
-  }
-
-  private static bool TokenIsNegator(Token t) {
-    return t == null
-        || t.TokenType == TokenType.Operator
-        || t.TokenType == TokenType.OpeningParenthesis
-        || t.TokenType == TokenType.Comma
-        || t.TokenType == TokenType.SemiColon
-        || t.TokenType == TokenType.OpeningEnumerable;
-  }
-
-  private bool IsPartOfMultipleCharSeparator(TokenizerContext context, char c) {
-    var lastToken = context.LastToken != null ? context.LastToken.Value : string.Empty;
-    return _tokenProvider.IsOperator(lastToken)
-        && _tokenProvider.IsPossibleLastPartOfMultipleCharOperator(
-            c.ToString(CultureInfo.InvariantCulture))
-        && !context.CurrentTokenHasValue;
-  }
-
-  private Token CreateToken(TokenizerContext context, string worksheet) {
-    if (context.CurrentToken == "-") {
-      if (context.LastToken == null && context.LastToken.TokenType == TokenType.Operator) {
-        return new("-", TokenType.Negator);
-      }
-    }
-    return _tokenFactory.Create(context.Result, context.CurrentToken, worksheet);
-  }
-
-  private bool CharIsTokenSeparator(char c, out Token token) {
-    var result = _tokenProvider.Tokens.ContainsKey(c.ToString());
-    token = result ? token = _tokenProvider.Tokens[c.ToString()] : null;
-    return result;
-  }
-}
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/SyntacticAnalyzer.cs b/EPPlus/FormulaParsing/LexicalAnalysis/SyntacticAnalyzer.cs
deleted file mode 100644
index e771aaf..0000000
--- a/EPPlus/FormulaParsing/LexicalAnalysis/SyntacticAnalyzer.cs
+++ /dev/null
@@ -1,89 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.Exceptions;
-
-namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-
-public class SyntacticAnalyzer : ISyntacticAnalyzer {
-  private class AnalyzingContext {
-    public int NumberOfOpenedParentheses { get; set; }
-
-    public int NumberOfClosedParentheses { get; set; }
-
-    public int OpenedStrings { get; set; }
-
-    public int ClosedStrings { get; set; }
-
-    public bool IsInString { get; set; }
-  }
-
-  public void Analyze(IEnumerable<Token> tokens) {
-    var context = new AnalyzingContext();
-    foreach (var token in tokens) {
-      if (token.TokenType == TokenType.Unrecognized) {
-        throw new UnrecognizedTokenException(token);
-      }
-      EnsureParenthesesAreWellFormed(token, context);
-      EnsureStringsAreWellFormed(token, context);
-    }
-    Validate(context);
-  }
-
-  private static void Validate(AnalyzingContext context) {
-    if (context.NumberOfOpenedParentheses != context.NumberOfClosedParentheses) {
-      throw new FormatException("Number of opened and closed parentheses does not match");
-    }
-    if (context.OpenedStrings != context.ClosedStrings) {
-      throw new FormatException("Unterminated string");
-    }
-  }
-
-  private void EnsureParenthesesAreWellFormed(Token token, AnalyzingContext context) {
-    if (token.TokenType == TokenType.OpeningParenthesis) {
-      context.NumberOfOpenedParentheses++;
-    } else if (token.TokenType == TokenType.ClosingParenthesis) {
-      context.NumberOfClosedParentheses++;
-    }
-  }
-
-  private void EnsureStringsAreWellFormed(Token token, AnalyzingContext context) {
-    if (!context.IsInString && token.TokenType == TokenType.String) {
-      context.IsInString = true;
-      context.OpenedStrings++;
-    } else if (context.IsInString && token.TokenType == TokenType.String) {
-      context.IsInString = false;
-      context.ClosedStrings++;
-    }
-  }
-}
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/Token.cs b/EPPlus/FormulaParsing/LexicalAnalysis/Token.cs
deleted file mode 100644
index f3faa0c..0000000
--- a/EPPlus/FormulaParsing/LexicalAnalysis/Token.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-
-public class Token {
-  public Token(string token, TokenType tokenType) {
-    Value = token;
-    TokenType = tokenType;
-  }
-
-  public string Value { get; internal set; }
-
-  public TokenType TokenType { get; internal set; }
-
-  public void Append(string stringToAppend) {
-    Value += stringToAppend;
-  }
-
-  public bool IsNegated { get; private set; }
-
-  public void Negate() {
-    if (TokenType == TokenType.Decimal
-        || TokenType == TokenType.Integer
-        || TokenType == TokenType.ExcelAddress) {
-      IsNegated = true;
-    }
-  }
-
-  public override string ToString() {
-    return TokenType + ", " + Value;
-  }
-}
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/TokenFactory.cs b/EPPlus/FormulaParsing/LexicalAnalysis/TokenFactory.cs
deleted file mode 100644
index 4639753..0000000
--- a/EPPlus/FormulaParsing/LexicalAnalysis/TokenFactory.cs
+++ /dev/null
@@ -1,140 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- * Jan Källman                      Replaced Adress validate    2013-03-01
- * *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Text.RegularExpressions;
-using OfficeOpenXml.FormulaParsing.Excel.Functions;
-using OfficeOpenXml.FormulaParsing.Utilities;
-
-namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-
-public class TokenFactory : ITokenFactory {
-  public TokenFactory(
-      IFunctionNameProvider functionRepository,
-      INameValueProvider nameValueProvider)
-      : this(new TokenSeparatorProvider(), nameValueProvider, functionRepository) {}
-
-  public TokenFactory(
-      ITokenSeparatorProvider tokenSeparatorProvider,
-      INameValueProvider nameValueProvider,
-      IFunctionNameProvider functionNameProvider) {
-    _tokenSeparatorProvider = tokenSeparatorProvider;
-    _functionNameProvider = functionNameProvider;
-    _nameValueProvider = nameValueProvider;
-  }
-
-  private readonly ITokenSeparatorProvider _tokenSeparatorProvider;
-  private readonly IFunctionNameProvider _functionNameProvider;
-  private readonly INameValueProvider _nameValueProvider;
-
-  public Token Create(IEnumerable<Token> tokens, string token) {
-    return Create(tokens, token, null);
-  }
-
-  public Token Create(IEnumerable<Token> tokens, string token, string worksheet) {
-    if (_tokenSeparatorProvider.Tokens.TryGetValue(token, out var tokenSeparator)) {
-      return tokenSeparator;
-    }
-    var tokenList = (IList<Token>)tokens;
-    //Address with worksheet-string before  /JK
-    if (token.StartsWith("!") && tokenList[tokenList.Count - 1].TokenType == TokenType.String) {
-      var i = tokenList.Count - 2;
-      if (i > 0) {
-        string addr;
-        if (tokenList[i].TokenType == TokenType.StringContent) {
-          addr = "'" + tokenList[i].Value.Replace("'", "''") + "'";
-        } else {
-          throw (new ArgumentException(
-                  string.Format("Invalid formula token sequence near {0}", token)));
-        }
-        //Remove the string tokens and content
-        tokenList.RemoveAt(tokenList.Count - 1);
-        tokenList.RemoveAt(tokenList.Count - 1);
-        tokenList.RemoveAt(tokenList.Count - 1);
-
-        return new(addr + token, TokenType.ExcelAddress);
-      }
-      throw (new ArgumentException(
-              string.Format("Invalid formula token sequence near {0}", token)));
-    }
-
-    if (tokens.Any() && tokens.Last().TokenType == TokenType.String) {
-      return new(token, TokenType.StringContent);
-    }
-    if (!string.IsNullOrEmpty(token)) {
-      token = token.Trim();
-    }
-    if (Regex.IsMatch(token, RegexConstants.Decimal)) {
-      return new(token, TokenType.Decimal);
-    }
-    if (Regex.IsMatch(token, RegexConstants.Integer)) {
-      return new(token, TokenType.Integer);
-    }
-    if (Regex.IsMatch(token, RegexConstants.Boolean, RegexOptions.IgnoreCase)) {
-      return new(token, TokenType.Boolean);
-    }
-    if (token.ToUpper(CultureInfo.InvariantCulture).Contains("#REF!")) {
-      return new(token, TokenType.InvalidReference);
-    }
-    if (token.ToUpper(CultureInfo.InvariantCulture) == "#NUM!") {
-      return new(token, TokenType.NumericError);
-    }
-    if (token.ToUpper(CultureInfo.InvariantCulture) == "#VALUE!") {
-      return new(token, TokenType.ValueDataTypeError);
-    }
-    if (token.ToUpper(CultureInfo.InvariantCulture) == "#NULL!") {
-      return new(token, TokenType.Null);
-    }
-    if (_nameValueProvider != null && _nameValueProvider.IsNamedValue(token, worksheet)) {
-      return new(token, TokenType.NameValue);
-    }
-    if (_functionNameProvider.IsFunctionName(token)) {
-      return new(token, TokenType.Function);
-    }
-    if (tokenList.Count > 0
-        && tokenList[tokenList.Count - 1].TokenType == TokenType.OpeningEnumerable) {
-      return new(token, TokenType.Enumerable);
-    }
-    var at = ExcelAddressBase.IsValid(token);
-    if (at == ExcelAddressBase.AddressType.InternalAddress) {
-      return new(token.ToUpper(CultureInfo.InvariantCulture), TokenType.ExcelAddress);
-    }
-    return new(token, TokenType.Unrecognized);
-  }
-
-  public Token Create(string token, TokenType explicitTokenType) {
-    return new(token, explicitTokenType);
-  }
-}
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorProvider.cs b/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorProvider.cs
deleted file mode 100644
index d56dc18..0000000
--- a/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorProvider.cs
+++ /dev/null
@@ -1,79 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-
-public class TokenSeparatorProvider : ITokenSeparatorProvider {
-  private static readonly Dictionary<string, Token> _tokens = new();
-
-  static TokenSeparatorProvider() {
-    _tokens.Add("+", new("+", TokenType.Operator));
-    _tokens.Add("-", new("-", TokenType.Operator));
-    _tokens.Add("*", new("*", TokenType.Operator));
-    _tokens.Add("/", new("/", TokenType.Operator));
-    _tokens.Add("^", new("^", TokenType.Operator));
-    _tokens.Add("&", new("&", TokenType.Operator));
-    _tokens.Add(">", new(">", TokenType.Operator));
-    _tokens.Add("<", new("<", TokenType.Operator));
-    _tokens.Add("=", new("=", TokenType.Operator));
-    _tokens.Add("<=", new("<=", TokenType.Operator));
-    _tokens.Add(">=", new(">=", TokenType.Operator));
-    _tokens.Add("<>", new("<>", TokenType.Operator));
-    _tokens.Add("(", new("(", TokenType.OpeningParenthesis));
-    _tokens.Add(")", new(")", TokenType.ClosingParenthesis));
-    _tokens.Add("{", new("{", TokenType.OpeningEnumerable));
-    _tokens.Add("}", new("}", TokenType.ClosingEnumerable));
-    _tokens.Add("'", new("'", TokenType.String));
-    _tokens.Add("\"", new("\"", TokenType.String));
-    _tokens.Add(",", new(",", TokenType.Comma));
-    _tokens.Add(";", new(";", TokenType.SemiColon));
-    _tokens.Add("[", new("[", TokenType.OpeningBracket));
-    _tokens.Add("]", new("]", TokenType.ClosingBracket));
-    _tokens.Add("%", new("%", TokenType.Percent));
-  }
-
-  IDictionary<string, Token> ITokenSeparatorProvider.Tokens => _tokens;
-
-  public bool IsOperator(string item) {
-    if (_tokens.TryGetValue(item, out var token)) {
-      if (token.TokenType == TokenType.Operator) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  public bool IsPossibleLastPartOfMultipleCharOperator(string part) {
-    return part == "=" || part == ">";
-  }
-}
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/TokenType.cs b/EPPlus/FormulaParsing/LexicalAnalysis/TokenType.cs
deleted file mode 100644
index a698470..0000000
--- a/EPPlus/FormulaParsing/LexicalAnalysis/TokenType.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-
-public enum TokenType {
-  Operator,
-  Negator,
-  OpeningParenthesis,
-  ClosingParenthesis,
-  OpeningEnumerable,
-  ClosingEnumerable,
-  OpeningBracket,
-  ClosingBracket,
-  Enumerable,
-  Comma,
-  SemiColon,
-  String,
-  StringContent,
-  Integer,
-  Boolean,
-  Decimal,
-  Percent,
-  Function,
-  ExcelAddress,
-  NameValue,
-  InvalidReference,
-  NumericError,
-  ValueDataTypeError,
-  Null,
-  Unrecognized,
-}
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/TokenizerContext.cs b/EPPlus/FormulaParsing/LexicalAnalysis/TokenizerContext.cs
deleted file mode 100644
index 130324d..0000000
--- a/EPPlus/FormulaParsing/LexicalAnalysis/TokenizerContext.cs
+++ /dev/null
@@ -1,95 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-
-public class TokenizerContext {
-  public TokenizerContext(string formula) {
-    if (!string.IsNullOrEmpty(formula)) {
-      _chars = formula.ToArray();
-    }
-  }
-
-  private readonly char[] _chars;
-  private readonly List<Token> _result = new();
-  private StringBuilder _currentToken = new();
-
-  public char[] FormulaChars => _chars;
-
-  public IList<Token> Result => _result;
-
-  public bool IsInString { get; private set; }
-
-  public void ToggleIsInString() {
-    IsInString = !IsInString;
-  }
-
-  internal int BracketCount { get; set; }
-
-  public string CurrentToken => _currentToken.ToString();
-
-  public bool CurrentTokenHasValue =>
-    !string.IsNullOrEmpty(IsInString ? CurrentToken : CurrentToken.Trim());
-
-  public void NewToken() {
-    _currentToken = new();
-  }
-
-  public void AddToken(Token token) {
-    _result.Add(token);
-  }
-
-  public void AppendToCurrentToken(char c) {
-    _currentToken.Append(c.ToString());
-  }
-
-  public void AppendToLastToken(string stringToAppend) {
-    _result.Last().Append(stringToAppend);
-  }
-
-  public void SetLastTokenType(TokenType type) {
-    _result.Last().TokenType = type;
-  }
-
-  public void ReplaceLastToken(Token newToken) {
-    var count = _result.Count;
-    if (count > 0) {
-      _result.RemoveAt(count - 1);
-    }
-    _result.Add(newToken);
-  }
-
-  public Token LastToken => _result.Count > 0 ? _result.Last() : null;
-}
diff --git a/EPPlus/FormulaParsing/Logging/IFormulaParserLogger.cs b/EPPlus/FormulaParsing/Logging/IFormulaParserLogger.cs
deleted file mode 100644
index dc38d9d..0000000
--- a/EPPlus/FormulaParsing/Logging/IFormulaParserLogger.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using System;
-
-namespace OfficeOpenXml.FormulaParsing.Logging;
-
-/// <summary>
-/// Used for logging during FormulaParsing
-/// </summary>
-public interface IFormulaParserLogger : IDisposable {
-  /// <summary>
-  /// Called each time an exception occurs during formula parsing.
-  /// </summary>
-  /// <param name="context"></param>
-  /// <param name="ex"></param>
-  void Log(ParsingContext context, Exception ex);
-
-  /// <summary>
-  /// Called each time information should be logged during formula parsing.
-  /// </summary>
-  /// <param name="context"></param>
-  /// <param name="message"></param>
-  void Log(ParsingContext context, string message);
-
-  /// <summary>
-  /// Called to log a message outside the parsing context.
-  /// </summary>
-  /// <param name="message"></param>
-  void Log(string message);
-
-  /// <summary>
-  /// Called each time a cell within the calc chain is accessed during formula parsing.
-  /// </summary>
-  void LogCellCounted();
-
-  /// <summary>
-  /// Called each time a function is called during formula parsing.
-  /// </summary>
-  /// <param name="func"></param>
-  void LogFunction(string func);
-
-  /// <summary>
-  /// Some functions measure performance, if so this function will be called.
-  /// </summary>
-  /// <param name="func"></param>
-  /// <param name="milliseconds"></param>
-  void LogFunction(string func, long milliseconds);
-}
diff --git a/EPPlus/FormulaParsing/NameValueProvider.cs b/EPPlus/FormulaParsing/NameValueProvider.cs
deleted file mode 100644
index f7b0a8d..0000000
--- a/EPPlus/FormulaParsing/NameValueProvider.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace OfficeOpenXml.FormulaParsing;
-
-public class NameValueProvider : INameValueProvider {
-  private NameValueProvider() {}
-
-  public static INameValueProvider Empty => new NameValueProvider();
-
-  public bool IsNamedValue(string key, string worksheet) {
-    return false;
-  }
-
-  public object GetNamedValue(string key) {
-    return null;
-  }
-
-  public void Reload() {}
-}
diff --git a/EPPlus/FormulaParsing/ParsedValue.cs b/EPPlus/FormulaParsing/ParsedValue.cs
deleted file mode 100644
index 43112b7..0000000
--- a/EPPlus/FormulaParsing/ParsedValue.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-namespace OfficeOpenXml.FormulaParsing;
-
-public class ParsedValue {
-  public ParsedValue(object val, int rowIndex, int colIndex) {
-    Value = val;
-    RowIndex = rowIndex;
-    ColIndex = colIndex;
-  }
-
-  public object Value { get; private set; }
-
-  public int RowIndex { get; private set; }
-
-  public int ColIndex { get; private set; }
-}
diff --git a/EPPlus/FormulaParsing/ParsingConfiguration.cs b/EPPlus/FormulaParsing/ParsingConfiguration.cs
deleted file mode 100644
index 90792b4..0000000
--- a/EPPlus/FormulaParsing/ParsingConfiguration.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-using OfficeOpenXml.FormulaParsing.Excel.Functions;
-using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-using OfficeOpenXml.FormulaParsing.Logging;
-using OfficeOpenXml.FormulaParsing.Utilities;
-
-namespace OfficeOpenXml.FormulaParsing;
-
-public class ParsingConfiguration {
-  public virtual ILexer Lexer { get; private set; }
-
-  public IFormulaParserLogger Logger { get; private set; }
-
-  public IExpressionGraphBuilder GraphBuilder { get; private set; }
-
-  public IExpressionCompiler ExpressionCompiler { get; private set; }
-
-  public FunctionRepository FunctionRepository { get; private set; } = FunctionRepository.Create();
-
-  private ParsingConfiguration() {}
-
-  internal static ParsingConfiguration Create() {
-    return new();
-  }
-
-  public ParsingConfiguration SetLexer(ILexer lexer) {
-    Lexer = lexer;
-    return this;
-  }
-
-  public ParsingConfiguration SetGraphBuilder(IExpressionGraphBuilder graphBuilder) {
-    GraphBuilder = graphBuilder;
-    return this;
-  }
-
-  public ParsingConfiguration SetExpresionCompiler(IExpressionCompiler expressionCompiler) {
-    ExpressionCompiler = expressionCompiler;
-    return this;
-  }
-
-  /// <summary>
-  /// Attaches a logger, errors and log entries will be written to the logger during the parsing process.
-  /// </summary>
-  /// <param name="logger"></param>
-  /// <returns></returns>
-  public ParsingConfiguration AttachLogger(IFormulaParserLogger logger) {
-    Require.That(logger).Named("logger").IsNotNull();
-    Logger = logger;
-    return this;
-  }
-
-  /// <summary>
-  /// if a logger is attached it will be removed.
-  /// </summary>
-  /// <returns></returns>
-  public ParsingConfiguration DetachLogger() {
-    Logger = null;
-    return this;
-  }
-}
diff --git a/EPPlus/FormulaParsing/ParsingContext.cs b/EPPlus/FormulaParsing/ParsingContext.cs
deleted file mode 100644
index 8eee889..0000000
--- a/EPPlus/FormulaParsing/ParsingContext.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-using OfficeOpenXml.FormulaParsing.ExcelUtilities;
-using OfficeOpenXml.FormulaParsing.Logging;
-
-namespace OfficeOpenXml.FormulaParsing;
-
-/// <summary>
-/// Parsing context
-/// </summary>
-public class ParsingContext : IParsingLifetimeEventHandler {
-  private ParsingContext() {}
-
-  /// <summary>
-  /// The <see cref="FormulaParser"/> of the current context.
-  /// </summary>
-  public FormulaParser Parser { get; set; }
-
-  /// <summary>
-  /// The <see cref="ExcelDataProvider"/> is an abstraction on top of
-  /// Excel, in this case EPPlus.
-  /// </summary>
-  public ExcelDataProvider ExcelDataProvider { get; set; }
-
-  /// <summary>
-  /// Utility for handling addresses
-  /// </summary>
-  public RangeAddressFactory RangeAddressFactory { get; set; }
-
-  /// <summary>
-  /// <see cref="INameValueProvider"/> of the current context
-  /// </summary>
-  public INameValueProvider NameValueProvider { get; set; }
-
-  /// <summary>
-  /// Configuration
-  /// </summary>
-  public ParsingConfiguration Configuration { get; set; }
-
-  /// <summary>
-  /// Scopes, a scope represents the parsing of a cell or a value.
-  /// </summary>
-  public ParsingScopes Scopes { get; private set; }
-
-  /// <summary>
-  /// Returns true if a <see cref="IFormulaParserLogger"/> is attached to the parser.
-  /// </summary>
-  public bool Debug => Configuration.Logger != null;
-
-  /// <summary>
-  /// Factory method.
-  /// </summary>
-  /// <returns></returns>
-  public static ParsingContext Create() {
-    var context = new ParsingContext();
-    context.Configuration = ParsingConfiguration.Create();
-    context.Scopes = new(context);
-    return context;
-  }
-
-  void IParsingLifetimeEventHandler.ParsingCompleted() {}
-}
diff --git a/EPPlus/FormulaParsing/ParsingScope.cs b/EPPlus/FormulaParsing/ParsingScope.cs
deleted file mode 100644
index f901f1e..0000000
--- a/EPPlus/FormulaParsing/ParsingScope.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-using System;
-using OfficeOpenXml.FormulaParsing.ExcelUtilities;
-
-namespace OfficeOpenXml.FormulaParsing;
-
-/// <summary>
-/// Represents a parsing of a single input or workbook addrses.
-/// </summary>
-public class ParsingScope : IDisposable {
-  private readonly ParsingScopes _parsingScopes;
-
-  public ParsingScope(ParsingScopes parsingScopes, RangeAddress address)
-      : this(parsingScopes, null, address) {}
-
-  public ParsingScope(ParsingScopes parsingScopes, ParsingScope parent, RangeAddress address) {
-    _parsingScopes = parsingScopes;
-    Parent = parent;
-    Address = address;
-  }
-
-  /// <summary>
-  /// Id of the scope.
-  /// </summary>
-  public Guid ScopeId { get; private set; } = Guid.NewGuid();
-
-  /// <summary>
-  /// The calling scope.
-  /// </summary>
-  public ParsingScope Parent { get; private set; }
-
-  /// <summary>
-  /// The address of the cell currently beeing parsed.
-  /// </summary>
-  public RangeAddress Address { get; private set; }
-
-  /// <summary>
-  /// True if the current scope is a Subtotal function beeing executed.
-  /// </summary>
-  public bool IsSubtotal { get; set; }
-
-  public void Dispose() {
-    _parsingScopes.KillScope(this);
-  }
-}
diff --git a/EPPlus/FormulaParsing/ParsingScopes.cs b/EPPlus/FormulaParsing/ParsingScopes.cs
deleted file mode 100644
index 66ef836..0000000
--- a/EPPlus/FormulaParsing/ParsingScopes.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using OfficeOpenXml.FormulaParsing.ExcelUtilities;
-
-namespace OfficeOpenXml.FormulaParsing;
-
-/// <summary>
-/// This class implements a stack on which instances of <see cref="ParsingScope"/>
-/// are put. Each ParsingScope represents the parsing of an address in the workbook.
-/// </summary>
-public class ParsingScopes {
-  private readonly IParsingLifetimeEventHandler _lifetimeEventHandler;
-
-  public ParsingScopes(IParsingLifetimeEventHandler lifetimeEventHandler) {
-    _lifetimeEventHandler = lifetimeEventHandler;
-  }
-
-  private readonly Stack<ParsingScope> _scopes = new();
-
-  /// <summary>
-  /// Creates a new <see cref="ParsingScope"/> and puts it on top of the stack.
-  /// </summary>
-  /// <param name="address"></param>
-  /// <returns></returns>
-  public virtual ParsingScope NewScope(RangeAddress address) {
-    ParsingScope scope;
-    if (_scopes.Count() > 0) {
-      scope = new(this, _scopes.Peek(), address);
-    } else {
-      scope = new(this, address);
-    }
-    _scopes.Push(scope);
-    return scope;
-  }
-
-  /// <summary>
-  /// The current parsing scope.
-  /// </summary>
-  public virtual ParsingScope Current => _scopes.Count() > 0 ? _scopes.Peek() : null;
-
-  /// <summary>
-  /// Removes the current scope, setting the calling scope to current.
-  /// </summary>
-  /// <param name="parsingScope"></param>
-  public virtual void KillScope(ParsingScope parsingScope) {
-    _scopes.Pop();
-    if (_scopes.Count() == 0) {
-      _lifetimeEventHandler.ParsingCompleted();
-    }
-  }
-}
diff --git a/EPPlus/FormulaParsing/Utilities/ArgumentInfo.cs b/EPPlus/FormulaParsing/Utilities/ArgumentInfo.cs
deleted file mode 100644
index a0a826f..0000000
--- a/EPPlus/FormulaParsing/Utilities/ArgumentInfo.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-namespace OfficeOpenXml.FormulaParsing.Utilities;
-
-public class ArgumentInfo<T> {
-  public ArgumentInfo(T val) {
-    Value = val;
-  }
-
-  public T Value { get; private set; }
-
-  public string Name { get; private set; }
-
-  public ArgumentInfo<T> Named(string argName) {
-    Name = argName;
-    return this;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Utilities/ExtensionMethods.cs b/EPPlus/FormulaParsing/Utilities/ExtensionMethods.cs
deleted file mode 100644
index 786ec4f..0000000
--- a/EPPlus/FormulaParsing/Utilities/ExtensionMethods.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using System;
-
-namespace OfficeOpenXml.FormulaParsing.Utilities;
-
-public static class ExtensionMethods {
-  public static void IsNotNullOrEmpty(this ArgumentInfo<string> val) {
-    if (string.IsNullOrEmpty(val.Value)) {
-      throw new ArgumentException(val.Name + " cannot be null or empty");
-    }
-  }
-
-  public static void IsNotNull<T>(this ArgumentInfo<T> val)
-      where T : class {
-    if (val.Value == null) {
-      throw new ArgumentNullException(val.Name);
-    }
-  }
-
-  public static bool IsNumeric(this object obj) {
-    if (obj == null) {
-      return false;
-    }
-    return (obj.GetType().IsPrimitive
-            || obj is double
-            || obj is decimal
-            || obj is DateTime
-            || obj is TimeSpan);
-  }
-}
diff --git a/EPPlus/FormulaParsing/Utilities/IdProvider.cs b/EPPlus/FormulaParsing/Utilities/IdProvider.cs
deleted file mode 100644
index 15e02b3..0000000
--- a/EPPlus/FormulaParsing/Utilities/IdProvider.cs
+++ /dev/null
@@ -1,5 +0,0 @@
-namespace OfficeOpenXml.FormulaParsing.Utilities;
-
-public abstract class IdProvider {
-  public abstract object NewId();
-}
diff --git a/EPPlus/FormulaParsing/Utilities/IntegerIdProvider.cs b/EPPlus/FormulaParsing/Utilities/IntegerIdProvider.cs
deleted file mode 100644
index d1a39f4..0000000
--- a/EPPlus/FormulaParsing/Utilities/IntegerIdProvider.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System;
-
-namespace OfficeOpenXml.FormulaParsing.Utilities;
-
-public class IntegerIdProvider : IdProvider {
-  private int _lastId = int.MinValue;
-
-  public override object NewId() {
-    if (_lastId >= int.MaxValue) {
-      throw new InvalidOperationException("IdProvider run out of id:s");
-    }
-    return _lastId++;
-  }
-}
diff --git a/EPPlus/FormulaParsing/Utilities/RegexConstants.cs b/EPPlus/FormulaParsing/Utilities/RegexConstants.cs
deleted file mode 100644
index deba058..0000000
--- a/EPPlus/FormulaParsing/Utilities/RegexConstants.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
- *******************************************************************************/
-
-namespace OfficeOpenXml.FormulaParsing.Utilities;
-
-public static class RegexConstants {
-  public const string SingleCellAddress =
-      @"^(('[^/\\?*\[\]]{1,31}'|[A-Za-z_]{1,31})!)?[A-Z]{1,3}[1-9]{1}[0-9]{0,7}$";
-
-  //Changed JK 26/2-2013
-  public const string ExcelAddress =
-      @"^(('[^/\\?*\[\]]{1,31}'|[A-Za-z_]{1,31})!)?[\$]{0,1}([A-Z]|[A-Z]{1,3}[\$]{0,1}[1-9]{1}[0-9]{0,7})(\:({0,1}[A-Z]|[A-Z]{1,3}[\$]{0,1}[1-9]{1}[0-9]{0,7})){0,1}$";
-
-  //public const string ExcelAddress = @"^([\$]{0,1}([A-Z]{1,3}[\$]{0,1}[0-9]{1,7})(\:([\$]{0,1}[A-Z]{1,3}[\$]{0,1}[0-9]{1,7}){0,1})|([\$]{0,1}[A-Z]{1,3}\:[\$]{0,1}[A-Z]{1,3})|([\$]{0,1}[0-9]{1,7}\:[\$]{0,1}[0-9]{1,7}))$";
-  public const string Boolean = "^(true|false)$";
-  public const string Decimal = @"^[0-9]+\.[0-9]+$";
-  public const string Integer = "^[0-9]+$";
-}
diff --git a/EPPlus/FormulaParsing/Utilities/Require.cs b/EPPlus/FormulaParsing/Utilities/Require.cs
deleted file mode 100644
index 35d53cd..0000000
--- a/EPPlus/FormulaParsing/Utilities/Require.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace OfficeOpenXml.FormulaParsing.Utilities;
-
-public static class Require {
-  public static ArgumentInfo<T> That<T>(T arg) {
-    return new(arg);
-  }
-}
diff --git a/EPPlus/IRangeID.cs b/EPPlus/IRangeID.cs
deleted file mode 100644
index 8ead21d..0000000
--- a/EPPlus/IRangeID.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman          Added       		        2010-02-04
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// Id from a cell, column or row.
-/// </summary>
-internal interface IRangeId {
-  /// <summary>
-  /// This is the id for a cell, row or column.
-  /// The id is a composit of the SheetID, the row number and the column number.
-  /// Bit 1-14 SheetID, Bit 15-28 Column number (0 if entire column), Bit 29- Row number (0 if entire row).
-  /// </summary>
-  ulong RangeID { get; set; }
-}
diff --git a/EPPlus/OfficeProperties.cs b/EPPlus/OfficeProperties.cs
deleted file mode 100644
index e41d226..0000000
--- a/EPPlus/OfficeProperties.cs
+++ /dev/null
@@ -1,265 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan K�llman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan K�llman		                Initial Release		        2009-10-01
- * Jan K�llman                      Total rewrite               2010-03-01
- * Jan K�llman		    License changed GPL-->LGPL  2011-12-27
- * Raziq York                       Added Created & Modified    2014-08-20
- *******************************************************************************/
-
-using System;
-using System.Globalization;
-using System.Xml;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// Provides access to the properties bag of the package
-/// </summary>
-public sealed class OfficeProperties : XmlHelper {
-  private readonly XmlDocument _xmlPropertiesCore;
-  private readonly XmlDocument _xmlPropertiesExtended;
-
-  private readonly Uri _uriPropertiesCore = new("/docProps/core.xml", UriKind.Relative);
-  private readonly Uri _uriPropertiesExtended = new("/docProps/app.xml", UriKind.Relative);
-
-  private readonly XmlHelper _coreHelper;
-  private readonly XmlHelper _extendedHelper;
-
-  /// <summary>
-  /// Provides access to all the office document properties.
-  /// </summary>
-  /// <param name="package"></param>
-  /// <param name="ns"></param>
-  internal OfficeProperties(ExcelPackage package, XmlNamespaceManager ns)
-      : base(ns) {
-    const string coreBaseXml =
-        $"""<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><cp:coreProperties xmlns:cp="{ExcelPackage._schemaCore}" xmlns:dc="{ExcelPackage._schemaDc}" xmlns:dcterms="{ExcelPackage._schemaDcTerms}" xmlns:dcmitype="{ExcelPackage._schemaDcmiType}" xmlns:xsi="{ExcelPackage._schemaXsi}"></cp:coreProperties>""";
-    _xmlPropertiesCore = package.GetOrCreateXmlDocument(
-        _uriPropertiesCore,
-        "application/vnd.openxmlformats-package.core-properties+xml",
-        "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties",
-        coreBaseXml);
-    _coreHelper = XmlHelperFactory.Create(
-        ns,
-        _xmlPropertiesCore.SelectSingleNode("cp:coreProperties", NameSpaceManager));
-
-    const string extendedBaseXml =
-        $"""<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><Properties xmlns:vt="{ExcelPackage._schemaVt}" xmlns="{ExcelPackage._schemaExtended}"></Properties>""";
-    _xmlPropertiesExtended = package.GetOrCreateXmlDocument(
-        _uriPropertiesExtended,
-        "application/vnd.openxmlformats-officedocument.extended-properties+xml",
-        "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties",
-        extendedBaseXml);
-    _extendedHelper = XmlHelperFactory.Create(ns, _xmlPropertiesExtended);
-  }
-
-  private const string _titlePath = "dc:title";
-
-  /// <summary>
-  /// Gets/sets the title property of the document (core property)
-  /// </summary>
-  public string Title {
-    get => _coreHelper.GetXmlNodeString(_titlePath);
-    set => _coreHelper.SetXmlNodeString(_titlePath, value);
-  }
-
-  private const string _subjectPath = "dc:subject";
-
-  /// <summary>
-  /// Gets/sets the subject property of the document (core property)
-  /// </summary>
-  public string Subject {
-    get => _coreHelper.GetXmlNodeString(_subjectPath);
-    set => _coreHelper.SetXmlNodeString(_subjectPath, value);
-  }
-
-  private const string _authorPath = "dc:creator";
-
-  /// <summary>
-  /// Gets/sets the author property of the document (core property)
-  /// </summary>
-  public string Author {
-    get => _coreHelper.GetXmlNodeString(_authorPath);
-    set => _coreHelper.SetXmlNodeString(_authorPath, value);
-  }
-
-  private const string _commentsPath = "dc:description";
-
-  /// <summary>
-  /// Gets/sets the comments property of the document (core property)
-  /// </summary>
-  public string Comments {
-    get => _coreHelper.GetXmlNodeString(_commentsPath);
-    set => _coreHelper.SetXmlNodeString(_commentsPath, value);
-  }
-
-  private const string _keywordsPath = "cp:keywords";
-
-  /// <summary>
-  /// Gets/sets the keywords property of the document (core property)
-  /// </summary>
-  public string Keywords {
-    get => _coreHelper.GetXmlNodeString(_keywordsPath);
-    set => _coreHelper.SetXmlNodeString(_keywordsPath, value);
-  }
-
-  private const string _lastModifiedByPath = "cp:lastModifiedBy";
-
-  /// <summary>
-  /// Gets/sets the lastModifiedBy property of the document (core property)
-  /// </summary>
-  public string LastModifiedBy {
-    get => _coreHelper.GetXmlNodeString(_lastModifiedByPath);
-    set => _coreHelper.SetXmlNodeString(_lastModifiedByPath, value);
-  }
-
-  private const string _lastPrintedPath = "cp:lastPrinted";
-
-  /// <summary>
-  /// Gets/sets the lastPrinted property of the document (core property)
-  /// </summary>
-  public string LastPrinted {
-    get => _coreHelper.GetXmlNodeString(_lastPrintedPath);
-    set => _coreHelper.SetXmlNodeString(_lastPrintedPath, value);
-  }
-
-  private const string _createdPath = "dcterms:created";
-
-  /// <summary>
-  /// Gets/sets the created property of the document (core property)
-  /// </summary>
-  public DateTime Created {
-    get =>
-      DateTime.TryParse(_coreHelper.GetXmlNodeString(_createdPath), out var date)
-          ? date
-          : DateTime.MinValue;
-    set {
-      var dateString = value.ToUniversalTime().ToString("s", CultureInfo.InvariantCulture) + "Z";
-      _coreHelper.SetXmlNodeString(_createdPath, dateString);
-      _coreHelper.SetXmlNodeString(_createdPath + "/@xsi:type", "dcterms:W3CDTF");
-    }
-  }
-
-  private const string _categoryPath = "cp:category";
-
-  /// <summary>
-  /// Gets/sets the category property of the document (core property)
-  /// </summary>
-  public string Category {
-    get => _coreHelper.GetXmlNodeString(_categoryPath);
-    set => _coreHelper.SetXmlNodeString(_categoryPath, value);
-  }
-
-  private const string _contentStatusPath = "cp:contentStatus";
-
-  /// <summary>
-  /// Gets/sets the status property of the document (core property)
-  /// </summary>
-  public string Status {
-    get => _coreHelper.GetXmlNodeString(_contentStatusPath);
-    set => _coreHelper.SetXmlNodeString(_contentStatusPath, value);
-  }
-
-  /// <summary>
-  /// Provides access to the XML document that holds the extended properties of the document (app.xml)
-  /// </summary>
-  public XmlDocument ExtendedPropertiesXml {
-    get {
-      if (_xmlPropertiesExtended == null) {}
-      return (_xmlPropertiesExtended);
-    }
-  }
-
-  private const string _applicationPath = "xp:Properties/xp:Application";
-
-  /// <summary>
-  /// Gets/Set the Application property of the document (extended property)
-  /// </summary>
-  public string Application {
-    get => _extendedHelper.GetXmlNodeString(_applicationPath);
-    set => _extendedHelper.SetXmlNodeString(_applicationPath, value);
-  }
-
-  private const string _hyperlinkBasePath = "xp:Properties/xp:HyperlinkBase";
-
-  /// <summary>
-  /// Gets/sets the HyperlinkBase property of the document (extended property)
-  /// </summary>
-  public Uri HyperlinkBase {
-    get => new(_extendedHelper.GetXmlNodeString(_hyperlinkBasePath), UriKind.Absolute);
-    set => _extendedHelper.SetXmlNodeString(_hyperlinkBasePath, value.AbsoluteUri);
-  }
-
-  private const string _appVersionPath = "xp:Properties/xp:AppVersion";
-
-  /// <summary>
-  /// Gets/Set the AppVersion property of the document (extended property)
-  /// </summary>
-  public string AppVersion {
-    get => _extendedHelper.GetXmlNodeString(_appVersionPath);
-    set => _extendedHelper.SetXmlNodeString(_appVersionPath, value);
-  }
-
-  private const string _companyPath = "xp:Properties/xp:Company";
-
-  /// <summary>
-  /// Gets/sets the Company property of the document (extended property)
-  /// </summary>
-  public string Company {
-    get => _extendedHelper.GetXmlNodeString(_companyPath);
-    set => _extendedHelper.SetXmlNodeString(_companyPath, value);
-  }
-
-  private const string _managerPath = "xp:Properties/xp:Manager";
-
-  /// <summary>
-  /// Gets/sets the Manager property of the document (extended property)
-  /// </summary>
-  public string Manager {
-    get => _extendedHelper.GetXmlNodeString(_managerPath);
-    set => _extendedHelper.SetXmlNodeString(_managerPath, value);
-  }
-
-  private const string _modifiedPath = "dcterms:modified";
-
-  /// <summary>
-  /// Gets/sets the modified property of the document (core property)
-  /// </summary>
-  public DateTime Modified {
-    get =>
-      DateTime.TryParse(_coreHelper.GetXmlNodeString(_modifiedPath), out var date)
-          ? date
-          : DateTime.MinValue;
-    set {
-      var dateString = value.ToUniversalTime().ToString("s", CultureInfo.InvariantCulture) + "Z";
-      _coreHelper.SetXmlNodeString(_modifiedPath, dateString);
-      _coreHelper.SetXmlNodeString(_modifiedPath + "/@xsi:type", "dcterms:W3CDTF");
-    }
-  }
-}
diff --git a/EPPlus/Packaging/ZipPackage.cs b/EPPlus/Packaging/ZipPackage.cs
deleted file mode 100644
index 921c744..0000000
--- a/EPPlus/Packaging/ZipPackage.cs
+++ /dev/null
@@ -1,263 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Jan Källman		Added		25-Oct-2012
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.IO.Compression;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Xml;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.Packaging;
-
-/// <summary>
-/// Specifies whether the target is inside or outside the System.IO.Packaging.Package.
-/// </summary>
-public enum TargetMode {
-  /// <summary>
-  /// The relationship references a part that is inside the package.
-  /// </summary>
-  Internal = 0,
-
-  /// <summary>
-  /// The relationship references a resource that is external to the package.
-  /// </summary>
-  External = 1,
-}
-
-/// <summary>
-/// Represent an OOXML Zip package.
-/// </summary>
-internal class ZipPackage : ZipPackageRelationshipBase {
-  internal class ContentType {
-    internal string Name;
-    internal bool IsExtension;
-    internal string Match;
-
-    public ContentType(string name, bool isExtension, string match) {
-      Name = name;
-      IsExtension = isExtension;
-      Match = match;
-    }
-  }
-
-  private readonly Dictionary<string, ZipPackagePart> Parts = new(
-      StringComparer.InvariantCultureIgnoreCase);
-  internal Dictionary<string, ContentType> _contentTypes = new(
-      StringComparer.InvariantCultureIgnoreCase);
-
-  internal ZipPackage() {
-    AddNew();
-  }
-
-  private void AddNew() {
-    _contentTypes.Add("xml", new(ExcelPackage._schemaXmlExtension, true, "xml"));
-    _contentTypes.Add("rels", new(ExcelPackage._schemaRelsExtension, true, "rels"));
-  }
-
-  internal ZipPackage(Stream stream) {
-    bool hasContentTypeXml = false;
-    if (stream == null || stream.Length == 0) {
-      AddNew();
-    } else {
-      var rels = new Dictionary<string, ZipArchiveEntry>();
-      stream.Seek(0, SeekOrigin.Begin);
-      using var zip = new ZipArchive(stream, ZipArchiveMode.Read, leaveOpen: true);
-      foreach (var e in zip.Entries) {
-        if (e.Length > 0) {
-          if (e.FullName.Equals(
-              "[content_types].xml",
-              StringComparison.InvariantCultureIgnoreCase)) {
-            using var inputStream = e.Open();
-            AddContentTypes(inputStream);
-            hasContentTypeXml = true;
-          } else if (e.FullName.Equals(
-              "_rels/.rels",
-              StringComparison.InvariantCultureIgnoreCase)) {
-            using var inputStream = e.Open();
-            ReadRelation(inputStream, "");
-          } else {
-            if (e.FullName.EndsWith(".rels", StringComparison.InvariantCultureIgnoreCase)) {
-              rels.Add(GetUriKey(e.FullName), e);
-            } else {
-              var data = new byte[e.Length];
-              using var inputStream = e.Open();
-              inputStream.ReadExactly(data);
-              var part = new ZipPackagePart(
-                  this,
-                  e,
-                  ImmutableCollectionsMarshal.AsImmutableArray(data));
-              Parts.Add(GetUriKey(e.FullName), part);
-            }
-          }
-        }
-      }
-      foreach (var p in Parts) {
-        string name = Path.GetFileName(p.Key);
-        string extension = Path.GetExtension(p.Key);
-        string relFile = string.Format(
-            "{0}_rels/{1}.rels",
-            p.Key.Substring(0, p.Key.Length - name.Length),
-            name);
-        if (rels.TryGetValue(relFile, out var zipArchiveEntry)) {
-          using var inputStream = zipArchiveEntry.Open();
-          p.Value.ReadRelation(inputStream, p.Value.Uri.OriginalString);
-        }
-        if (_contentTypes.TryGetValue(p.Key, out var type)) {
-          p.Value.ContentType = type.Name;
-        } else if (extension.Length > 1 && _contentTypes.ContainsKey(extension.Substring(1))) {
-          p.Value.ContentType = _contentTypes[extension.Substring(1)].Name;
-        }
-      }
-      if (!hasContentTypeXml) {
-        throw new InvalidDataException("The file is not an valid Package file.");
-      }
-    }
-  }
-
-  private void AddContentTypes(Stream inputStream) {
-    var doc = new XmlDocument();
-    XmlHelper.LoadXmlSafe(doc, inputStream);
-
-    foreach (XmlElement c in doc.DocumentElement.ChildNodes) {
-      ContentType ct;
-      if (string.IsNullOrEmpty(c.GetAttribute("Extension"))) {
-        ct = new(c.GetAttribute("ContentType"), false, c.GetAttribute("PartName"));
-      } else {
-        ct = new(c.GetAttribute("ContentType"), true, c.GetAttribute("Extension"));
-      }
-      _contentTypes.Add(GetUriKey(ct.Match), ct);
-    }
-  }
-
-  internal void CreatePart(Uri partUri, string contentType, Action<StreamWriter> saveHandler) {
-    if (PartExists(partUri)) {
-      throw (new InvalidOperationException("Part already exist"));
-    }
-
-    var part = new ZipPackagePart(this, partUri, contentType, saveHandler);
-    _contentTypes.Add(
-        GetUriKey(part.Uri.OriginalString),
-        new(contentType, false, part.Uri.OriginalString));
-    Parts.Add(GetUriKey(part.Uri.OriginalString), part);
-  }
-
-  internal ZipPackagePart GetPart(Uri partUri) {
-    if (PartExists(partUri)) {
-      return Parts
-          .Single(x =>
-              x.Key.Equals(
-                  GetUriKey(partUri.OriginalString),
-                  StringComparison.InvariantCultureIgnoreCase))
-          .Value;
-    }
-    throw (new InvalidOperationException("Part does not exist."));
-  }
-
-  internal string GetUriKey(string uri) {
-    string ret = uri;
-    if (ret[0] != '/') {
-      ret = "/" + ret;
-    }
-    return ret;
-  }
-
-  internal bool PartExists(Uri partUri) {
-    var uriKey = GetUriKey(partUri.OriginalString.ToLower(CultureInfo.InvariantCulture));
-    return Parts.Keys.Any(x => x.Equals(uriKey, StringComparison.InvariantCultureIgnoreCase));
-  }
-
-  internal void DeletePart(Uri uri) {
-    var delList = new List<object[]>();
-    foreach (var p in Parts.Values) {
-      foreach (var r in p.GetRelationships()) {
-        if (UriHelper
-            .ResolvePartUri(p.Uri, r.TargetUri)
-            .OriginalString.Equals(
-                uri.OriginalString,
-                StringComparison.InvariantCultureIgnoreCase)) {
-          delList.Add(new object[] { r.Id, p });
-        }
-      }
-    }
-    foreach (var o in delList) {
-      ((ZipPackagePart)o[1]).DeleteRelationship(o[0].ToString());
-    }
-    var rels = GetPart(uri).GetRelationships();
-    while (rels.Count > 0) {
-      rels.Remove(rels.First().Id);
-    }
-    _contentTypes.Remove(GetUriKey(uri.OriginalString));
-    //remove all relations
-    Parts.Remove(GetUriKey(uri.OriginalString));
-  }
-
-  internal void Save(Stream stream) {
-    using var zipArchive = new ZipArchive(stream, ZipArchiveMode.Create, leaveOpen: true);
-    // Content types
-    var contentTypesEntry = zipArchive.CreateEntry("[Content_Types].xml");
-    using (var contentTypesWriter = new StreamWriter(contentTypesEntry.Open())) {
-      contentTypesWriter.Write(GetContentTypeXml());
-    }
-    // Top Rels
-    _rels.WriteZip(zipArchive, "_rels/.rels");
-    ZipPackagePart ssPart = null;
-    foreach (var part in Parts.Values) {
-      if (part.ContentType != ExcelPackage._contentTypeSharedString) {
-        part.WriteZip(zipArchive);
-      } else {
-        ssPart = part;
-      }
-    }
-    //Shared strings must be saved after all worksheets. The ss dictionary is populated when that workheets are saved (to get the best performance).
-    if (ssPart != null) {
-      ssPart.WriteZip(zipArchive);
-    }
-  }
-
-  private string GetContentTypeXml() {
-    StringBuilder xml = new StringBuilder(
-        "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">");
-    foreach (ContentType ct in _contentTypes.Values) {
-      if (ct.IsExtension) {
-        xml.Append($"<Default ContentType=\"{ct.Name}\" Extension=\"{ct.Match}\"/>");
-      } else {
-        xml.Append($"<Override ContentType=\"{ct.Name}\" PartName=\"{GetUriKey(ct.Match)}\" />");
-      }
-    }
-    xml.Append("</Types>");
-    return xml.ToString();
-  }
-}
diff --git a/EPPlus/Packaging/ZipPackagePart.cs b/EPPlus/Packaging/ZipPackagePart.cs
deleted file mode 100644
index 47d20fb..0000000
--- a/EPPlus/Packaging/ZipPackagePart.cs
+++ /dev/null
@@ -1,119 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Jan Källman		Added		25-Oct-2012
- *******************************************************************************/
-
-using System;
-using System.Collections.Immutable;
-using System.IO;
-using System.IO.Compression;
-using System.Runtime.InteropServices;
-
-namespace OfficeOpenXml.Packaging;
-
-internal class ZipPackagePart : ZipPackageRelationshipBase, IDisposable {
-  internal ZipPackagePart(ZipPackage package, ZipArchiveEntry entry, ImmutableArray<byte> data) {
-    Package = package;
-    SaveHandler = null;
-    Uri = new(package.GetUriKey(entry.FullName), UriKind.Relative);
-    _data = data;
-  }
-
-  private readonly ImmutableArray<byte> _data;
-
-  internal ZipPackagePart(
-      ZipPackage package,
-      Uri partUri,
-      string contentType,
-      Action<StreamWriter> saveHandler) {
-    Package = package;
-    Uri = partUri;
-    ContentType = contentType;
-    SaveHandler = saveHandler;
-  }
-
-  private ZipPackage Package { get; }
-
-  internal override ZipPackageRelationship CreateRelationship(
-      Uri targetUri,
-      TargetMode targetMode,
-      string relationshipType) {
-    var rel = base.CreateRelationship(targetUri, targetMode, relationshipType);
-    rel.SourceUri = Uri;
-    return rel;
-  }
-
-  internal MemoryStream GetStream() {
-    return new(ImmutableCollectionsMarshal.AsArray(_data) ?? [], false);
-  }
-
-  private string _contentType = "";
-
-  public string ContentType {
-    get => _contentType;
-    internal set {
-      if (!string.IsNullOrEmpty(_contentType)) {
-        if (Package._contentTypes.ContainsKey(Package.GetUriKey(Uri.OriginalString))) {
-          Package._contentTypes.Remove(Package.GetUriKey(Uri.OriginalString));
-          Package._contentTypes.Add(
-              Package.GetUriKey(Uri.OriginalString),
-              new(value, false, Uri.OriginalString));
-        }
-      }
-      _contentType = value;
-    }
-  }
-
-  public Uri Uri { get; }
-
-  internal Action<StreamWriter> SaveHandler { get; set; }
-
-  internal void WriteZip(ZipArchive zipArchive) {
-    if (SaveHandler == null) {
-      if (_data.Length == 0) {
-        return;
-      }
-      var zipEntry = zipArchive.CreateEntry(Uri.OriginalString);
-      using var os = zipEntry.Open();
-      os.Write(_data.AsSpan());
-    } else {
-      var zipEntry = zipArchive.CreateEntry(Uri.OriginalString);
-      using var streamWriter = new StreamWriter(zipEntry.Open());
-      SaveHandler(streamWriter);
-    }
-
-    if (_rels.Count > 0) {
-      string f = Uri.OriginalString;
-      var name = Path.GetFileName(f);
-      _rels.WriteZip(zipArchive, $"{f.Substring(0, f.Length - name.Length)}_rels/{name}.rels");
-    }
-  }
-
-  public void Dispose() {}
-}
diff --git a/EPPlus/Packaging/ZipPackageRelationship.cs b/EPPlus/Packaging/ZipPackageRelationship.cs
deleted file mode 100644
index 1d76501..0000000
--- a/EPPlus/Packaging/ZipPackageRelationship.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Jan Källman		Added		25-Oct-2012
- *******************************************************************************/
-
-using System;
-
-namespace OfficeOpenXml.Packaging;
-
-internal class ZipPackageRelationship {
-  public Uri TargetUri { get; internal set; }
-
-  public Uri SourceUri { get; internal set; }
-
-  public string RelationshipType { get; internal set; }
-
-  public TargetMode TargetMode { get; internal set; }
-
-  public string Id { get; internal set; }
-}
diff --git a/EPPlus/Packaging/ZipPackageRelationshipBase.cs b/EPPlus/Packaging/ZipPackageRelationshipBase.cs
deleted file mode 100644
index ff9bf8f..0000000
--- a/EPPlus/Packaging/ZipPackageRelationshipBase.cs
+++ /dev/null
@@ -1,123 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Jan Källman		Added		25-Oct-2012
- *******************************************************************************/
-
-using System;
-using System.IO;
-using System.Xml;
-
-namespace OfficeOpenXml.Packaging;
-
-internal abstract class ZipPackageRelationshipBase {
-  protected ZipPackageRelationshipCollection _rels = new();
-  protected internal int maxRId = 1;
-
-  internal void DeleteRelationship(string id) {
-    _rels.Remove(id);
-    UpdateMaxRId(id, ref maxRId);
-  }
-
-  protected void UpdateMaxRId(string id, ref int maxRId) {
-    if (id.StartsWith("rId")) {
-      if (int.TryParse(id.Substring(3), out var num)) {
-        if (num == maxRId - 1) {
-          maxRId--;
-        }
-      }
-    }
-  }
-
-  internal virtual ZipPackageRelationship CreateRelationship(
-      Uri targetUri,
-      TargetMode targetMode,
-      string relationshipType) {
-    var rel = new ZipPackageRelationship();
-    rel.TargetUri = targetUri;
-    rel.TargetMode = targetMode;
-    rel.RelationshipType = relationshipType;
-    rel.Id = "rId" + (maxRId++);
-    _rels.Add(rel);
-    return rel;
-  }
-
-  internal bool RelationshipExists(string id) {
-    return _rels.ContainsKey(id);
-  }
-
-  internal ZipPackageRelationshipCollection GetRelationshipsByType(string schema) {
-    return _rels.GetRelationshipsByType(schema);
-  }
-
-  internal ZipPackageRelationshipCollection GetRelationships() {
-    return _rels;
-  }
-
-  internal ZipPackageRelationship GetRelationship(string id) {
-    return _rels[id];
-  }
-
-  internal void ReadRelation(Stream inputStream, string source) {
-    var doc = new XmlDocument();
-    XmlHelper.LoadXmlSafe(doc, inputStream);
-
-    foreach (XmlElement c in doc.DocumentElement.ChildNodes) {
-      var rel = new ZipPackageRelationship();
-      rel.Id = c.GetAttribute("Id");
-      rel.RelationshipType = c.GetAttribute("Type");
-      rel.TargetMode = c.GetAttribute("TargetMode")
-          .Equals("external", StringComparison.InvariantCultureIgnoreCase)
-          ? TargetMode.External
-          : TargetMode.Internal;
-      try {
-        rel.TargetUri = new(c.GetAttribute("Target"), UriKind.RelativeOrAbsolute);
-      } catch {
-        //The URI is not a valid URI. Encode it to make i valid.
-        rel.TargetUri = new(
-            Uri.EscapeUriString("Invalid:URI " + c.GetAttribute("Target")),
-            UriKind.RelativeOrAbsolute);
-      }
-      if (!string.IsNullOrEmpty(source)) {
-        rel.SourceUri = new(source, UriKind.Relative);
-      }
-      if (rel.Id.StartsWith("rid", StringComparison.InvariantCultureIgnoreCase)) {
-        if (int.TryParse(rel.Id.Substring(3), out var id)) {
-          if (id >= maxRId
-              && id
-                  < int.MaxValue
-                      - 10000) //Not likly to have this high id's but make sure we have space to avoid overflow.
-          {
-            maxRId = id + 1;
-          }
-        }
-      }
-      _rels.Add(rel);
-    }
-  }
-}
diff --git a/EPPlus/Packaging/ZipPackageRelationshipCollection.cs b/EPPlus/Packaging/ZipPackageRelationshipCollection.cs
deleted file mode 100644
index 7890ad6..0000000
--- a/EPPlus/Packaging/ZipPackageRelationshipCollection.cs
+++ /dev/null
@@ -1,95 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- *******************************************************************************
- * Jan Källman		Added		25-Oct-2012
- *******************************************************************************/
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.IO;
-using System.IO.Compression;
-using System.Security;
-
-namespace OfficeOpenXml.Packaging;
-
-internal class ZipPackageRelationshipCollection : IEnumerable<ZipPackageRelationship> {
-  protected internal Dictionary<string, ZipPackageRelationship> _rels = new(
-      StringComparer.InvariantCultureIgnoreCase);
-
-  internal void Add(ZipPackageRelationship item) {
-    _rels.Add(item.Id, item);
-  }
-
-  public IEnumerator<ZipPackageRelationship> GetEnumerator() {
-    return _rels.Values.GetEnumerator();
-  }
-
-  IEnumerator IEnumerable.GetEnumerator() {
-    return _rels.Values.GetEnumerator();
-  }
-
-  internal void Remove(string id) {
-    _rels.Remove(id);
-  }
-
-  internal bool ContainsKey(string id) {
-    return _rels.ContainsKey(id);
-  }
-
-  internal ZipPackageRelationship this[string id] => _rels[id];
-
-  internal ZipPackageRelationshipCollection GetRelationshipsByType(string relationshipType) {
-    var ret = new ZipPackageRelationshipCollection();
-    foreach (var rel in _rels.Values) {
-      if (rel.RelationshipType == relationshipType) {
-        ret.Add(rel);
-      }
-    }
-    return ret;
-  }
-
-  internal void WriteZip(ZipArchive zipArchive, string filename) {
-    var entry = zipArchive.CreateEntry(filename);
-    using var writer = new StreamWriter(entry.Open());
-
-    writer.Write(
-        "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">");
-    foreach (var rel in _rels.Values) {
-      writer.Write(
-          "<Relationship Id=\"{0}\" Type=\"{1}\" Target=\"{2}\"{3}/>",
-          SecurityElement.Escape(rel.Id),
-          rel.RelationshipType,
-          SecurityElement.Escape(rel.TargetUri.OriginalString),
-          rel.TargetMode == TargetMode.External ? " TargetMode=\"External\"" : "");
-    }
-    writer.Write("</Relationships>");
-  }
-
-  public int Count => _rels.Count;
-}
diff --git a/EPPlus/RangeCollection.cs b/EPPlus/RangeCollection.cs
deleted file mode 100644
index c7f8218..0000000
--- a/EPPlus/RangeCollection.cs
+++ /dev/null
@@ -1,277 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		    Added       		        2010-02-04
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// This is the store for all Rows, Columns and Cells.
-/// It is a Dictionary implementation that allows you to change the Key (the RowID, ColumnID or CellID )
-/// </summary>
-internal class RangeCollection : IEnumerator<IRangeId>, IEnumerable, IDisposable {
-  private class IndexItem {
-    internal IndexItem(ulong cellId) {
-      RangeID = cellId;
-    }
-
-    internal IndexItem(ulong cellId, int listPointer) {
-      RangeID = cellId;
-      ListPointer = listPointer;
-    }
-
-    internal ulong RangeID;
-    internal int ListPointer;
-  }
-
-  /// <summary>
-  /// Compares an IndexItem
-  /// </summary>
-  internal class Compare : IComparer<IndexItem> {
-    int IComparer<IndexItem>.Compare(IndexItem x, IndexItem y) {
-      return x.RangeID < y.RangeID
-          ? -1
-          : x.RangeID > y.RangeID
-              ? 1
-              : 0;
-    }
-  }
-
-  private IndexItem[] _cellIndex;
-  private List<IRangeId> _cells;
-  private static readonly Compare _comparer = new();
-
-  /// <summary>
-  /// Creates a new collection
-  /// </summary>
-  /// <param name="cells">The Cells. This list must be sorted</param>
-  internal RangeCollection(List<IRangeId> cells) {
-    _cells = cells;
-    InitSize(_cells);
-    for (int i = 0; i < _cells.Count; i++) {
-      _cellIndex[i] = new(cells[i].RangeID, i);
-    }
-  }
-
-  ~RangeCollection() {
-    _cells = null;
-    _cellIndex = null;
-  }
-
-  /// <summary>
-  /// Return the item with the RangeID
-  /// </summary>
-  /// <param name="rangeId"></param>
-  /// <returns></returns>
-  internal IRangeId this[ulong rangeId] => _cells[_cellIndex[IndexOf(rangeId)].ListPointer];
-
-  /// <summary>
-  /// Return specified index from the sorted list
-  /// </summary>
-  /// <param name="index"></param>
-  /// <returns></returns>
-  internal IRangeId this[int index] => _cells[_cellIndex[index].ListPointer];
-
-  internal int Count => _cells.Count;
-
-  internal void Add(IRangeId cell) {
-    var ix = IndexOf(cell.RangeID);
-    if (ix >= 0) {
-      throw (new("Item already exists"));
-    }
-    Insert(~ix, cell);
-  }
-
-  internal void Delete(ulong key) {
-    var ix = IndexOf(key);
-    if (ix < 0) {
-      throw (new("Key does not exists"));
-    }
-    int listPointer = _cellIndex[ix].ListPointer;
-    Array.Copy(_cellIndex, ix + 1, _cellIndex, ix, _cells.Count - ix - 1);
-    _cells.RemoveAt(listPointer);
-
-    //Item is removed subtract one from all items with greater ListPointer
-    for (int i = 0; i < _cells.Count; i++) {
-      if (_cellIndex[i].ListPointer >= listPointer) {
-        _cellIndex[i].ListPointer--;
-      }
-    }
-  }
-
-  internal int IndexOf(ulong key) {
-    return Array.BinarySearch(_cellIndex, 0, _cells.Count, new(key), _comparer);
-  }
-
-  internal bool ContainsKey(ulong key) {
-    return IndexOf(key) < 0 ? false : true;
-  }
-
-  private int _size { get; set; }
-
-  /// <summary>
-  /// Insert a number of rows in the collecion but dont update the cell only the index
-  /// </summary>
-  /// <param name="rowId"></param>
-  /// <param name="rows"></param>
-  /// <returns>Index of first rangeItem</returns>
-  internal int InsertRowsUpdateIndex(ulong rowId, int rows) {
-    int index = IndexOf(rowId);
-    if (index < 0) {
-      index = ~index; //No match found invert to get start cell
-    }
-    ulong rowAdd = (((ulong)rows) << 29);
-    for (int i = index; i < _cells.Count; i++) {
-      _cellIndex[i].RangeID += rowAdd;
-    }
-    return index;
-  }
-
-  /// <summary>
-  /// Insert a number of rows in the collecion
-  /// </summary>
-  /// <param name="rowId"></param>
-  /// <param name="rows"></param>
-  /// <returns>Index of first rangeItem</returns>
-  internal int InsertRows(ulong rowId, int rows) {
-    int index = IndexOf(rowId);
-    if (index < 0) {
-      index = ~index; //No match found invert to get start cell
-    }
-    ulong rowAdd = (((ulong)rows) << 29);
-    for (int i = index; i < _cells.Count; i++) {
-      _cellIndex[i].RangeID += rowAdd;
-      _cells[_cellIndex[i].ListPointer].RangeID += rowAdd;
-    }
-    return index;
-  }
-
-  /// <summary>
-  /// Delete rows from the collecion
-  /// </summary>
-  /// <param name="rowId"></param>
-  /// <param name="rows"></param>
-  /// <param name="updateCells">Update range id's on cells</param>
-  internal int DeleteRows(ulong rowId, int rows, bool updateCells) {
-    ulong rowAdd = (((ulong)rows) << 29);
-    var index = IndexOf(rowId);
-    if (index < 0) {
-      index = ~index; //No match found invert to get start cell
-    }
-
-    if (index >= _cells.Count || _cellIndex[index] == null) {
-      return -1; //No row above this row
-    }
-    while (index < _cells.Count && _cellIndex[index].RangeID < rowId + rowAdd) {
-      Delete(_cellIndex[index].RangeID);
-    }
-
-    int updIndex = IndexOf(rowId + rowAdd);
-    if (updIndex < 0) {
-      updIndex = ~updIndex; //No match found invert to get start cell
-    }
-
-    for (int i = updIndex; i < _cells.Count; i++) {
-      _cellIndex[i].RangeID -= rowAdd; //Change the index
-      if (updateCells) {
-        _cells[_cellIndex[i].ListPointer].RangeID -= rowAdd; //Change the cell/row or column object
-      }
-    }
-    return index;
-  }
-
-  internal void InsertColumn(ulong columnId, int columns) {
-    throw (new("Working on it..."));
-  }
-
-  internal void DeleteColumn(ulong columnId, int columns) {
-    throw (new("Working on it..."));
-  }
-
-  /// <summary>
-  /// Init the size starting from 128 items. Double the size until the list fits.
-  /// </summary>
-  /// <param name="_cells"></param>
-  private void InitSize(List<IRangeId> cells) {
-    _size = 128;
-    while (cells.Count > _size) {
-      _size <<= 1;
-    }
-    _cellIndex = new IndexItem[_size];
-  }
-
-  /// <summary>
-  /// Check the size and double the size if out of bound
-  /// </summary>
-  private void CheckSize() {
-    if (_cells.Count >= _size) {
-      _size <<= 1;
-      Array.Resize(ref _cellIndex, _size);
-    }
-  }
-
-  private void Insert(int ix, IRangeId cell) {
-    CheckSize();
-    Array.Copy(_cellIndex, ix, _cellIndex, ix + 1, _cells.Count - ix);
-    _cellIndex[ix] = new(cell.RangeID, _cells.Count);
-    _cells.Add(cell);
-  }
-
-  IRangeId IEnumerator<IRangeId>.Current {
-    get { throw new NotImplementedException(); }
-  }
-
-  void IDisposable.Dispose() {
-    _ix = -1;
-  }
-
-  private int _ix = -1;
-
-  object IEnumerator.Current {
-    get { return _cells[_cellIndex[_ix].ListPointer]; }
-  }
-
-  bool IEnumerator.MoveNext() {
-    _ix++;
-    return _ix < _cells.Count;
-  }
-
-  void IEnumerator.Reset() {
-    _ix = -1;
-  }
-
-  IEnumerator IEnumerable.GetEnumerator() {
-    return MemberwiseClone() as IEnumerator;
-  }
-}
diff --git a/EPPlus/Style/Dxf/DxfStyleBase.cs b/EPPlus/Style/Dxf/DxfStyleBase.cs
deleted file mode 100644
index b81e07a..0000000
--- a/EPPlus/Style/Dxf/DxfStyleBase.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-using System;
-using System.Globalization;
-
-namespace OfficeOpenXml.Style.Dxf;
-
-public abstract class DxfStyleBase<T> {
-  protected ExcelStyles _styles;
-
-  internal DxfStyleBase(ExcelStyles styles) {
-    _styles = styles;
-  }
-
-  protected internal abstract string Id { get; }
-
-  protected internal abstract bool HasValue { get; }
-
-  protected internal abstract void CreateNodes(XmlHelper helper, string path);
-
-  protected internal abstract T Clone();
-
-  protected void SetValueColor(XmlHelper helper, string path, ExcelDxfColor color) {
-    if (color != null && color.HasValue) {
-      if (color.Rgb != null) {
-        SetValue(helper, path + "/@rgb", color.Rgb);
-      } else if (color.Auto != null) {
-        SetValueBool(helper, path + "/@auto", color.Auto);
-      } else if (color.Theme != null) {
-        SetValue(helper, path + "/@theme", color.Theme);
-      } else if (color.Index != null) {
-        SetValue(helper, path + "/@indexed", color.Index);
-      }
-      if (color.Tint != null) {
-        SetValue(helper, path + "/@tint", color.Tint);
-      }
-    }
-  }
-
-  /// <summary>
-  /// Same as SetValue but will set first char to lower case.
-  /// </summary>
-  /// <param name="helper"></param>
-  /// <param name="path"></param>
-  /// <param name="v"></param>
-  protected void SetValueEnum(XmlHelper helper, string path, Enum v) {
-    if (v == null) {
-      helper.DeleteNode(path);
-    } else {
-      var s = v.ToString();
-      s = s.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + s.Substring(1);
-      helper.SetXmlNodeString(path, s);
-    }
-  }
-
-  protected void SetValue(XmlHelper helper, string path, object v) {
-    if (v == null) {
-      helper.DeleteNode(path);
-    } else {
-      helper.SetXmlNodeString(path, v.ToString());
-    }
-  }
-
-  protected void SetValueBool(XmlHelper helper, string path, bool? v) {
-    if (v == null) {
-      helper.DeleteNode(path);
-    } else {
-      helper.SetXmlNodeBool(path, (bool)v);
-    }
-  }
-
-  protected string GetAsString(object v) {
-    return (v ?? "").ToString();
-  }
-
-  /// <summary>
-  /// Is this value allowed to be changed?
-  /// </summary>
-  protected internal bool AllowChange { get; set; } = false;
-}
diff --git a/EPPlus/Style/Dxf/ExcelDxfBorder.cs b/EPPlus/Style/Dxf/ExcelDxfBorder.cs
deleted file mode 100644
index 12bcc84..0000000
--- a/EPPlus/Style/Dxf/ExcelDxfBorder.cs
+++ /dev/null
@@ -1,81 +0,0 @@
-namespace OfficeOpenXml.Style.Dxf;
-
-public class ExcelDxfBorderBase : DxfStyleBase<ExcelDxfBorderBase> {
-  internal ExcelDxfBorderBase(ExcelStyles styles)
-      : base(styles) {
-    Left = new(_styles);
-    Right = new(_styles);
-    Top = new(_styles);
-    Bottom = new(_styles);
-  }
-
-  /// <summary>
-  /// Left border style
-  /// </summary>
-  public ExcelDxfBorderItem Left { get; internal set; }
-
-  /// <summary>
-  /// Right border style
-  /// </summary>
-  public ExcelDxfBorderItem Right { get; internal set; }
-
-  /// <summary>
-  /// Top border style
-  /// </summary>
-  public ExcelDxfBorderItem Top { get; internal set; }
-
-  /// <summary>
-  /// Bottom border style
-  /// </summary>
-  public ExcelDxfBorderItem Bottom { get; internal set; }
-
-  ///// <summary>
-  ///// Diagonal border style
-  ///// </summary>
-  //public ExcelDxfBorderItem Diagonal
-  //{
-  //    get;
-  //    private set;
-  //}
-  ///// <summary>
-  ///// A diagonal from the bottom left to top right of the cell
-  ///// </summary>
-  //public bool DiagonalUp
-  //{
-  //    get;
-  //    set;
-  //}
-  ///// <summary>
-  ///// A diagonal from the top left to bottom right of the cell
-  ///// </summary>
-  //public bool DiagonalDown
-  //{
-  //    get;
-  //    set;
-  //}
-
-  protected internal override string Id =>
-    Top.Id
-        + Bottom.Id
-        + Left.Id
-        + Right.Id /* + Diagonal.Id + GetAsString(DiagonalUp) + GetAsString(DiagonalDown)*/;
-
-  protected internal override void CreateNodes(XmlHelper helper, string path) {
-    Left.CreateNodes(helper, path + "/d:left");
-    Right.CreateNodes(helper, path + "/d:right");
-    Top.CreateNodes(helper, path + "/d:top");
-    Bottom.CreateNodes(helper, path + "/d:bottom");
-  }
-
-  protected internal override bool HasValue =>
-    Left.HasValue || Right.HasValue || Top.HasValue || Bottom.HasValue;
-
-  protected internal override ExcelDxfBorderBase Clone() {
-    return new(_styles) {
-      Bottom = Bottom.Clone(),
-      Top = Top.Clone(),
-      Left = Left.Clone(),
-      Right = Right.Clone(),
-    };
-  }
-}
diff --git a/EPPlus/Style/Dxf/ExcelDxfBorderItem.cs b/EPPlus/Style/Dxf/ExcelDxfBorderItem.cs
deleted file mode 100644
index f068605..0000000
--- a/EPPlus/Style/Dxf/ExcelDxfBorderItem.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-namespace OfficeOpenXml.Style.Dxf;
-
-public class ExcelDxfBorderItem : DxfStyleBase<ExcelDxfBorderItem> {
-  internal ExcelDxfBorderItem(ExcelStyles styles)
-      : base(styles) {
-    Color = new(styles);
-  }
-
-  public ExcelBorderStyle? Style { get; set; }
-
-  public ExcelDxfColor Color { get; internal set; }
-
-  protected internal override string Id =>
-    GetAsString(Style) + "|" + (Color == null ? "" : Color.Id);
-
-  protected internal override void CreateNodes(XmlHelper helper, string path) {
-    SetValueEnum(helper, path + "/@style", Style);
-    SetValueColor(helper, path + "/d:color", Color);
-  }
-
-  protected internal override bool HasValue => Style != null || Color.HasValue;
-
-  protected internal override ExcelDxfBorderItem Clone() {
-    return new(_styles) {
-      Style = Style,
-      Color = Color,
-    };
-  }
-}
diff --git a/EPPlus/Style/Dxf/ExcelDxfColor.cs b/EPPlus/Style/Dxf/ExcelDxfColor.cs
deleted file mode 100644
index d22a7f9..0000000
--- a/EPPlus/Style/Dxf/ExcelDxfColor.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using System;
-
-namespace OfficeOpenXml.Style.Dxf;
-
-public class ExcelDxfColor : DxfStyleBase<ExcelDxfColor> {
-  public ExcelDxfColor(ExcelStyles styles)
-      : base(styles) {}
-
-  public int? Theme { get; set; }
-
-  public int? Index { get; set; }
-
-  public bool? Auto { get; set; }
-
-  public double? Tint { get; set; }
-
-  public string Rgb { get; set; }
-
-  protected internal override string Id =>
-    GetAsString(Theme)
-        + "|"
-        + GetAsString(Index)
-        + "|"
-        + GetAsString(Auto)
-        + "|"
-        + GetAsString(Tint)
-        + "|"
-        + GetAsString(Rgb);
-
-  protected internal override ExcelDxfColor Clone() {
-    return new(_styles) {
-      Theme = Theme,
-      Index = Index,
-      Rgb = Rgb,
-      Auto = Auto,
-      Tint = Tint,
-    };
-  }
-
-  protected internal override bool HasValue =>
-    Theme != null || Index != null || Auto != null || Tint != null || Rgb != null;
-
-  protected internal override void CreateNodes(XmlHelper helper, string path) {
-    throw new NotImplementedException();
-  }
-}
diff --git a/EPPlus/Style/Dxf/ExcelDxfFill.cs b/EPPlus/Style/Dxf/ExcelDxfFill.cs
deleted file mode 100644
index f4bf1d3..0000000
--- a/EPPlus/Style/Dxf/ExcelDxfFill.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-namespace OfficeOpenXml.Style.Dxf;
-
-public class ExcelDxfFill : DxfStyleBase<ExcelDxfFill> {
-  public ExcelDxfFill(ExcelStyles styles)
-      : base(styles) {
-    PatternColor = new(styles);
-    BackgroundColor = new(styles);
-  }
-
-  public ExcelFillStyle? PatternType { get; set; }
-
-  /// <summary>
-  /// The color of the pattern
-  /// </summary>
-  public ExcelDxfColor PatternColor { get; internal set; }
-
-  /// <summary>
-  /// The background color
-  /// </summary>
-  public ExcelDxfColor BackgroundColor { get; internal set; }
-
-  protected internal override string Id =>
-    GetAsString(PatternType)
-        + "|"
-        + (PatternColor == null ? "" : PatternColor.Id)
-        + "|"
-        + (BackgroundColor == null ? "" : BackgroundColor.Id);
-
-  protected internal override void CreateNodes(XmlHelper helper, string path) {
-    helper.CreateNode(path);
-    SetValueEnum(helper, path + "/d:patternFill/@patternType", PatternType);
-    SetValueColor(helper, path + "/d:patternFill/d:fgColor", PatternColor);
-    SetValueColor(helper, path + "/d:patternFill/d:bgColor", BackgroundColor);
-  }
-
-  protected internal override bool HasValue =>
-    PatternType != null || PatternColor.HasValue || BackgroundColor.HasValue;
-
-  protected internal override ExcelDxfFill Clone() {
-    return new(_styles) {
-      PatternType = PatternType,
-      PatternColor = PatternColor.Clone(),
-      BackgroundColor = BackgroundColor.Clone(),
-    };
-  }
-}
diff --git a/EPPlus/Style/Dxf/ExcelDxfFontBase.cs b/EPPlus/Style/Dxf/ExcelDxfFontBase.cs
deleted file mode 100644
index aae7d61..0000000
--- a/EPPlus/Style/Dxf/ExcelDxfFontBase.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-namespace OfficeOpenXml.Style.Dxf;
-
-public class ExcelDxfFontBase : DxfStyleBase<ExcelDxfFontBase> {
-  public ExcelDxfFontBase(ExcelStyles styles)
-      : base(styles) {
-    Color = new(styles);
-  }
-
-  /// <summary>
-  /// Font bold
-  /// </summary>
-  public bool? Bold { get; set; }
-
-  /// <summary>
-  /// Font Italic
-  /// </summary>
-  public bool? Italic { get; set; }
-
-  /// <summary>
-  /// Font-Strikeout
-  /// </summary>
-  public bool? Strike { get; set; }
-
-  //public float? Size { get; set; }
-  public ExcelDxfColor Color { get; set; }
-
-  //public string Name { get; set; }
-  //public int? Family { get; set; }
-  ///// <summary>
-  ///// Font-Vertical Align
-  ///// </summary>
-  //public ExcelVerticalAlignmentFont? VerticalAlign
-  //{
-  //    get;
-  //    set;
-  //}
-
-  public ExcelUnderLineType? Underline { get; set; }
-
-  protected internal override string Id =>
-    GetAsString(Bold)
-        + "|"
-        + GetAsString(Italic)
-        + "|"
-        + GetAsString(Strike)
-        + "|"
-        + (Color == null ? "" : Color.Id)
-        + "|" /*+ GetAsString(VerticalAlign) + "|"*/
-        + GetAsString(Underline);
-
-  protected internal override void CreateNodes(XmlHelper helper, string path) {
-    helper.CreateNode(path);
-    SetValueBool(helper, path + "/d:b/@val", Bold);
-    SetValueBool(helper, path + "/d:i/@val", Italic);
-    SetValueBool(helper, path + "/d:strike", Strike);
-    SetValue(helper, path + "/d:u/@val", Underline);
-    SetValueColor(helper, path + "/d:color", Color);
-  }
-
-  protected internal override bool HasValue =>
-    Bold != null || Italic != null || Strike != null || Underline != null || Color.HasValue;
-
-  protected internal override ExcelDxfFontBase Clone() {
-    return new(_styles) {
-      Bold = Bold,
-      Color = Color.Clone(),
-      Italic = Italic,
-      Strike = Strike,
-      Underline = Underline,
-    };
-  }
-}
diff --git a/EPPlus/Style/Dxf/ExcelDxfNumberFormat.cs b/EPPlus/Style/Dxf/ExcelDxfNumberFormat.cs
deleted file mode 100644
index e00114c..0000000
--- a/EPPlus/Style/Dxf/ExcelDxfNumberFormat.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-namespace OfficeOpenXml.Style.Dxf;
-
-public class ExcelDxfNumberFormat : DxfStyleBase<ExcelDxfNumberFormat> {
-  public ExcelDxfNumberFormat(ExcelStyles styles)
-      : base(styles) {}
-
-  private int _numFmtID = int.MinValue;
-
-  /// <summary>
-  /// Id for number format
-  ///
-  /// Build in ID's
-  ///
-  /// 0   General
-  /// 1   0
-  /// 2   0.00
-  /// 3   #,##0
-  /// 4   #,##0.00
-  /// 9   0%
-  /// 10  0.00%
-  /// 11  0.00E+00
-  /// 12  # ?/?
-  /// 13  # ??/??
-  /// 14  mm-dd-yy
-  /// 15  d-mmm-yy
-  /// 16  d-mmm
-  /// 17  mmm-yy
-  /// 18  h:mm AM/PM
-  /// 19  h:mm:ss AM/PM
-  /// 20  h:mm
-  /// 21  h:mm:ss
-  /// 22  m/d/yy h:mm
-  /// 37  #,##0 ;(#,##0)
-  /// 38  #,##0 ;[Red](#,##0)
-  /// 39  #,##0.00;(#,##0.00)
-  /// 40  #,##0.00;[Red](#,##0.00)
-  /// 45  mm:ss
-  /// 46  [h]:mm:ss
-  /// 47  mmss.0
-  /// 48  ##0.0E+0
-  /// 49  @
-  /// </summary>
-  public int NumFmtID {
-    get => _numFmtID;
-    internal set => _numFmtID = value;
-  }
-
-  private string _format = "";
-
-  public string Format {
-    get => _format;
-    set {
-      _format = value;
-      NumFmtID = ExcelNumberFormat.GetFromBuildIdFromFormat(value);
-    }
-  }
-
-  protected internal override string Id => Format;
-
-  protected internal override void CreateNodes(XmlHelper helper, string path) {
-    if (NumFmtID < 0 && !string.IsNullOrEmpty(Format)) {
-      NumFmtID = _styles._nextDfxNumFmtID++;
-    }
-    helper.CreateNode(path);
-    SetValue(helper, path + "/@numFmtId", NumFmtID);
-    SetValue(helper, path + "/@formatCode", Format);
-  }
-
-  protected internal override bool HasValue => !string.IsNullOrEmpty(Format);
-
-  protected internal override ExcelDxfNumberFormat Clone() {
-    return new(_styles) {
-      NumFmtID = NumFmtID,
-      Format = Format,
-    };
-  }
-}
diff --git a/EPPlus/Style/Dxf/ExcelDxfStyle.cs b/EPPlus/Style/Dxf/ExcelDxfStyle.cs
deleted file mode 100644
index 4784a1e..0000000
--- a/EPPlus/Style/Dxf/ExcelDxfStyle.cs
+++ /dev/null
@@ -1,135 +0,0 @@
-using System;
-using System.Collections.Immutable;
-using System.Globalization;
-using System.Xml;
-
-namespace OfficeOpenXml.Style.Dxf;
-
-public class ExcelDxfStyleConditionalFormatting : DxfStyleBase<ExcelDxfStyleConditionalFormatting> {
-  private readonly DxfStyleXmlHelper _helper;
-
-  private class DxfStyleXmlHelper(XmlNamespaceManager nameSpaceManager, XmlNode topNode)
-      : XmlHelper(nameSpaceManager, topNode) {
-    protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
-      "font",
-      "numFmt",
-      "fill",
-      "border",
-    ];
-  }
-
-  internal ExcelDxfStyleConditionalFormatting(
-      XmlNamespaceManager nameSpaceManager,
-      XmlNode topNode,
-      ExcelStyles styles)
-      : base(styles) {
-    NumberFormat = new(_styles);
-    Font = new(_styles);
-    Border = new(_styles);
-    Fill = new(_styles);
-    if (topNode != null) {
-      _helper = new(nameSpaceManager, topNode);
-      NumberFormat.NumFmtID = _helper.GetXmlNodeInt("d:numFmt/@numFmtId");
-      NumberFormat.Format = _helper.GetXmlNodeString("d:numFmt/@formatCode");
-      if (NumberFormat.NumFmtID < 164 && string.IsNullOrEmpty(NumberFormat.Format)) {
-        NumberFormat.Format = ExcelNumberFormat.GetFromBuildInFromId(NumberFormat.NumFmtID);
-      }
-
-      Font.Bold = _helper.GetXmlNodeBoolNullable("d:font/d:b/@val");
-      Font.Italic = _helper.GetXmlNodeBoolNullable("d:font/d:i/@val");
-      Font.Strike = _helper.GetXmlNodeBoolNullable("d:font/d:strike");
-      Font.Underline = GetUnderLineEnum(_helper.GetXmlNodeString("d:font/d:u/@val"));
-      Font.Color = GetColor(_helper, "d:font/d:color");
-
-      Border.Left = GetBorderItem(_helper, "d:border/d:left");
-      Border.Right = GetBorderItem(_helper, "d:border/d:right");
-      Border.Bottom = GetBorderItem(_helper, "d:border/d:bottom");
-      Border.Top = GetBorderItem(_helper, "d:border/d:top");
-
-      Fill.PatternType = GetPatternTypeEnum(
-          _helper.GetXmlNodeString("d:fill/d:patternFill/@patternType"));
-      Fill.BackgroundColor = GetColor(_helper, "d:fill/d:patternFill/d:bgColor/");
-      Fill.PatternColor = GetColor(_helper, "d:fill/d:patternFill/d:fgColor/");
-    } else {
-      _helper = new(nameSpaceManager, null);
-    }
-  }
-
-  private ExcelDxfBorderItem GetBorderItem(XmlHelper helper, string path) {
-    ExcelDxfBorderItem bi = new ExcelDxfBorderItem(_styles);
-    bi.Style = GetBorderStyleEnum(helper.GetXmlNodeString(path + "/@style"));
-    bi.Color = GetColor(helper, path + "/d:color");
-    return bi;
-  }
-
-  private ExcelBorderStyle GetBorderStyleEnum(string style) =>
-    Enum.TryParse<ExcelBorderStyle>(style, true, out var result) ? result : ExcelBorderStyle.None;
-
-  private ExcelFillStyle GetPatternTypeEnum(string patternType) =>
-    Enum.TryParse<ExcelFillStyle>(patternType, true, out var result) ? result : ExcelFillStyle.None;
-
-  private ExcelDxfColor GetColor(XmlHelper helper, string path) {
-    ExcelDxfColor ret = new ExcelDxfColor(_styles);
-    ret.Theme = helper.GetXmlNodeIntNull(path + "/@theme");
-    ret.Index = helper.GetXmlNodeIntNull(path + "/@indexed");
-    ret.Rgb = helper.GetXmlNodeString(path + "/@rgb");
-    ret.Auto = helper.GetXmlNodeBoolNullable(path + "/@auto");
-    ret.Tint = helper.GetXmlNodeDoubleNull(path + "/@tint");
-    return ret;
-  }
-
-  private ExcelUnderLineType? GetUnderLineEnum(string value) {
-    switch (value.ToLower(CultureInfo.InvariantCulture)) {
-      case "single":
-        return ExcelUnderLineType.Single;
-      case "double":
-        return ExcelUnderLineType.Double;
-      case "singleaccounting":
-        return ExcelUnderLineType.SingleAccounting;
-      case "doubleaccounting":
-        return ExcelUnderLineType.DoubleAccounting;
-      default:
-        return null;
-    }
-  }
-
-  internal int DxfId { get; set; }
-
-  public ExcelDxfFontBase Font { get; set; }
-
-  public ExcelDxfNumberFormat NumberFormat { get; set; }
-
-  public ExcelDxfFill Fill { get; set; }
-
-  public ExcelDxfBorderBase Border { get; set; }
-
-  protected internal override string Id =>
-    NumberFormat.Id + Font.Id + Border.Id + Fill.Id + (AllowChange ? "" : DxfId.ToString()); //If allowchange is false we add the dxfID to ensure it's not used when conditional formatting is updated);
-
-  protected internal override ExcelDxfStyleConditionalFormatting Clone() {
-    var s = new ExcelDxfStyleConditionalFormatting(_helper.NameSpaceManager, null, _styles);
-    s.Font = Font.Clone();
-    s.NumberFormat = NumberFormat.Clone();
-    s.Fill = Fill.Clone();
-    s.Border = Border.Clone();
-    return s;
-  }
-
-  protected internal override void CreateNodes(XmlHelper helper, string path) {
-    if (Font.HasValue) {
-      Font.CreateNodes(helper, "d:font");
-    }
-    if (NumberFormat.HasValue) {
-      NumberFormat.CreateNodes(helper, "d:numFmt");
-    }
-    if (Fill.HasValue) {
-      Fill.CreateNodes(helper, "d:fill");
-    }
-    if (Border.HasValue) {
-      Border.CreateNodes(helper, "d:border");
-    }
-  }
-
-  protected internal override bool HasValue =>
-    Font.HasValue || NumberFormat.HasValue || Fill.HasValue || Border.HasValue;
-}
diff --git a/EPPlus/Style/ExcelBorder.cs b/EPPlus/Style/ExcelBorder.cs
deleted file mode 100644
index 55889fb..0000000
--- a/EPPlus/Style/ExcelBorder.cs
+++ /dev/null
@@ -1,105 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		                Initial Release		        2009-10-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-namespace OfficeOpenXml.Style;
-
-/// <summary>
-/// Cell Border style
-/// </summary>
-public sealed class Border : StyleBase {
-  internal Border(
-      ExcelStyles styles,
-      XmlHelper.ChangedEventHandler changedEvent,
-      int positionId,
-      string address,
-      int index)
-      : base(styles, changedEvent, positionId, address) {
-    Index = index;
-  }
-
-  /// <summary>
-  /// Left border style
-  /// </summary>
-  public ExcelBorderItem Left =>
-    new(_styles, _ChangedEvent, _positionID, _address, eStyleClass.BorderLeft, this);
-
-  /// <summary>
-  /// Right border style
-  /// </summary>
-  public ExcelBorderItem Right =>
-    new(_styles, _ChangedEvent, _positionID, _address, eStyleClass.BorderRight, this);
-
-  /// <summary>
-  /// Top border style
-  /// </summary>
-  public ExcelBorderItem Top =>
-    new(_styles, _ChangedEvent, _positionID, _address, eStyleClass.BorderTop, this);
-
-  /// <summary>
-  /// Bottom border style
-  /// </summary>
-  public ExcelBorderItem Bottom =>
-    new(_styles, _ChangedEvent, _positionID, _address, eStyleClass.BorderBottom, this);
-
-  /// <summary>
-  /// 0Diagonal border style
-  /// </summary>
-  public ExcelBorderItem Diagonal =>
-    new(_styles, _ChangedEvent, _positionID, _address, eStyleClass.BorderDiagonal, this);
-
-  /// <summary>
-  /// A diagonal from the bottom left to top right of the cell
-  /// </summary>
-  public bool DiagonalUp {
-    get {
-      if (Index >= 0) {
-        return _styles.Borders[Index].DiagonalUp;
-      }
-      return false;
-    }
-  }
-
-  /// <summary>
-  /// A diagonal from the top left to bottom right of the cell
-  /// </summary>
-  public bool DiagonalDown {
-    get {
-      if (Index >= 0) {
-        return _styles.Borders[Index].DiagonalDown;
-      }
-      return false;
-    }
-  }
-
-  internal override string Id =>
-    Top.Id + Bottom.Id + Left.Id + Right.Id + Diagonal.Id + DiagonalUp + DiagonalDown;
-}
diff --git a/EPPlus/Style/ExcelBorderItem.cs b/EPPlus/Style/ExcelBorderItem.cs
deleted file mode 100644
index 89dc283..0000000
--- a/EPPlus/Style/ExcelBorderItem.cs
+++ /dev/null
@@ -1,99 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		                Initial Release		        2009-10-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using OfficeOpenXml.Style.XmlAccess;
-
-namespace OfficeOpenXml.Style;
-
-/// <summary>
-/// Cell border style
-/// </summary>
-public sealed class ExcelBorderItem : StyleBase {
-  private readonly eStyleClass _cls;
-  private readonly StyleBase _parent;
-
-  internal ExcelBorderItem(
-      ExcelStyles styles,
-      XmlHelper.ChangedEventHandler changedEvent,
-      int worksheetId,
-      string address,
-      eStyleClass cls,
-      StyleBase parent)
-      : base(styles, changedEvent, worksheetId, address) {
-    _cls = cls;
-    _parent = parent;
-  }
-
-  /// <summary>
-  /// The line style of the border
-  /// </summary>
-  public ExcelBorderStyle Style => GetSource().Style;
-
-  private ExcelColor _color;
-
-  /// <summary>
-  /// The color of the border
-  /// </summary>
-  public ExcelColor Color {
-    get {
-      if (_color == null) {
-        _color = new(_styles, _ChangedEvent, _positionID, _address, _cls, _parent);
-      }
-      return _color;
-    }
-  }
-
-  internal override string Id => Style + Color.Id;
-
-  internal override void SetIndex(int index) {
-    _parent.Index = index;
-  }
-
-  private ExcelBorderItemXml GetSource() {
-    int ix = _parent.Index < 0 ? 0 : _parent.Index;
-
-    switch (_cls) {
-      case eStyleClass.BorderTop:
-        return _styles.Borders[ix].Top;
-      case eStyleClass.BorderBottom:
-        return _styles.Borders[ix].Bottom;
-      case eStyleClass.BorderLeft:
-        return _styles.Borders[ix].Left;
-      case eStyleClass.BorderRight:
-        return _styles.Borders[ix].Right;
-      case eStyleClass.BorderDiagonal:
-        return _styles.Borders[ix].Diagonal;
-      default:
-        throw new("Invalid class for Borderitem");
-    }
-  }
-}
diff --git a/EPPlus/Style/ExcelColor.cs b/EPPlus/Style/ExcelColor.cs
deleted file mode 100644
index e02de45..0000000
--- a/EPPlus/Style/ExcelColor.cs
+++ /dev/null
@@ -1,105 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		                Initial Release		        2009-10-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using OfficeOpenXml.Style.XmlAccess;
-
-namespace OfficeOpenXml.Style;
-
-/// <summary>
-/// Color for cellstyling
-/// </summary>
-public sealed class ExcelColor : StyleBase {
-  private readonly eStyleClass _cls;
-  private readonly StyleBase _parent;
-
-  internal ExcelColor(
-      ExcelStyles styles,
-      XmlHelper.ChangedEventHandler changedEvent,
-      int worksheetId,
-      string address,
-      eStyleClass cls,
-      StyleBase parent)
-      : base(styles, changedEvent, worksheetId, address) {
-    _parent = parent;
-    _cls = cls;
-  }
-
-  /// <summary>
-  /// The theme color
-  /// </summary>
-  public string Theme => GetSource().Theme;
-
-  /// <summary>
-  /// The tint value
-  /// </summary>
-  public decimal Tint => GetSource().Tint;
-
-  /// <summary>
-  /// The RGB value
-  /// </summary>
-  public string Rgb => GetSource().Rgb;
-
-  /// <summary>
-  /// The indexed color number.
-  /// </summary>
-  public int Indexed => GetSource().Indexed;
-
-  internal override string Id => Theme + Tint + Rgb + Indexed;
-
-  private ExcelColorXml GetSource() {
-    Index = _parent.Index < 0 ? 0 : _parent.Index;
-    switch (_cls) {
-      case eStyleClass.FillBackgroundColor:
-        return _styles.Fills[Index].BackgroundColor;
-      case eStyleClass.FillPatternColor:
-        return _styles.Fills[Index].PatternColor;
-      case eStyleClass.Font:
-        return _styles.Fonts[Index].Color;
-      case eStyleClass.BorderLeft:
-        return _styles.Borders[Index].Left.Color;
-      case eStyleClass.BorderTop:
-        return _styles.Borders[Index].Top.Color;
-      case eStyleClass.BorderRight:
-        return _styles.Borders[Index].Right.Color;
-      case eStyleClass.BorderBottom:
-        return _styles.Borders[Index].Bottom.Color;
-      case eStyleClass.BorderDiagonal:
-        return _styles.Borders[Index].Diagonal.Color;
-      default:
-        throw (new("Invalid style-class for Color"));
-    }
-  }
-
-  internal override void SetIndex(int index) {
-    _parent.Index = index;
-  }
-}
diff --git a/EPPlus/Style/ExcelFill.cs b/EPPlus/Style/ExcelFill.cs
deleted file mode 100644
index 09193d7..0000000
--- a/EPPlus/Style/ExcelFill.cs
+++ /dev/null
@@ -1,131 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		                Initial Release		        2009-10-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-namespace OfficeOpenXml.Style;
-
-/// <summary>
-/// The background fill of a cell
-/// </summary>
-public class ExcelFill : StyleBase {
-  internal ExcelFill(
-      ExcelStyles styles,
-      XmlHelper.ChangedEventHandler changedEvent,
-      int positionId,
-      string address,
-      int index)
-      : base(styles, changedEvent, positionId, address) {
-    Index = index;
-  }
-
-  /// <summary>
-  /// The pattern for solid fills.
-  /// </summary>
-  public ExcelFillStyle PatternType {
-    get {
-      if (Index == int.MinValue) {
-        return ExcelFillStyle.None;
-      }
-      return _styles.Fills[Index].PatternType;
-    }
-  }
-
-  private ExcelColor _patternColor;
-
-  /// <summary>
-  /// The color of the pattern
-  /// </summary>
-  public ExcelColor PatternColor {
-    get {
-      if (_patternColor == null) {
-        _patternColor = new(
-            _styles,
-            _ChangedEvent,
-            _positionID,
-            _address,
-            eStyleClass.FillPatternColor,
-            this);
-        if (_gradient != null) {
-          _gradient = null;
-        }
-      }
-      return _patternColor;
-    }
-  }
-
-  private ExcelColor _backgroundColor;
-
-  /// <summary>
-  /// The background color
-  /// </summary>
-  public ExcelColor BackgroundColor {
-    get {
-      if (_backgroundColor == null) {
-        _backgroundColor = new(
-            _styles,
-            _ChangedEvent,
-            _positionID,
-            _address,
-            eStyleClass.FillBackgroundColor,
-            this);
-        if (_gradient != null) {
-          _gradient = null;
-        }
-      }
-      return _backgroundColor;
-    }
-  }
-
-  private ExcelGradientFill _gradient;
-
-  /// <summary>
-  /// Access to properties for gradient fill.
-  /// </summary>
-  public ExcelGradientFill Gradient {
-    get {
-      if (_gradient == null) {
-        _gradient = new(_styles, _ChangedEvent, _positionID, _address, Index);
-        _backgroundColor = null;
-        _patternColor = null;
-      }
-      return _gradient;
-    }
-  }
-
-  internal override string Id {
-    get {
-      if (_gradient == null) {
-        return PatternType + PatternColor.Id + BackgroundColor.Id;
-      }
-      return _gradient.Id;
-    }
-  }
-}
diff --git a/EPPlus/Style/ExcelFont.cs b/EPPlus/Style/ExcelFont.cs
deleted file mode 100644
index 528c3c6..0000000
--- a/EPPlus/Style/ExcelFont.cs
+++ /dev/null
@@ -1,124 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		                Initial Release		        2009-10-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System;
-
-namespace OfficeOpenXml.Style;
-
-/// <summary>
-/// Cell style Font
-/// </summary>
-public sealed class ExcelFont : StyleBase {
-  internal ExcelFont(
-      ExcelStyles styles,
-      XmlHelper.ChangedEventHandler changedEvent,
-      int positionId,
-      string address,
-      int index)
-      : base(styles, changedEvent, positionId, address) {
-    Index = index;
-  }
-
-  /// <summary>
-  /// The name of the font
-  /// </summary>
-  public string Name => _styles.Fonts[Index].Name;
-
-  /// <summary>
-  /// The Size of the font
-  /// </summary>
-  public float Size => _styles.Fonts[Index].Size;
-
-  /// <summary>
-  /// Font family
-  /// </summary>
-  public int Family => _styles.Fonts[Index].Family;
-
-  /// <summary>
-  /// Cell color
-  /// </summary>
-  public ExcelColor Color =>
-    new(_styles, _ChangedEvent, _positionID, _address, eStyleClass.Font, this);
-
-  /// <summary>
-  /// Scheme
-  /// </summary>
-  public string Scheme => _styles.Fonts[Index].Scheme;
-
-  /// <summary>
-  /// Font-bold
-  /// </summary>
-  public bool Bold {
-    get => _styles.Fonts[Index].Bold;
-    set =>
-      _ChangedEvent(this, new(eStyleClass.Font, eStyleProperty.Bold, value, _positionID, _address));
-  }
-
-  /// <summary>
-  /// Font-italic
-  /// </summary>
-  public bool Italic => _styles.Fonts[Index].Italic;
-
-  /// <summary>
-  /// Font-Strikeout
-  /// </summary>
-  public bool Strike => _styles.Fonts[Index].Strike;
-
-  /// <summary>
-  /// Font-Underline
-  /// </summary>
-  public bool UnderLine => _styles.Fonts[Index].UnderLine;
-
-  public ExcelUnderLineType UnderLineType => _styles.Fonts[Index].UnderLineType;
-
-  /// <summary>
-  /// Font-Vertical Align
-  /// </summary>
-  public ExcelVerticalAlignmentFont VerticalAlign =>
-    Enum.TryParse<ExcelVerticalAlignmentFont>(
-        _styles.Fonts[Index].VerticalAlign,
-        true,
-        out var result)
-        ? result
-        : ExcelVerticalAlignmentFont.None;
-
-  internal override string Id =>
-    Name
-        + Size
-        + Family
-        + Scheme
-        + Bold.ToString()[0]
-        + Italic.ToString()[0]
-        + Strike.ToString()[0]
-        + UnderLine.ToString()[0]
-        + VerticalAlign;
-}
diff --git a/EPPlus/Style/ExcelGradientFill.cs b/EPPlus/Style/ExcelGradientFill.cs
deleted file mode 100644
index 4ab355e..0000000
--- a/EPPlus/Style/ExcelGradientFill.cs
+++ /dev/null
@@ -1,123 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		                Initial Release		        2009-10-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using OfficeOpenXml.Style.XmlAccess;
-
-namespace OfficeOpenXml.Style;
-
-/// <summary>
-/// The background fill of a cell
-/// </summary>
-public class ExcelGradientFill : StyleBase {
-  internal ExcelGradientFill(
-      ExcelStyles styles,
-      XmlHelper.ChangedEventHandler changedEvent,
-      int positionId,
-      string address,
-      int index)
-      : base(styles, changedEvent, positionId, address) {
-    Index = index;
-  }
-
-  /// <summary>
-  /// Angle of the linear gradient
-  /// </summary>
-  public double Degree => ((ExcelGradientFillXml)_styles.Fills[Index]).Degree;
-
-  /// <summary>
-  /// Linear or Path gradient
-  /// </summary>
-  public ExcelFillGradientType Type => ((ExcelGradientFillXml)_styles.Fills[Index]).Type;
-
-  /// <summary>
-  /// Specifies in percentage format(from the top to the bottom) the position of the top edge of the inner rectangle (color 1). For top, 0 means the top edge of the inner rectangle is on the top edge of the cell, and 1 means it is on the bottom edge of the cell. (applies to From Corner and From Center gradients).
-  /// </summary>
-  public double Top => ((ExcelGradientFillXml)_styles.Fills[Index]).Top;
-
-  /// <summary>
-  /// Specifies in percentage format (from the top to the bottom) the position of the bottom edge of the inner rectangle (color 1). For bottom, 0 means the bottom edge of the inner rectangle is on the top edge of the cell, and 1 means it is on the bottom edge of the cell.
-  /// </summary>
-  public double Bottom => ((ExcelGradientFillXml)_styles.Fills[Index]).Bottom;
-
-  /// <summary>
-  /// Specifies in percentage format (from the left to the right) the position of the left edge of the inner rectangle (color 1). For left, 0 means the left edge of the inner rectangle is on the left edge of the cell, and 1 means it is on the right edge of the cell. (applies to From Corner and From Center gradients).
-  /// </summary>
-  public double Left => ((ExcelGradientFillXml)_styles.Fills[Index]).Left;
-
-  /// <summary>
-  /// Specifies in percentage format (from the left to the right) the position of the right edge of the inner rectangle (color 1). For right, 0 means the right edge of the inner rectangle is on the left edge of the cell, and 1 means it is on the right edge of the cell. (applies to From Corner and From Center gradients).
-  /// </summary>
-  public double Right => ((ExcelGradientFillXml)_styles.Fills[Index]).Right;
-
-  private ExcelColor _gradientColor1;
-
-  /// <summary>
-  /// Gradient Color 1
-  /// </summary>
-  public ExcelColor Color1 {
-    get {
-      if (_gradientColor1 == null) {
-        _gradientColor1 = new(
-            _styles,
-            _ChangedEvent,
-            _positionID,
-            _address,
-            eStyleClass.FillGradientColor1,
-            this);
-      }
-      return _gradientColor1;
-    }
-  }
-
-  private ExcelColor _gradientColor2;
-
-  /// <summary>
-  /// Gradient Color 2
-  /// </summary>
-  public ExcelColor Color2 {
-    get {
-      if (_gradientColor2 == null) {
-        _gradientColor2 = new(
-            _styles,
-            _ChangedEvent,
-            _positionID,
-            _address,
-            eStyleClass.FillGradientColor2,
-            this);
-      }
-      return _gradientColor2;
-    }
-  }
-
-  internal override string Id =>
-    Degree.ToString() + Type + Color1.Id + Color2.Id + Top + Bottom + Left + Right;
-}
diff --git a/EPPlus/Style/ExcelNumberFormat.cs b/EPPlus/Style/ExcelNumberFormat.cs
deleted file mode 100644
index 32d88ac..0000000
--- a/EPPlus/Style/ExcelNumberFormat.cs
+++ /dev/null
@@ -1,210 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		                Initial Release		        2009-10-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-namespace OfficeOpenXml.Style;
-
-/// <summary>
-/// The numberformat of the cell
-/// </summary>
-public sealed class ExcelNumberFormat : StyleBase {
-  internal ExcelNumberFormat(
-      ExcelStyles styles,
-      XmlHelper.ChangedEventHandler changedEvent,
-      int positionId,
-      string address,
-      int index)
-      : base(styles, changedEvent, positionId, address) {
-    Index = index;
-  }
-
-  /// <summary>
-  /// The numeric index fror the format
-  /// </summary>
-  public int NumFmtID => Index;
-
-  /// <summary>
-  /// The numberformat
-  /// </summary>
-  public string Format {
-    get {
-      for (int i = 0; i < _styles.NumberFormats.Count; i++) {
-        if (Index == _styles.NumberFormats[i].NumFmtId) {
-          return _styles.NumberFormats[i].Format;
-        }
-      }
-      return "general";
-    }
-    set =>
-      _ChangedEvent(
-          this,
-          new(
-              eStyleClass.Numberformat,
-              eStyleProperty.Format,
-              (string.IsNullOrEmpty(value) ? "General" : value),
-              _positionID,
-              _address));
-  }
-
-  internal override string Id => Format;
-
-  /// <summary>
-  /// If the numeric format is a build-in from.
-  /// </summary>
-  public bool BuildIn { get; private set; }
-
-  internal static string GetFromBuildInFromId(int numFmtId) {
-    switch (numFmtId) {
-      case 0:
-        return "General";
-      case 1:
-        return "0";
-      case 2:
-        return "0.00";
-      case 3:
-        return "#,##0";
-      case 4:
-        return "#,##0.00";
-      case 9:
-        return "0%";
-      case 10:
-        return "0.00%";
-      case 11:
-        return "0.00E+00";
-      case 12:
-        return "# ?/?";
-      case 13:
-        return "# ??/??";
-      case 14:
-        return "mm-dd-yy";
-      case 15:
-        return "d-mmm-yy";
-      case 16:
-        return "d-mmm";
-      case 17:
-        return "mmm-yy";
-      case 18:
-        return "h:mm AM/PM";
-      case 19:
-        return "h:mm:ss AM/PM";
-      case 20:
-        return "h:mm";
-      case 21:
-        return "h:mm:ss";
-      case 22:
-        return "m/d/yy h:mm";
-      case 37:
-        return "#,##0 ;(#,##0)";
-      case 38:
-        return "#,##0 ;[Red](#,##0)";
-      case 39:
-        return "#,##0.00;(#,##0.00)";
-      case 40:
-        return "#,##0.00;[Red](#,##0.00)";
-      case 45:
-        return "mm:ss";
-      case 46:
-        return "[h]:mm:ss";
-      case 47:
-        return "mmss.0";
-      case 48:
-        return "##0.0";
-      case 49:
-        return "@";
-      default:
-        return string.Empty;
-    }
-  }
-
-  internal static int GetFromBuildIdFromFormat(string format) {
-    switch (format) {
-      case "General":
-      case "":
-        return 0;
-      case "0":
-        return 1;
-      case "0.00":
-        return 2;
-      case "#,##0":
-        return 3;
-      case "#,##0.00":
-        return 4;
-      case "0%":
-        return 9;
-      case "0.00%":
-        return 10;
-      case "0.00E+00":
-        return 11;
-      case "# ?/?":
-        return 12;
-      case "# ??/??":
-        return 13;
-      case "mm-dd-yy":
-        return 14;
-      case "d-mmm-yy":
-        return 15;
-      case "d-mmm":
-        return 16;
-      case "mmm-yy":
-        return 17;
-      case "h:mm AM/PM":
-        return 18;
-      case "h:mm:ss AM/PM":
-        return 19;
-      case "h:mm":
-        return 20;
-      case "h:mm:ss":
-        return 21;
-      case "m/d/yy h:mm":
-        return 22;
-      case "#,##0 ;(#,##0)":
-        return 37;
-      case "#,##0 ;[Red](#,##0)":
-        return 38;
-      case "#,##0.00;(#,##0.00)":
-        return 39;
-      case "#,##0.00;[Red](#,##0.00)":
-        return 40;
-      case "mm:ss":
-        return 45;
-      case "[h]:mm:ss":
-        return 46;
-      case "mmss.0":
-        return 47;
-      case "##0.0":
-        return 48;
-      case "@":
-        return 49;
-      default:
-        return int.MinValue;
-    }
-  }
-}
diff --git a/EPPlus/Style/ExcelRichText.cs b/EPPlus/Style/ExcelRichText.cs
deleted file mode 100644
index 3e9994e..0000000
--- a/EPPlus/Style/ExcelRichText.cs
+++ /dev/null
@@ -1,277 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		                Initial Release		        2009-10-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- * Richard Tallent					Fix inadvertent removal of XML node					2012-10-31
- * Richard Tallent					Remove VertAlign node if no alignment specified		2012-10-31
- *******************************************************************************/
-
-using System;
-using System.Collections.Immutable;
-using System.Globalization;
-using System.Xml;
-
-namespace OfficeOpenXml.Style;
-
-/// <summary>
-/// A richtext part
-/// </summary>
-public class ExcelRichText : XmlHelper {
-  protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
-    "rPr",
-    "t",
-    "b",
-    "i",
-    "strike",
-    "u",
-    "vertAlign",
-    "sz",
-    "color",
-    "rFont",
-    "family",
-    "scheme",
-    "charset",
-  ];
-
-  internal ExcelRichText(
-      XmlNamespaceManager ns,
-      XmlNode topNode,
-      ExcelRichTextCollection collection)
-      : base(ns, topNode) {
-    _collection = collection;
-  }
-
-  internal delegate void CallbackDelegate();
-
-  private CallbackDelegate _callback;
-
-  internal void SetCallback(CallbackDelegate callback) {
-    _callback = callback;
-  }
-
-  private const string _textPath = "d:t";
-
-  /// <summary>
-  /// The text
-  /// </summary>
-  public string Text {
-    get {
-      // Bug 15151
-      if (TopNode.Name == "t") {
-        return TopNode.InnerText;
-      }
-      return GetXmlNodeString(_textPath);
-    }
-    set {
-      _collection.ConvertRichtext();
-      // Don't remove if blank -- setting a blank rich text value on a node is common,
-      // for example when applying both bold and italic to text.
-      SetXmlNodeString(_textPath, value, false);
-      if (PreserveSpace) {
-        XmlElement elem = TopNode.SelectSingleNode(_textPath, NameSpaceManager) as XmlElement;
-        elem.SetAttribute("xml:space", "preserve");
-      }
-      if (_callback != null) {
-        _callback();
-      }
-    }
-  }
-
-  /// <summary>
-  /// Preserves whitespace. Default true
-  /// </summary>
-  public bool PreserveSpace {
-    get {
-      XmlElement elem = TopNode.SelectSingleNode(_textPath, NameSpaceManager) as XmlElement;
-      if (elem != null) {
-        return elem.GetAttribute("xml:space") == "preserve";
-      }
-      return false;
-    }
-    set {
-      _collection.ConvertRichtext();
-      XmlElement elem = TopNode.SelectSingleNode(_textPath, NameSpaceManager) as XmlElement;
-      if (elem != null) {
-        if (value) {
-          elem.SetAttribute("xml:space", "preserve");
-        } else {
-          elem.RemoveAttribute("xml:space");
-        }
-      }
-      if (_callback != null) {
-        _callback();
-      }
-    }
-  }
-
-  private const string _boldPath = "d:rPr/d:b";
-
-  /// <summary>
-  /// Bold text
-  /// </summary>
-  public bool Bold {
-    get => ExistNode(_boldPath);
-    set {
-      _collection.ConvertRichtext();
-      if (value) {
-        CreateNode(_boldPath);
-      } else {
-        DeleteNode(_boldPath);
-      }
-      if (_callback != null) {
-        _callback();
-      }
-    }
-  }
-
-  private const string _italicPath = "d:rPr/d:i";
-
-  /// <summary>
-  /// Italic text
-  /// </summary>
-  public bool Italic {
-    get =>
-      //return GetXmlNodeBool(ITALIC_PATH, false);
-      ExistNode(_italicPath);
-    set {
-      _collection.ConvertRichtext();
-      if (value) {
-        CreateNode(_italicPath);
-      } else {
-        DeleteNode(_italicPath);
-      }
-      if (_callback != null) {
-        _callback();
-      }
-    }
-  }
-
-  private const string _strikePath = "d:rPr/d:strike";
-
-  /// <summary>
-  /// Strike-out text
-  /// </summary>
-  public bool Strike {
-    get => ExistNode(_strikePath);
-    set {
-      _collection.ConvertRichtext();
-      if (value) {
-        CreateNode(_strikePath);
-      } else {
-        DeleteNode(_strikePath);
-      }
-      if (_callback != null) {
-        _callback();
-      }
-    }
-  }
-
-  private const string _underlinePath = "d:rPr/d:u";
-
-  /// <summary>
-  /// Underlined text
-  /// </summary>
-  public bool UnderLine {
-    get => ExistNode(_underlinePath);
-    set {
-      _collection.ConvertRichtext();
-      if (value) {
-        CreateNode(_underlinePath);
-      } else {
-        DeleteNode(_underlinePath);
-      }
-      if (_callback != null) {
-        _callback();
-      }
-    }
-  }
-
-  private const string _vertAlignPath = "d:rPr/d:vertAlign/@val";
-
-  /// <summary>
-  /// Vertical Alignment
-  /// </summary>
-  public ExcelVerticalAlignmentFont VerticalAlign =>
-    Enum.TryParse<ExcelVerticalAlignmentFont>(
-        GetXmlNodeString(TopNode, _vertAlignPath),
-        true,
-        out var result)
-        ? result
-        : ExcelVerticalAlignmentFont.None;
-
-  private const string _sizePath = "d:rPr/d:sz/@val";
-
-  /// <summary>
-  /// Font size
-  /// </summary>
-  public float Size {
-    get => Convert.ToSingle(GetXmlNodeDecimal(_sizePath));
-    set {
-      _collection.ConvertRichtext();
-      SetXmlNodeString(_sizePath, value.ToString(CultureInfo.InvariantCulture));
-      if (_callback != null) {
-        _callback();
-      }
-    }
-  }
-
-  private const string _fontPath = "d:rPr/d:rFont/@val";
-
-  /// <summary>
-  /// Name of the font
-  /// </summary>
-  public string FontName {
-    get => GetXmlNodeString(_fontPath);
-    set {
-      _collection.ConvertRichtext();
-      SetXmlNodeString(_fontPath, value);
-      if (_callback != null) {
-        _callback();
-      }
-    }
-  }
-
-  private const string _colorPath = "d:rPr/d:color/@rgb";
-
-  /// <summary>
-  /// Text color
-  /// </summary>
-  public string Color {
-    get => GetXmlNodeString(_colorPath);
-    set {
-      _collection.ConvertRichtext();
-      SetXmlNodeString(_colorPath, value);
-      if (_callback != null) {
-        _callback();
-      }
-    }
-  }
-
-  public ExcelRichTextCollection _collection { get; set; }
-}
diff --git a/EPPlus/Style/ExcelRichTextCollection.cs b/EPPlus/Style/ExcelRichTextCollection.cs
deleted file mode 100644
index 21f4803..0000000
--- a/EPPlus/Style/ExcelRichTextCollection.cs
+++ /dev/null
@@ -1,233 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		                Initial Release		        2009-10-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Xml;
-
-namespace OfficeOpenXml.Style;
-
-/// <summary>
-/// Collection of Richtext objects
-/// </summary>
-public class ExcelRichTextCollection : XmlHelper, IEnumerable<ExcelRichText> {
-  private readonly List<ExcelRichText> _list = new();
-  private readonly ExcelRangeBase _cells;
-
-  internal ExcelRichTextCollection(XmlNamespaceManager ns, XmlNode topNode)
-      : base(ns, topNode) {
-    var nl = topNode.SelectNodes("d:r|d:t", NameSpaceManager); // Bug 15151
-    if (nl != null) {
-      foreach (XmlNode n in nl) {
-        _list.Add(new(ns, n, this));
-      }
-    }
-  }
-
-  internal ExcelRichTextCollection(XmlNamespaceManager ns, XmlNode topNode, ExcelRangeBase cells)
-      : this(ns, topNode) {
-    _cells = cells;
-  }
-
-  /// <summary>
-  /// Collection containing the richtext objects
-  /// </summary>
-  /// <param name="index"></param>
-  /// <returns></returns>
-  public ExcelRichText this[int index] {
-    get {
-      var item = _list[index];
-      if (_cells != null) {
-        item.SetCallback(UpdateCells);
-      }
-      return item;
-    }
-  }
-
-  /// <summary>
-  /// Items in the list
-  /// </summary>
-  public int Count => _list.Count;
-
-  /// <summary>
-  /// Add a rich text string
-  /// </summary>
-  /// <param name="text">The text to add</param>
-  /// <returns></returns>
-  public ExcelRichText Add(string text) {
-    ConvertRichtext();
-    XmlDocument doc;
-    if (TopNode is XmlDocument document) {
-      doc = document;
-    } else {
-      doc = TopNode.OwnerDocument;
-    }
-    var node = doc.CreateElement("d", "r", ExcelPackage._schemaMain);
-    TopNode.AppendChild(node);
-    var rt = new ExcelRichText(NameSpaceManager, node, this);
-    if (_list.Count > 0) {
-      ExcelRichText prevItem = _list[_list.Count - 1];
-      rt.FontName = prevItem.FontName;
-      rt.Size = prevItem.Size;
-      rt.Color = prevItem.Color == "" ? "FF00000" : prevItem.Color;
-      rt.PreserveSpace = rt.PreserveSpace;
-      rt.Bold = prevItem.Bold;
-      rt.Italic = prevItem.Italic;
-      rt.UnderLine = prevItem.UnderLine;
-    } else if (_cells == null) {
-      rt.FontName = "Calibri";
-      rt.Size = 11;
-    } else {
-      var style = _cells.Offset(0, 0).Style;
-      rt.FontName = style.Font.Name;
-      rt.Size = style.Font.Size;
-      rt.Bold = style.Font.Bold;
-      rt.Italic = style.Font.Italic;
-      _cells.IsRichText = true;
-    }
-    rt.Text = text;
-    rt.PreserveSpace = true;
-    if (_cells != null) {
-      rt.SetCallback(UpdateCells);
-      UpdateCells();
-    }
-    _list.Add(rt);
-    return rt;
-  }
-
-  internal void ConvertRichtext() {
-    if (_cells == null) {
-      return;
-    }
-    var isRt = _cells.Worksheet._flags.GetFlagValue(
-        _cells._fromRow,
-        _cells._fromCol,
-        CellFlags.RichText);
-    if (Count == 1 && isRt == false) {
-      _cells.Worksheet._flags.SetFlagValue(
-          _cells._fromRow,
-          _cells._fromCol,
-          true,
-          CellFlags.RichText);
-      var s = _cells.Worksheet._styles.GetValue(_cells._fromRow, _cells._fromCol);
-      //var fnt = cell.Style.Font;
-      var fnt = _cells.Worksheet.Workbook.Styles
-          .GetStyleObject(
-              s,
-              _cells.Worksheet.PositionID,
-              ExcelCellBase.GetAddress(_cells._fromRow, _cells._fromCol))
-          .Font;
-      this[0].PreserveSpace = true;
-      this[0].Bold = fnt.Bold;
-      this[0].FontName = fnt.Name;
-      this[0].Italic = fnt.Italic;
-      this[0].Size = fnt.Size;
-      this[0].UnderLine = fnt.UnderLine;
-    }
-  }
-
-  internal void UpdateCells() {
-    _cells.SetValueRichText(TopNode.InnerXml);
-  }
-
-  /// <summary>
-  /// Removes an item at the specific index
-  /// </summary>
-  /// <param name="index"></param>
-  public void RemoveAt(int index) {
-    TopNode.RemoveChild(_list[index].TopNode);
-    _list.RemoveAt(index);
-    if (_cells != null && _list.Count == 0) {
-      _cells.IsRichText = false;
-    }
-  }
-
-  /// <summary>
-  /// Removes an item
-  /// </summary>
-  /// <param name="item"></param>
-  public void Remove(ExcelRichText item) {
-    TopNode.RemoveChild(item.TopNode);
-    _list.Remove(item);
-    if (_cells != null && _list.Count == 0) {
-      _cells.IsRichText = false;
-    }
-  }
-
-  //public void Insert(int index, string Text)
-  //{
-  //    _list.Insert(index, item);
-  //}
-
-  /// <summary>
-  /// The text
-  /// </summary>
-  public string Text {
-    get {
-      StringBuilder sb = new StringBuilder();
-      foreach (var item in _list) {
-        sb.Append(item.Text);
-      }
-      return sb.ToString();
-    }
-    set {
-      if (Count == 0) {
-        Add(value);
-      } else {
-        this[0].Text = value;
-        for (int ix = 1; ix < Count; ix++) {
-          RemoveAt(ix);
-        }
-      }
-    }
-  }
-
-  IEnumerator<ExcelRichText> IEnumerable<ExcelRichText>.GetEnumerator() {
-    return _list
-        .Select(x => {
-          x.SetCallback(UpdateCells);
-          return x;
-        })
-        .GetEnumerator();
-  }
-
-  IEnumerator IEnumerable.GetEnumerator() {
-    return _list
-        .Select(x => {
-          x.SetCallback(UpdateCells);
-          return x;
-        })
-        .GetEnumerator();
-  }
-}
diff --git a/EPPlus/Style/ExcelStyle.cs b/EPPlus/Style/ExcelStyle.cs
deleted file mode 100644
index 088b8c3..0000000
--- a/EPPlus/Style/ExcelStyle.cs
+++ /dev/null
@@ -1,163 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		                Initial Release		        2009-10-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using OfficeOpenXml.Style.XmlAccess;
-
-namespace OfficeOpenXml.Style;
-
-/// <summary>
-/// Toplevel class for cell styling
-/// </summary>
-public sealed class ExcelStyle : StyleBase {
-  internal ExcelStyle(
-      ExcelStyles styles,
-      XmlHelper.ChangedEventHandler changedEvent,
-      int positionId,
-      string address,
-      int xfsId)
-      : base(styles, changedEvent, positionId, address) {
-    Index = xfsId;
-    ExcelXfs xfs;
-    if (positionId > -1) {
-      xfs = _styles.CellXfs[xfsId];
-    } else {
-      xfs = _styles.CellStyleXfs[xfsId];
-    }
-    Styles = styles;
-    PositionID = positionId;
-    Numberformat = new(styles, changedEvent, PositionID, address, xfs.NumberFormatId);
-    Font = new(styles, changedEvent, PositionID, address, xfs.FontId);
-    Fill = new(styles, changedEvent, PositionID, address, xfs.FillId);
-    Border = new(styles, changedEvent, PositionID, address, xfs.BorderId);
-  }
-
-  /// <summary>
-  /// Numberformat
-  /// </summary>
-  public ExcelNumberFormat Numberformat { get; set; }
-
-  /// <summary>
-  /// Font styling
-  /// </summary>
-  public ExcelFont Font { get; set; }
-
-  /// <summary>
-  /// Fill Styling
-  /// </summary>
-  public ExcelFill Fill { get; set; }
-
-  /// <summary>
-  /// Border
-  /// </summary>
-  public Border Border { get; set; }
-
-  /// <summary>
-  /// The horizontal alignment in the cell
-  /// </summary>
-  public ExcelHorizontalAlignment HorizontalAlignment => _styles.CellXfs[Index].HorizontalAlignment;
-
-  /// <summary>
-  /// The vertical alignment in the cell
-  /// </summary>
-  public ExcelVerticalAlignment VerticalAlignment => _styles.CellXfs[Index].VerticalAlignment;
-
-  /// <summary>
-  /// Wrap the text
-  /// </summary>
-  public bool WrapText {
-    get => _styles.CellXfs[Index].WrapText;
-    set =>
-      _ChangedEvent(
-          this,
-          new(eStyleClass.Style, eStyleProperty.WrapText, value, _positionID, _address));
-  }
-
-  /// <summary>
-  /// Readingorder
-  /// </summary>
-  public ExcelReadingOrder ReadingOrder => _styles.CellXfs[Index].ReadingOrder;
-
-  /// <summary>
-  /// Shrink the text to fit
-  /// </summary>
-  public bool ShrinkToFit => _styles.CellXfs[Index].ShrinkToFit;
-
-  /// <summary>
-  /// The margin between the border and the text
-  /// </summary>
-  public int Indent => _styles.CellXfs[Index].Indent;
-
-  /// <summary>
-  /// Text orientation in degrees. Values range from 0 to 180.
-  /// </summary>
-  public int TextRotation => _styles.CellXfs[Index].TextRotation;
-
-  /// <summary>
-  /// If true the cell is locked for editing when the sheet is protected
-  /// <seealso cref="ExcelWorksheet.Protection"/>
-  /// </summary>
-  public bool Locked => _styles.CellXfs[Index].Locked;
-
-  /// <summary>
-  /// If true the formula is hidden when the sheet is protected.
-  /// <seealso cref="ExcelWorksheet.Protection"/>
-  /// </summary>
-  public bool Hidden => _styles.CellXfs[Index].Hidden;
-
-  /// <summary>
-  /// The index in the style collection
-  /// </summary>
-  public int XfId => _styles.CellXfs[Index].XfId;
-
-  internal int PositionID { get; set; }
-
-  internal ExcelStyles Styles { get; set; }
-
-  internal override string Id =>
-    Numberformat.Id
-        + "|"
-        + Font.Id
-        + "|"
-        + Fill.Id
-        + "|"
-        + Border.Id
-        + "|"
-        + VerticalAlignment
-        + "|"
-        + HorizontalAlignment
-        + "|"
-        + WrapText
-        + "|"
-        + ReadingOrder
-        + "|"
-        + XfId;
-}
diff --git a/EPPlus/Style/IStyle.cs b/EPPlus/Style/IStyle.cs
deleted file mode 100644
index f1f492e..0000000
--- a/EPPlus/Style/IStyle.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		                Initial Release		        2009-10-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-namespace OfficeOpenXml.Style;
-
-internal interface IStyle {
-  void SetNewStyleId(string value);
-
-  ulong Id { get; }
-
-  ExcelStyle ExcelStyle { get; }
-}
diff --git a/EPPlus/Style/StyleBase.cs b/EPPlus/Style/StyleBase.cs
deleted file mode 100644
index edc6650..0000000
--- a/EPPlus/Style/StyleBase.cs
+++ /dev/null
@@ -1,188 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		                Initial Release		        2009-10-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-namespace OfficeOpenXml.Style;
-
-/// <summary>
-/// Border line style
-/// </summary>
-public enum ExcelBorderStyle {
-  None,
-  Hair,
-  Dotted,
-  DashDot,
-  Thin,
-  DashDotDot,
-  Dashed,
-  MediumDashDotDot,
-  MediumDashed,
-  MediumDashDot,
-  Thick,
-  Medium,
-  Double,
-}
-
-/// <summary>
-/// Horizontal text alignment
-/// </summary>
-public enum ExcelHorizontalAlignment {
-  General,
-  Left,
-  Center,
-  CenterContinuous,
-  Right,
-  Fill,
-  Distributed,
-  Justify,
-}
-
-/// <summary>
-/// Vertical text alignment
-/// </summary>
-public enum ExcelVerticalAlignment {
-  Top,
-  Center,
-  Bottom,
-  Distributed,
-  Justify,
-}
-
-/// <summary>
-/// Font-Vertical Align
-/// </summary>
-public enum ExcelVerticalAlignmentFont {
-  None,
-  Subscript,
-  Superscript,
-}
-
-/// <summary>
-/// Font-Underlinestyle for
-/// </summary>
-public enum ExcelUnderLineType {
-  None,
-  Single,
-  Double,
-  SingleAccounting,
-  DoubleAccounting,
-}
-
-/// <summary>
-/// Fill pattern
-/// </summary>
-public enum ExcelFillStyle {
-  None,
-  Solid,
-  DarkGray,
-  MediumGray,
-  LightGray,
-  Gray125,
-  Gray0625,
-  DarkVertical,
-  DarkHorizontal,
-  DarkDown,
-  DarkUp,
-  DarkGrid,
-  DarkTrellis,
-  LightVertical,
-  LightHorizontal,
-  LightDown,
-  LightUp,
-  LightGrid,
-  LightTrellis,
-}
-
-/// <summary>
-/// Type of gradient fill
-/// </summary>
-public enum ExcelFillGradientType {
-  /// <summary>
-  /// No gradient fill.
-  /// </summary>
-  None,
-
-  /// <summary>
-  /// This gradient fill is of linear gradient type. Linear gradient type means that the transition from one color to the next is along a line (e.g., horizontal, vertical,diagonal, etc.)
-  /// </summary>
-  Linear,
-
-  /// <summary>
-  /// This gradient fill is of path gradient type. Path gradient type means the that the boundary of transition from one color to the next is a rectangle, defined by top,bottom, left, and right attributes on the gradientFill element.
-  /// </summary>
-  Path,
-}
-
-/// <summary>
-/// The reading order
-/// </summary>
-public enum ExcelReadingOrder {
-  /// <summary>
-  /// Reading order is determined by scanning the text for the first non-whitespace character: if it is a strong right-to-left character, the reading order is right-to-left; otherwise, the reading order left-to-right.
-  /// </summary>
-  ContextDependent = 0,
-
-  /// <summary>
-  /// Left to Right
-  /// </summary>
-  LeftToRight = 1,
-
-  /// <summary>
-  /// Right to Left
-  /// </summary>
-  RightToLeft = 2,
-}
-
-public abstract class StyleBase {
-  protected ExcelStyles _styles;
-  internal XmlHelper.ChangedEventHandler _ChangedEvent;
-  protected int _positionID;
-  protected string _address;
-
-  internal StyleBase(
-      ExcelStyles styles,
-      XmlHelper.ChangedEventHandler changedEvent,
-      int positionId,
-      string address) {
-    _styles = styles;
-    _ChangedEvent = changedEvent;
-    _address = address;
-    _positionID = positionId;
-  }
-
-  internal int Index { get; set; }
-
-  internal abstract string Id { get; }
-
-  internal virtual void SetIndex(int index) {
-    Index = index;
-  }
-}
diff --git a/EPPlus/Style/StyleChangeEventArgs.cs b/EPPlus/Style/StyleChangeEventArgs.cs
deleted file mode 100644
index 352dc51..0000000
--- a/EPPlus/Style/StyleChangeEventArgs.cs
+++ /dev/null
@@ -1,119 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		                Initial Release		        2009-10-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System;
-
-namespace OfficeOpenXml.Style;
-
-internal enum eStyleClass {
-  Numberformat,
-  Font,
-  Border,
-  BorderTop,
-  BorderLeft,
-  BorderBottom,
-  BorderRight,
-  BorderDiagonal,
-  Fill,
-  GradientFill,
-  FillBackgroundColor,
-  FillPatternColor,
-  FillGradientColor1,
-  FillGradientColor2,
-  NamedStyle,
-  Style,
-}
-
-internal enum eStyleProperty {
-  Format,
-  Name,
-  Size,
-  Bold,
-  Italic,
-  Strike,
-  Color,
-  Tint,
-  IndexedColor,
-  AutoColor,
-  GradientColor,
-  Family,
-  Scheme,
-  UnderlineType,
-  HorizontalAlign,
-  VerticalAlign,
-  Border,
-  NamedStyle,
-  Style,
-  PatternType,
-  ReadingOrder,
-  WrapText,
-  TextRotation,
-  Locked,
-  Hidden,
-  ShrinkToFit,
-  BorderDiagonalUp,
-  BorderDiagonalDown,
-  GradientDegree,
-  GradientType,
-  GradientTop,
-  GradientBottom,
-  GradientLeft,
-  GradientRight,
-  XfId,
-  Indent,
-}
-
-internal class StyleChangeEventArgs : EventArgs {
-  internal StyleChangeEventArgs(
-      eStyleClass styleclass,
-      eStyleProperty styleProperty,
-      object value,
-      int positionId,
-      string address) {
-    StyleClass = styleclass;
-    StyleProperty = styleProperty;
-    Value = value;
-    Address = address;
-    PositionID = positionId;
-  }
-
-  internal eStyleClass StyleClass;
-  internal eStyleProperty StyleProperty;
-
-  //internal string PropertyName;
-  internal object Value;
-
-  internal int PositionID { get; set; }
-
-  //internal string Address;
-  internal string Address;
-}
diff --git a/EPPlus/Style/XmlAccess/ExcelBorderItemXml.cs b/EPPlus/Style/XmlAccess/ExcelBorderItemXml.cs
deleted file mode 100644
index 9c0de5e..0000000
--- a/EPPlus/Style/XmlAccess/ExcelBorderItemXml.cs
+++ /dev/null
@@ -1,130 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		                Initial Release		        2009-10-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System;
-using System.Globalization;
-using System.Xml;
-
-namespace OfficeOpenXml.Style.XmlAccess;
-
-/// <summary>
-/// Xml access class for border items
-/// </summary>
-public sealed class ExcelBorderItemXml : StyleXmlHelper {
-  internal ExcelBorderItemXml(XmlNamespaceManager nameSpaceManager)
-      : base(nameSpaceManager) {
-    _borderStyle = ExcelBorderStyle.None;
-    _color = new(NameSpaceManager);
-  }
-
-  internal ExcelBorderItemXml(XmlNamespaceManager nsm, XmlNode topNode)
-      : base(nsm, topNode) {
-    if (topNode != null) {
-      _borderStyle = GetBorderStyle(GetXmlNodeString("@style"));
-      _color = new(nsm, topNode.SelectSingleNode(_colorPath, nsm));
-      Exists = true;
-    } else {
-      Exists = false;
-    }
-  }
-
-  private ExcelBorderStyle GetBorderStyle(string style) {
-    if (style == "") {
-      return ExcelBorderStyle.None;
-    }
-    return Enum.TryParse<ExcelBorderStyle>(style, true, out var result)
-        ? result
-        : ExcelBorderStyle.None;
-  }
-
-  private ExcelBorderStyle _borderStyle = ExcelBorderStyle.None;
-
-  /// <summary>
-  /// Cell Border style
-  /// </summary>
-  public ExcelBorderStyle Style {
-    get => _borderStyle;
-    set {
-      _borderStyle = value;
-      Exists = true;
-    }
-  }
-
-  private ExcelColorXml _color;
-  private const string _colorPath = "d:color";
-
-  /// <summary>
-  /// Border style
-  /// </summary>
-  public ExcelColorXml Color {
-    get => _color;
-    internal set => _color = value;
-  }
-
-  internal override string Id {
-    get {
-      if (Exists) {
-        return Style + Color.Id;
-      }
-      return "None";
-    }
-  }
-
-  internal ExcelBorderItemXml Copy() {
-    ExcelBorderItemXml borderItem = new ExcelBorderItemXml(NameSpaceManager);
-    borderItem.Style = _borderStyle;
-    borderItem.Color = _color.Copy();
-    return borderItem;
-  }
-
-  internal override XmlNode CreateXmlNode(XmlNode topNode) {
-    TopNode = topNode;
-
-    if (Style != ExcelBorderStyle.None) {
-      SetXmlNodeString("@style", SetBorderString(Style));
-      if (Color.Exists) {
-        CreateNode(_colorPath);
-        topNode.AppendChild(
-            Color.CreateXmlNode(TopNode.SelectSingleNode(_colorPath, NameSpaceManager)));
-      }
-    }
-    return TopNode;
-  }
-
-  private string SetBorderString(ExcelBorderStyle style) {
-    string newName = Enum.GetName(typeof(ExcelBorderStyle), style);
-    return newName.Substring(0, 1).ToLower(CultureInfo.InvariantCulture)
-        + newName.Substring(1, newName.Length - 1);
-  }
-
-  public bool Exists { get; private set; }
-}
diff --git a/EPPlus/Style/XmlAccess/ExcelBorderXml.cs b/EPPlus/Style/XmlAccess/ExcelBorderXml.cs
deleted file mode 100644
index 9d19974..0000000
--- a/EPPlus/Style/XmlAccess/ExcelBorderXml.cs
+++ /dev/null
@@ -1,171 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		                Initial Release		        2009-10-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System.Xml;
-
-namespace OfficeOpenXml.Style.XmlAccess;
-
-/// <summary>
-/// Xml access class for border top level
-/// </summary>
-public sealed class ExcelBorderXml : StyleXmlHelper {
-  internal ExcelBorderXml(XmlNamespaceManager nameSpaceManager)
-      : base(nameSpaceManager) {}
-
-  internal ExcelBorderXml(XmlNamespaceManager nsm, XmlNode topNode)
-      : base(nsm, topNode) {
-    _left = new(nsm, topNode.SelectSingleNode(_leftPath, nsm));
-    _right = new(nsm, topNode.SelectSingleNode(_rightPath, nsm));
-    _top = new(nsm, topNode.SelectSingleNode(_topPath, nsm));
-    _bottom = new(nsm, topNode.SelectSingleNode(_bottomPath, nsm));
-    _diagonal = new(nsm, topNode.SelectSingleNode(_diagonalPath, nsm));
-    _diagonalUp = GetBoolValue(topNode, _diagonalUpPath);
-    _diagonalDown = GetBoolValue(topNode, _diagonalDownPath);
-  }
-
-  internal override string Id =>
-    Left.Id + Right.Id + Top.Id + Bottom.Id + Diagonal.Id + DiagonalUp + DiagonalDown;
-
-  private const string _leftPath = "d:left";
-  private ExcelBorderItemXml _left;
-
-  /// <summary>
-  /// Left border style properties
-  /// </summary>
-  public ExcelBorderItemXml Left {
-    get => _left;
-    internal set => _left = value;
-  }
-
-  private const string _rightPath = "d:right";
-  private ExcelBorderItemXml _right;
-
-  /// <summary>
-  /// Right border style properties
-  /// </summary>
-  public ExcelBorderItemXml Right {
-    get => _right;
-    internal set => _right = value;
-  }
-
-  private const string _topPath = "d:top";
-  private ExcelBorderItemXml _top;
-
-  /// <summary>
-  /// Top border style properties
-  /// </summary>
-  public ExcelBorderItemXml Top {
-    get => _top;
-    internal set => _top = value;
-  }
-
-  private const string _bottomPath = "d:bottom";
-  private ExcelBorderItemXml _bottom;
-
-  /// <summary>
-  /// Bottom border style properties
-  /// </summary>
-  public ExcelBorderItemXml Bottom {
-    get => _bottom;
-    internal set => _bottom = value;
-  }
-
-  private const string _diagonalPath = "d:diagonal";
-  private ExcelBorderItemXml _diagonal;
-
-  /// <summary>
-  /// Diagonal border style properties
-  /// </summary>
-  public ExcelBorderItemXml Diagonal {
-    get => _diagonal;
-    internal set => _diagonal = value;
-  }
-
-  private const string _diagonalUpPath = "@diagonalUp";
-  private bool _diagonalUp;
-
-  /// <summary>
-  /// Diagonal up border
-  /// </summary>
-  public bool DiagonalUp {
-    get => _diagonalUp;
-    internal set => _diagonalUp = value;
-  }
-
-  private const string _diagonalDownPath = "@diagonalDown";
-  private bool _diagonalDown;
-
-  /// <summary>
-  /// Diagonal down border
-  /// </summary>
-  public bool DiagonalDown {
-    get => _diagonalDown;
-    internal set => _diagonalDown = value;
-  }
-
-  internal ExcelBorderXml Copy() {
-    ExcelBorderXml newBorder = new ExcelBorderXml(NameSpaceManager);
-    newBorder.Bottom = _bottom.Copy();
-    newBorder.Diagonal = _diagonal.Copy();
-    newBorder.Left = _left.Copy();
-    newBorder.Right = _right.Copy();
-    newBorder.Top = _top.Copy();
-    newBorder.DiagonalUp = _diagonalUp;
-    newBorder.DiagonalDown = _diagonalDown;
-
-    return newBorder;
-  }
-
-  internal override XmlNode CreateXmlNode(XmlNode topNode) {
-    TopNode = topNode;
-    CreateNode(_leftPath);
-    topNode.AppendChild(_left.CreateXmlNode(TopNode.SelectSingleNode(_leftPath, NameSpaceManager)));
-    CreateNode(_rightPath);
-    topNode.AppendChild(
-        _right.CreateXmlNode(TopNode.SelectSingleNode(_rightPath, NameSpaceManager)));
-    CreateNode(_topPath);
-    topNode.AppendChild(_top.CreateXmlNode(TopNode.SelectSingleNode(_topPath, NameSpaceManager)));
-    CreateNode(_bottomPath);
-    topNode.AppendChild(
-        _bottom.CreateXmlNode(TopNode.SelectSingleNode(_bottomPath, NameSpaceManager)));
-    CreateNode(_diagonalPath);
-    topNode.AppendChild(
-        _diagonal.CreateXmlNode(TopNode.SelectSingleNode(_diagonalPath, NameSpaceManager)));
-    if (_diagonalUp) {
-      SetXmlNodeString(_diagonalUpPath, "1");
-    }
-    if (_diagonalDown) {
-      SetXmlNodeString(_diagonalDownPath, "1");
-    }
-    return topNode;
-  }
-}
diff --git a/EPPlus/Style/XmlAccess/ExcelColorXml.cs b/EPPlus/Style/XmlAccess/ExcelColorXml.cs
deleted file mode 100644
index 7a6d024..0000000
--- a/EPPlus/Style/XmlAccess/ExcelColorXml.cs
+++ /dev/null
@@ -1,175 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		                Initial Release		        2009-10-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System;
-using System.Globalization;
-using System.Xml;
-
-namespace OfficeOpenXml.Style.XmlAccess;
-
-/// <summary>
-/// Xml access class for color
-/// </summary>
-public sealed class ExcelColorXml : StyleXmlHelper {
-  internal ExcelColorXml(XmlNamespaceManager nameSpaceManager)
-      : base(nameSpaceManager) {
-    _auto = false;
-    _theme = "";
-    _tint = 0;
-    _rgb = "";
-    _indexed = int.MinValue;
-  }
-
-  internal ExcelColorXml(XmlNamespaceManager nsm, XmlNode topNode)
-      : base(nsm, topNode) {
-    if (topNode == null) {
-      _exists = false;
-    } else {
-      _exists = true;
-      _auto = GetXmlNodeBool("@auto");
-      _theme = GetXmlNodeString("@theme");
-      _tint = GetXmlNodeDecimalNull("@tint") ?? decimal.MinValue;
-      _rgb = GetXmlNodeString("@rgb");
-      _indexed = GetXmlNodeIntNull("@indexed") ?? int.MinValue;
-    }
-  }
-
-  internal override string Id => _auto + "|" + _theme + "|" + _tint + "|" + _rgb + "|" + _indexed;
-
-  private bool _auto;
-
-  public bool Auto {
-    get => _auto;
-    set {
-      _auto = value;
-      _exists = true;
-      Clear();
-    }
-  }
-
-  private string _theme;
-
-  /// <summary>
-  /// Theme color value
-  /// </summary>
-  public string Theme => _theme;
-
-  private decimal _tint;
-
-  /// <summary>
-  /// Tint
-  /// </summary>
-  public decimal Tint {
-    get {
-      if (_tint == decimal.MinValue) {
-        return 0;
-      }
-      return _tint;
-    }
-    set {
-      _tint = value;
-      _exists = true;
-    }
-  }
-
-  private string _rgb;
-
-  /// <summary>
-  /// RGB value
-  /// </summary>
-  public string Rgb {
-    get => _rgb;
-    set {
-      _rgb = value;
-      _exists = true;
-      _indexed = int.MinValue;
-      _auto = false;
-    }
-  }
-
-  private int _indexed;
-
-  /// <summary>
-  /// Indexed color value
-  /// </summary>
-  public int Indexed {
-    get => (_indexed == int.MinValue ? 0 : _indexed);
-    set {
-      if (value < 0 || value > 65) {
-        throw (new ArgumentOutOfRangeException("Index out of range"));
-      }
-      Clear();
-      _indexed = value;
-      _exists = true;
-    }
-  }
-
-  internal void Clear() {
-    _theme = "";
-    _tint = decimal.MinValue;
-    _indexed = int.MinValue;
-    _rgb = "";
-    _auto = false;
-  }
-
-  internal ExcelColorXml Copy() {
-    return new(NameSpaceManager) {
-      _indexed = _indexed,
-      _tint = _tint,
-      _rgb = _rgb,
-      _theme = _theme,
-      _auto = _auto,
-      _exists = _exists,
-    };
-  }
-
-  internal override XmlNode CreateXmlNode(XmlNode topNode) {
-    TopNode = topNode;
-    if (_rgb != "") {
-      SetXmlNodeString("@rgb", _rgb);
-    } else if (_indexed >= 0) {
-      SetXmlNodeString("@indexed", _indexed.ToString());
-    } else if (_auto) {
-      SetXmlNodeBool("@auto", _auto);
-    } else {
-      SetXmlNodeString("@theme", _theme);
-    }
-    if (_tint != decimal.MinValue) {
-      SetXmlNodeString("@tint", _tint.ToString(CultureInfo.InvariantCulture));
-    }
-    return TopNode;
-  }
-
-  private bool _exists;
-
-  internal bool Exists => _exists;
-}
diff --git a/EPPlus/Style/XmlAccess/ExcelFillXml.cs b/EPPlus/Style/XmlAccess/ExcelFillXml.cs
deleted file mode 100644
index cf43d0e..0000000
--- a/EPPlus/Style/XmlAccess/ExcelFillXml.cs
+++ /dev/null
@@ -1,130 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		                Initial Release		        2009-10-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System;
-using System.Globalization;
-using System.Xml;
-
-namespace OfficeOpenXml.Style.XmlAccess;
-
-/// <summary>
-/// Xml access class for fills
-/// </summary>
-public class ExcelFillXml : StyleXmlHelper {
-  internal ExcelFillXml(XmlNamespaceManager nameSpaceManager)
-      : base(nameSpaceManager) {
-    _fillPatternType = ExcelFillStyle.None;
-    _backgroundColor = new(NameSpaceManager);
-    _patternColor = new(NameSpaceManager);
-  }
-
-  internal ExcelFillXml(XmlNamespaceManager nsm, XmlNode topNode)
-      : base(nsm, topNode) {
-    PatternType = GetPatternType(GetXmlNodeString(_fillPatternTypePath));
-    _backgroundColor = new(nsm, topNode.SelectSingleNode(_backgroundColorPath, nsm));
-    _patternColor = new(nsm, topNode.SelectSingleNode(_patternColorPath, nsm));
-  }
-
-  private ExcelFillStyle GetPatternType(string patternType) {
-    return Enum.TryParse<ExcelFillStyle>(patternType, true, out var result)
-        ? result
-        : ExcelFillStyle.None;
-  }
-
-  internal override string Id => PatternType + PatternColor.Id + BackgroundColor.Id;
-
-  private const string _fillPatternTypePath = "d:patternFill/@patternType";
-  protected ExcelFillStyle _fillPatternType;
-
-  /// <summary>
-  /// Cell fill pattern style
-  /// </summary>
-  public ExcelFillStyle PatternType {
-    get => _fillPatternType;
-    set => _fillPatternType = value;
-  }
-
-  protected ExcelColorXml _patternColor;
-  private const string _patternColorPath = "d:patternFill/d:bgColor";
-
-  /// <summary>
-  /// Pattern color
-  /// </summary>
-  public ExcelColorXml PatternColor {
-    get => _patternColor;
-    internal set => _patternColor = value;
-  }
-
-  protected ExcelColorXml _backgroundColor;
-  private const string _backgroundColorPath = "d:patternFill/d:fgColor";
-
-  /// <summary>
-  /// Cell background color
-  /// </summary>
-  public ExcelColorXml BackgroundColor {
-    get => _backgroundColor;
-    internal set => _backgroundColor = value;
-  }
-
-  internal virtual ExcelFillXml Copy() {
-    ExcelFillXml newFill = new ExcelFillXml(NameSpaceManager);
-    newFill.PatternType = _fillPatternType;
-    newFill.BackgroundColor = _backgroundColor.Copy();
-    newFill.PatternColor = _patternColor.Copy();
-    return newFill;
-  }
-
-  internal override XmlNode CreateXmlNode(XmlNode topNode) {
-    TopNode = topNode;
-    SetXmlNodeString(_fillPatternTypePath, SetPatternString(_fillPatternType));
-    if (PatternType != ExcelFillStyle.None) {
-      XmlNode pattern = topNode.SelectSingleNode(_fillPatternTypePath, NameSpaceManager);
-      if (BackgroundColor.Exists) {
-        CreateNode(_backgroundColorPath);
-        BackgroundColor.CreateXmlNode(
-            topNode.SelectSingleNode(_backgroundColorPath, NameSpaceManager));
-        if (PatternColor.Exists) {
-          CreateNode(_patternColorPath);
-          //topNode.AppendChild(PatternColor.CreateXmlNode(topNode.SelectSingleNode(_patternColorPath, NameSpaceManager)));
-          PatternColor.CreateXmlNode(topNode.SelectSingleNode(_patternColorPath, NameSpaceManager));
-        }
-      }
-    }
-    return topNode;
-  }
-
-  private string SetPatternString(ExcelFillStyle pattern) {
-    string newName = Enum.GetName(typeof(ExcelFillStyle), pattern);
-    return newName.Substring(0, 1).ToLower(CultureInfo.InvariantCulture)
-        + newName.Substring(1, newName.Length - 1);
-  }
-}
diff --git a/EPPlus/Style/XmlAccess/ExcelFontXml.cs b/EPPlus/Style/XmlAccess/ExcelFontXml.cs
deleted file mode 100644
index 2d90c95..0000000
--- a/EPPlus/Style/XmlAccess/ExcelFontXml.cs
+++ /dev/null
@@ -1,294 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		                Initial Release		        2009-10-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System;
-using System.Globalization;
-using System.Xml;
-
-namespace OfficeOpenXml.Style.XmlAccess;
-
-/// <summary>
-/// Xml access class for fonts
-/// </summary>
-public sealed class ExcelFontXml : StyleXmlHelper {
-  internal ExcelFontXml(XmlNamespaceManager nameSpaceManager)
-      : base(nameSpaceManager) {
-    _name = "";
-    _size = 0;
-    _family = int.MinValue;
-    _scheme = "";
-    _color = _color = new(NameSpaceManager);
-    _bold = false;
-    _italic = false;
-    _strike = false;
-    _underlineType = ExcelUnderLineType.None;
-    _verticalAlign = "";
-  }
-
-  internal ExcelFontXml(XmlNamespaceManager nsm, XmlNode topNode)
-      : base(nsm, topNode) {
-    _name = GetXmlNodeString(_namePath);
-    _size = (float)GetXmlNodeDecimal(_sizePath);
-    _family = GetXmlNodeIntNull(_familyPath) ?? int.MinValue;
-    _scheme = GetXmlNodeString(_schemePath);
-    _color = new(nsm, topNode.SelectSingleNode(_colorPath, nsm));
-    _bold = GetBoolValue(topNode, _boldPath);
-    _italic = GetBoolValue(topNode, _italicPath);
-    _strike = GetBoolValue(topNode, _strikePath);
-    _verticalAlign = GetXmlNodeString(_verticalAlignPath);
-    if (topNode.SelectSingleNode(_underLinedPath, NameSpaceManager) != null) {
-      string ut = GetXmlNodeString(_underLinedPath + "/@val");
-      if (ut == "") {
-        _underlineType = ExcelUnderLineType.Single;
-      } else {
-        if (!Enum.TryParse(ut, true, out _underlineType)) {
-          _underlineType = ExcelUnderLineType.Single;
-        }
-      }
-    } else {
-      _underlineType = ExcelUnderLineType.None;
-    }
-  }
-
-  internal override string Id =>
-    Name
-        + "|"
-        + Size
-        + "|"
-        + Family
-        + "|"
-        + Color.Id
-        + "|"
-        + Scheme
-        + "|"
-        + Bold
-        + "|"
-        + Italic
-        + "|"
-        + Strike
-        + "|"
-        + VerticalAlign
-        + "|"
-        + UnderLineType;
-
-  private const string _namePath = "d:name/@val";
-  private string _name;
-
-  /// <summary>
-  /// The name of the font
-  /// </summary>
-  public string Name {
-    get => _name;
-    set {
-      Scheme = ""; //Reset schema to avoid corrupt file if unsupported font is selected.
-      _name = value;
-    }
-  }
-
-  private const string _sizePath = "d:sz/@val";
-  private float _size;
-
-  /// <summary>
-  /// Font size
-  /// </summary>
-  public float Size {
-    get => _size;
-    set => _size = value;
-  }
-
-  private const string _familyPath = "d:family/@val";
-  private int _family;
-
-  /// <summary>
-  /// Font family
-  /// </summary>
-  public int Family {
-    get => (_family == int.MinValue ? 0 : _family);
-    set => _family = value;
-  }
-
-  private ExcelColorXml _color;
-  private const string _colorPath = "d:color";
-
-  /// <summary>
-  /// Text color
-  /// </summary>
-  public ExcelColorXml Color {
-    get => _color;
-    internal set => _color = value;
-  }
-
-  private const string _schemePath = "d:scheme/@val";
-  private string _scheme = "";
-
-  /// <summary>
-  /// Font Scheme
-  /// </summary>
-  public string Scheme {
-    get => _scheme;
-    private set => _scheme = value;
-  }
-
-  private const string _boldPath = "d:b";
-  private bool _bold;
-
-  /// <summary>
-  /// If the font is bold
-  /// </summary>
-  public bool Bold {
-    get => _bold;
-    set => _bold = value;
-  }
-
-  private const string _italicPath = "d:i";
-  private bool _italic;
-
-  /// <summary>
-  /// If the font is italic
-  /// </summary>
-  public bool Italic {
-    get => _italic;
-    set => _italic = value;
-  }
-
-  private const string _strikePath = "d:strike";
-  private bool _strike;
-
-  /// <summary>
-  /// If the font is striked out
-  /// </summary>
-  public bool Strike {
-    get => _strike;
-    set => _strike = value;
-  }
-
-  private const string _underLinedPath = "d:u";
-
-  /// <summary>
-  /// If the font is underlined.
-  /// When set to true a the text is underlined with a single line
-  /// </summary>
-  public bool UnderLine {
-    get => UnderLineType != ExcelUnderLineType.None;
-    set => _underlineType = value ? ExcelUnderLineType.Single : ExcelUnderLineType.None;
-  }
-
-  private ExcelUnderLineType _underlineType;
-
-  /// <summary>
-  /// If the font is underlined
-  /// </summary>
-  public ExcelUnderLineType UnderLineType {
-    get => _underlineType;
-    set => _underlineType = value;
-  }
-
-  private const string _verticalAlignPath = "d:vertAlign/@val";
-  private string _verticalAlign;
-
-  /// <summary>
-  /// Vertical aligned
-  /// </summary>
-  public string VerticalAlign {
-    get => _verticalAlign;
-    set => _verticalAlign = value;
-  }
-
-  internal ExcelFontXml Copy() {
-    ExcelFontXml newFont = new ExcelFontXml(NameSpaceManager);
-    newFont.Name = _name;
-    newFont.Size = _size;
-    newFont.Family = _family;
-    newFont.Scheme = _scheme;
-    newFont.Bold = _bold;
-    newFont.Italic = _italic;
-    newFont.UnderLineType = _underlineType;
-    newFont.Strike = _strike;
-    newFont.VerticalAlign = _verticalAlign;
-    newFont.Color = Color.Copy();
-    return newFont;
-  }
-
-  internal override XmlNode CreateXmlNode(XmlNode topElement) {
-    TopNode = topElement;
-
-    if (_bold) {
-      CreateNode(_boldPath);
-    } else {
-      DeleteAllNode(_boldPath);
-    }
-    if (_italic) {
-      CreateNode(_italicPath);
-    } else {
-      DeleteAllNode(_italicPath);
-    }
-    if (_strike) {
-      CreateNode(_strikePath);
-    } else {
-      DeleteAllNode(_strikePath);
-    }
-
-    if (_underlineType == ExcelUnderLineType.None) {
-      DeleteAllNode(_underLinedPath);
-    } else if (_underlineType == ExcelUnderLineType.Single) {
-      CreateNode(_underLinedPath);
-    } else {
-      var v = _underlineType.ToString();
-      SetXmlNodeString(
-          _underLinedPath + "/@val",
-          v.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + v.Substring(1));
-    }
-
-    if (_verticalAlign != "") {
-      SetXmlNodeString(_verticalAlignPath, _verticalAlign);
-    }
-    if (_size > 0) {
-      SetXmlNodeString(_sizePath, _size.ToString(CultureInfo.InvariantCulture));
-    }
-    if (_color.Exists) {
-      CreateNode(_colorPath);
-      TopNode.AppendChild(
-          _color.CreateXmlNode(TopNode.SelectSingleNode(_colorPath, NameSpaceManager)));
-    }
-    if (!string.IsNullOrEmpty(_name)) {
-      SetXmlNodeString(_namePath, _name);
-    }
-    if (_family > int.MinValue) {
-      SetXmlNodeString(_familyPath, _family.ToString());
-    }
-    if (_scheme != "") {
-      SetXmlNodeString(_schemePath, _scheme);
-    }
-
-    return TopNode;
-  }
-}
diff --git a/EPPlus/Style/XmlAccess/ExcelGradientFillXml.cs b/EPPlus/Style/XmlAccess/ExcelGradientFillXml.cs
deleted file mode 100644
index 00adf5e..0000000
--- a/EPPlus/Style/XmlAccess/ExcelGradientFillXml.cs
+++ /dev/null
@@ -1,184 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		                Initial Release		        2009-10-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System.Globalization;
-using System.Xml;
-
-namespace OfficeOpenXml.Style.XmlAccess;
-
-/// <summary>
-/// Xml access class for gradient fillsde
-/// </summary>
-public sealed class ExcelGradientFillXml : ExcelFillXml {
-  internal ExcelGradientFillXml(XmlNamespaceManager nameSpaceManager)
-      : base(nameSpaceManager) {
-    GradientColor1 = new(nameSpaceManager);
-    GradientColor2 = new(nameSpaceManager);
-  }
-
-  internal ExcelGradientFillXml(XmlNamespaceManager nsm, XmlNode topNode)
-      : base(nsm, topNode) {
-    Degree = GetXmlNodeDouble(_degreePath);
-    Type =
-        GetXmlNodeString(_typePath) == "path"
-            ? ExcelFillGradientType.Path
-            : ExcelFillGradientType.Linear;
-    GradientColor1 = new(nsm, topNode.SelectSingleNode(_gradientColor1Path, nsm));
-    GradientColor2 = new(nsm, topNode.SelectSingleNode(_gradientColor2Path, nsm));
-
-    Top = GetXmlNodeDouble(_topPath);
-    Bottom = GetXmlNodeDouble(_bottomPath);
-    Left = GetXmlNodeDouble(_leftPath);
-    Right = GetXmlNodeDouble(_rightPath);
-  }
-
-  private const string _typePath = "d:gradientFill/@type";
-
-  /// <summary>
-  /// Type of gradient fill.
-  /// </summary>
-  public ExcelFillGradientType Type { get; internal set; }
-
-  private const string _degreePath = "d:gradientFill/@degree";
-
-  /// <summary>
-  /// Angle of the linear gradient
-  /// </summary>
-  public double Degree { get; internal set; }
-
-  private const string _gradientColor1Path = "d:gradientFill/d:stop[@position=\"0\"]/d:color";
-
-  /// <summary>
-  /// Gradient color 1
-  /// </summary>
-  public ExcelColorXml GradientColor1 { get; private set; }
-
-  private const string _gradientColor2Path = "d:gradientFill/d:stop[@position=\"1\"]/d:color";
-
-  /// <summary>
-  /// Gradient color 2
-  /// </summary>
-  public ExcelColorXml GradientColor2 { get; private set; }
-
-  private const string _bottomPath = "d:gradientFill/@bottom";
-
-  /// <summary>
-  /// Percentage format bottom
-  /// </summary>
-  public double Bottom { get; internal set; }
-
-  private const string _topPath = "d:gradientFill/@top";
-
-  /// <summary>
-  /// Percentage format top
-  /// </summary>
-  public double Top { get; internal set; }
-
-  private const string _leftPath = "d:gradientFill/@left";
-
-  /// <summary>
-  /// Percentage format left
-  /// </summary>
-  public double Left { get; internal set; }
-
-  private const string _rightPath = "d:gradientFill/@right";
-
-  /// <summary>
-  /// Percentage format right
-  /// </summary>
-  public double Right { get; internal set; }
-
-  internal override string Id =>
-    base.Id + Degree + GradientColor1.Id + GradientColor2.Id + Type + Left + Right + Bottom + Top;
-
-  internal override ExcelFillXml Copy() {
-    ExcelGradientFillXml newFill = new ExcelGradientFillXml(NameSpaceManager);
-    newFill.PatternType = _fillPatternType;
-    newFill.BackgroundColor = _backgroundColor.Copy();
-    newFill.PatternColor = _patternColor.Copy();
-
-    newFill.GradientColor1 = GradientColor1.Copy();
-    newFill.GradientColor2 = GradientColor2.Copy();
-    newFill.Type = Type;
-    newFill.Degree = Degree;
-    newFill.Top = Top;
-    newFill.Bottom = Bottom;
-    newFill.Left = Left;
-    newFill.Right = Right;
-
-    return newFill;
-  }
-
-  internal override XmlNode CreateXmlNode(XmlNode topNode) {
-    TopNode = topNode;
-    CreateNode("d:gradientFill");
-    if (Type == ExcelFillGradientType.Path) {
-      SetXmlNodeString(_typePath, "path");
-    }
-    if (!double.IsNaN(Degree)) {
-      SetXmlNodeString(_degreePath, Degree.ToString(CultureInfo.InvariantCulture));
-    }
-    if (GradientColor1 != null) {
-      /*** Gradient color node 1***/
-      var node = TopNode.SelectSingleNode("d:gradientFill", NameSpaceManager);
-      var stopNode = node.OwnerDocument.CreateElement("stop", ExcelPackage._schemaMain);
-      stopNode.SetAttribute("position", "0");
-      node.AppendChild(stopNode);
-      var colorNode = node.OwnerDocument.CreateElement("color", ExcelPackage._schemaMain);
-      stopNode.AppendChild(colorNode);
-      GradientColor1.CreateXmlNode(colorNode);
-
-      /*** Gradient color node 2***/
-      stopNode = node.OwnerDocument.CreateElement("stop", ExcelPackage._schemaMain);
-      stopNode.SetAttribute("position", "1");
-      node.AppendChild(stopNode);
-      colorNode = node.OwnerDocument.CreateElement("color", ExcelPackage._schemaMain);
-      stopNode.AppendChild(colorNode);
-
-      GradientColor2.CreateXmlNode(colorNode);
-    }
-    if (!double.IsNaN(Top)) {
-      SetXmlNodeString(_topPath, Top.ToString("F5", CultureInfo.InvariantCulture));
-    }
-    if (!double.IsNaN(Bottom)) {
-      SetXmlNodeString(_bottomPath, Bottom.ToString("F5", CultureInfo.InvariantCulture));
-    }
-    if (!double.IsNaN(Left)) {
-      SetXmlNodeString(_leftPath, Left.ToString("F5", CultureInfo.InvariantCulture));
-    }
-    if (!double.IsNaN(Right)) {
-      SetXmlNodeString(_rightPath, Right.ToString("F5", CultureInfo.InvariantCulture));
-    }
-
-    return topNode;
-  }
-}
diff --git a/EPPlus/Style/XmlAccess/ExcelNamedStyleXml.cs b/EPPlus/Style/XmlAccess/ExcelNamedStyleXml.cs
deleted file mode 100644
index 8004056..0000000
--- a/EPPlus/Style/XmlAccess/ExcelNamedStyleXml.cs
+++ /dev/null
@@ -1,127 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		                Initial Release		        2009-10-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System.Xml;
-
-namespace OfficeOpenXml.Style.XmlAccess;
-
-/// <summary>
-/// Xml access class for named styles
-/// </summary>
-public sealed class ExcelNamedStyleXml : StyleXmlHelper {
-  private readonly ExcelStyles _styles;
-
-  internal ExcelNamedStyleXml(XmlNamespaceManager nameSpaceManager, ExcelStyles styles)
-      : base(nameSpaceManager) {
-    _styles = styles;
-    BuildInId = int.MinValue;
-  }
-
-  internal ExcelNamedStyleXml(
-      XmlNamespaceManager nameSpaceManager,
-      XmlNode topNode,
-      ExcelStyles styles)
-      : base(nameSpaceManager, topNode) {
-    StyleXfId = GetXmlNodeInt(_idPath);
-    Name = GetXmlNodeString(_namePath);
-    BuildInId = GetXmlNodeInt(_buildInIdPath);
-    CustomBuildin = GetXmlNodeBool(_customBuiltinPath);
-
-    _styles = styles;
-    _style = new(styles, styles.NamedStylePropertyChange, -1, Name, _styleXfId);
-  }
-
-  internal override string Id => Name;
-
-  private int _styleXfId;
-  private const string _idPath = "@xfId";
-
-  /// <summary>
-  /// Named style index
-  /// </summary>
-  public int StyleXfId {
-    get => _styleXfId;
-    set => _styleXfId = value;
-  }
-
-  private int _xfId = int.MinValue;
-
-  /// <summary>
-  /// Style index
-  /// </summary>
-  internal int XfId {
-    get => _xfId;
-    set => _xfId = value;
-  }
-
-  private const string _buildInIdPath = "@builtinId";
-
-  public int BuildInId { get; set; }
-
-  private const string _customBuiltinPath = "@customBuiltin";
-
-  public bool CustomBuildin { get; set; }
-
-  private const string _namePath = "@name";
-  private string _name;
-
-  /// <summary>
-  /// Name of the style
-  /// </summary>
-  public string Name {
-    get => _name;
-    internal set => _name = value;
-  }
-
-  private ExcelStyle _style;
-
-  /// <summary>
-  /// The style object
-  /// </summary>
-  public ExcelStyle Style {
-    get => _style;
-    internal set => _style = value;
-  }
-
-  internal override XmlNode CreateXmlNode(XmlNode topNode) {
-    TopNode = topNode;
-    SetXmlNodeString(_namePath, _name);
-    SetXmlNodeString("@xfId", _styles.CellStyleXfs[StyleXfId].newID.ToString());
-    if (BuildInId >= 0) {
-      SetXmlNodeString("@builtinId", BuildInId.ToString());
-    }
-    if (CustomBuildin) {
-      SetXmlNodeBool(_customBuiltinPath, true);
-    }
-    return TopNode;
-  }
-}
diff --git a/EPPlus/Style/XmlAccess/ExcelNumberFormatXml.cs b/EPPlus/Style/XmlAccess/ExcelNumberFormatXml.cs
deleted file mode 100644
index c67aed9..0000000
--- a/EPPlus/Style/XmlAccess/ExcelNumberFormatXml.cs
+++ /dev/null
@@ -1,696 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		                Initial Release		        2009-10-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Xml;
-
-namespace OfficeOpenXml.Style.XmlAccess;
-
-/// <summary>
-/// Xml access class for number formats
-/// </summary>
-public sealed class ExcelNumberFormatXml : StyleXmlHelper {
-  internal ExcelNumberFormatXml(XmlNamespaceManager nameSpaceManager)
-      : base(nameSpaceManager) {}
-
-  internal ExcelNumberFormatXml(XmlNamespaceManager nameSpaceManager, bool buildIn)
-      : base(nameSpaceManager) {
-    BuildIn = buildIn;
-  }
-
-  internal ExcelNumberFormatXml(XmlNamespaceManager nsm, XmlNode topNode)
-      : base(nsm, topNode) {
-    _numFmtId = GetXmlNodeInt("@numFmtId");
-    _format = GetXmlNodeString("@formatCode");
-  }
-
-  public bool BuildIn { get; private set; }
-
-  private int _numFmtId;
-
-  //        const string idPath = "@numFmtId";
-  /// <summary>
-  /// Id for number format
-  ///
-  /// Build in ID's
-  ///
-  /// 0   General
-  /// 1   0
-  /// 2   0.00
-  /// 3   #,##0
-  /// 4   #,##0.00
-  /// 9   0%
-  /// 10  0.00%
-  /// 11  0.00E+00
-  /// 12  # ?/?
-  /// 13  # ??/??
-  /// 14  mm-dd-yy
-  /// 15  d-mmm-yy
-  /// 16  d-mmm
-  /// 17  mmm-yy
-  /// 18  h:mm AM/PM
-  /// 19  h:mm:ss AM/PM
-  /// 20  h:mm
-  /// 21  h:mm:ss
-  /// 22  m/d/yy h:mm
-  /// 37  #,##0 ;(#,##0)
-  /// 38  #,##0 ;[Red](#,##0)
-  /// 39  #,##0.00;(#,##0.00)
-  /// 40  #,##0.00;[Red](#,##0.00)
-  /// 45  mm:ss
-  /// 46  [h]:mm:ss
-  /// 47  mmss.0
-  /// 48  ##0.0E+0
-  /// 49  @
-  /// </summary>
-  public int NumFmtId {
-    get => _numFmtId;
-    set => _numFmtId = value;
-  }
-
-  internal override string Id => _format;
-
-  private string _format = string.Empty;
-
-  public string Format {
-    get => _format;
-    set {
-      _numFmtId = ExcelNumberFormat.GetFromBuildIdFromFormat(value);
-      _format = value;
-    }
-  }
-
-  internal string GetNewId(int numFmtId, string format) {
-    if (numFmtId < 0) {
-      numFmtId = ExcelNumberFormat.GetFromBuildIdFromFormat(format);
-    }
-    return numFmtId.ToString();
-  }
-
-  internal static void AddBuildIn(
-      XmlNamespaceManager nameSpaceManager,
-      ExcelStyleCollection<ExcelNumberFormatXml> numberFormats) {
-    numberFormats.Add(
-        "General",
-        new(nameSpaceManager, true) {
-          NumFmtId = 0,
-          Format = "General",
-        });
-    numberFormats.Add(
-        "0",
-        new(nameSpaceManager, true) {
-          NumFmtId = 1,
-          Format = "0",
-        });
-    numberFormats.Add(
-        "0.00",
-        new(nameSpaceManager, true) {
-          NumFmtId = 2,
-          Format = "0.00",
-        });
-    numberFormats.Add(
-        "#,##0",
-        new(nameSpaceManager, true) {
-          NumFmtId = 3,
-          Format = "#,##0",
-        });
-    numberFormats.Add(
-        "#,##0.00",
-        new(nameSpaceManager, true) {
-          NumFmtId = 4,
-          Format = "#,##0.00",
-        });
-    numberFormats.Add(
-        "0%",
-        new(nameSpaceManager, true) {
-          NumFmtId = 9,
-          Format = "0%",
-        });
-    numberFormats.Add(
-        "0.00%",
-        new(nameSpaceManager, true) {
-          NumFmtId = 10,
-          Format = "0.00%",
-        });
-    numberFormats.Add(
-        "0.00E+00",
-        new(nameSpaceManager, true) {
-          NumFmtId = 11,
-          Format = "0.00E+00",
-        });
-    numberFormats.Add(
-        "# ?/?",
-        new(nameSpaceManager, true) {
-          NumFmtId = 12,
-          Format = "# ?/?",
-        });
-    numberFormats.Add(
-        "# ??/??",
-        new(nameSpaceManager, true) {
-          NumFmtId = 13,
-          Format = "# ??/??",
-        });
-    numberFormats.Add(
-        "mm-dd-yy",
-        new(nameSpaceManager, true) {
-          NumFmtId = 14,
-          Format = "mm-dd-yy",
-        });
-    numberFormats.Add(
-        "d-mmm-yy",
-        new(nameSpaceManager, true) {
-          NumFmtId = 15,
-          Format = "d-mmm-yy",
-        });
-    numberFormats.Add(
-        "d-mmm",
-        new(nameSpaceManager, true) {
-          NumFmtId = 16,
-          Format = "d-mmm",
-        });
-    numberFormats.Add(
-        "mmm-yy",
-        new(nameSpaceManager, true) {
-          NumFmtId = 17,
-          Format = "mmm-yy",
-        });
-    numberFormats.Add(
-        "h:mm AM/PM",
-        new(nameSpaceManager, true) {
-          NumFmtId = 18,
-          Format = "h:mm AM/PM",
-        });
-    numberFormats.Add(
-        "h:mm:ss AM/PM",
-        new(nameSpaceManager, true) {
-          NumFmtId = 19,
-          Format = "h:mm:ss AM/PM",
-        });
-    numberFormats.Add(
-        "h:mm",
-        new(nameSpaceManager, true) {
-          NumFmtId = 20,
-          Format = "h:mm",
-        });
-    numberFormats.Add(
-        "h:mm:ss",
-        new(nameSpaceManager, true) {
-          NumFmtId = 21,
-          Format = "h:mm:ss",
-        });
-    numberFormats.Add(
-        "m/d/yy h:mm",
-        new(nameSpaceManager, true) {
-          NumFmtId = 22,
-          Format = "m/d/yy h:mm",
-        });
-    numberFormats.Add(
-        "#,##0 ;(#,##0)",
-        new(nameSpaceManager, true) {
-          NumFmtId = 37,
-          Format = "#,##0 ;(#,##0)",
-        });
-    numberFormats.Add(
-        "#,##0 ;[Red](#,##0)",
-        new(nameSpaceManager, true) {
-          NumFmtId = 38,
-          Format = "#,##0 ;[Red](#,##0)",
-        });
-    numberFormats.Add(
-        "#,##0.00;(#,##0.00)",
-        new(nameSpaceManager, true) {
-          NumFmtId = 39,
-          Format = "#,##0.00;(#,##0.00)",
-        });
-    numberFormats.Add(
-        "#,##0.00;[Red](#,##0.00)",
-        new(nameSpaceManager, true) {
-          NumFmtId = 40,
-          Format = "#,##0.00;[Red](#,#)",
-        });
-    numberFormats.Add(
-        "mm:ss",
-        new(nameSpaceManager, true) {
-          NumFmtId = 45,
-          Format = "mm:ss",
-        });
-    numberFormats.Add(
-        "[h]:mm:ss",
-        new(nameSpaceManager, true) {
-          NumFmtId = 46,
-          Format = "[h]:mm:ss",
-        });
-    numberFormats.Add(
-        "mmss.0",
-        new(nameSpaceManager, true) {
-          NumFmtId = 47,
-          Format = "mmss.0",
-        });
-    numberFormats.Add(
-        "##0.0",
-        new(nameSpaceManager, true) {
-          NumFmtId = 48,
-          Format = "##0.0",
-        });
-    numberFormats.Add(
-        "@",
-        new(nameSpaceManager, true) {
-          NumFmtId = 49,
-          Format = "@",
-        });
-
-    numberFormats.NextId = 164; //Start for custom formats.
-  }
-
-  internal override XmlNode CreateXmlNode(XmlNode topNode) {
-    TopNode = topNode;
-    SetXmlNodeString("@numFmtId", NumFmtId.ToString());
-    SetXmlNodeString("@formatCode", Format);
-    return TopNode;
-  }
-
-  internal enum eFormatType {
-    Unknown = 0,
-    Number = 1,
-    DateTime = 2,
-  }
-
-  private ExcelFormatTranslator _translator;
-
-  internal ExcelFormatTranslator FormatTranslator {
-    get {
-      if (_translator == null) {
-        _translator = new(Format, NumFmtId);
-      }
-      return _translator;
-    }
-  }
-
-  internal class ExcelFormatTranslator {
-    internal ExcelFormatTranslator(string format, int numFmtId) {
-      if (numFmtId == 14) {
-        NetFormat = NetFormatForWidth = "d";
-        NetTextFormat = NetTextFormatForWidth = "";
-        DataType = eFormatType.DateTime;
-      } else if (format.Equals("general", StringComparison.InvariantCultureIgnoreCase)) {
-        NetFormat = NetFormatForWidth = "0.#####";
-        NetTextFormat = NetTextFormatForWidth = "";
-        DataType = eFormatType.Number;
-      } else {
-        ToNetFormat(format, false);
-        ToNetFormat(format, true);
-      }
-    }
-
-    internal string NetTextFormat { get; private set; }
-
-    internal string NetFormat { get; private set; }
-
-    private CultureInfo _ci;
-
-    internal CultureInfo Culture {
-      get {
-        if (_ci == null) {
-          return CultureInfo.CurrentCulture;
-        }
-        return _ci;
-      }
-      private set => _ci = value;
-    }
-
-    internal eFormatType DataType { get; private set; }
-
-    internal string NetTextFormatForWidth { get; private set; }
-
-    internal string NetFormatForWidth { get; private set; }
-
-    internal string FractionFormat { get; private set; }
-
-    private void ToNetFormat(string excelFormat, bool forColWidth) {
-      DataType = eFormatType.Unknown;
-      int secCount = 0;
-      bool isText = false;
-      bool isBracket = false;
-      string bracketText = "";
-      bool prevBslsh = false;
-      bool useMinute = false;
-      bool prevUnderScore = false;
-      bool ignoreNext = false;
-      string specialDateFormat = "";
-      bool containsAmPm = excelFormat.Contains("AM/PM");
-      List<int> lstDec = new List<int>();
-      StringBuilder sb = new StringBuilder();
-      Culture = null;
-      var format = "";
-      var text = "";
-      char clc;
-
-      if (containsAmPm) {
-        excelFormat = Regex.Replace(excelFormat, "AM/PM", "");
-        DataType = eFormatType.DateTime;
-      }
-
-      for (int pos = 0; pos < excelFormat.Length; pos++) {
-        char c = excelFormat[pos];
-        if (c == '"') {
-          isText = !isText;
-        } else {
-          if (ignoreNext) {
-            ignoreNext = false;
-            continue;
-          }
-          if (isText && !isBracket) {
-            sb.Append(c);
-          } else if (isBracket) {
-            if (c == ']') {
-              isBracket = false;
-              if (bracketText[0]
-                  == '$') //Local Info
-              {
-                string[] li = Regex.Split(bracketText, "-");
-                if (li[0].Length > 1) {
-                  sb.Append("\"" + li[0].Substring(1, li[0].Length - 1) + "\""); //Currency symbol
-                }
-                if (li.Length > 1) {
-                  if (li[1].Equals("f800", StringComparison.InvariantCultureIgnoreCase)) {
-                    specialDateFormat = "D";
-                  } else if (li[1].Equals("f400", StringComparison.InvariantCultureIgnoreCase)) {
-                    specialDateFormat = "T";
-                  } else {
-                    var num = int.Parse(li[1], NumberStyles.HexNumber);
-                    try {
-                      Culture = CultureInfo.GetCultureInfo(num & 0xFFFF);
-                    } catch {
-                      Culture = null;
-                    }
-                  }
-                }
-              } else if (bracketText[0] == 't') {
-                sb.Append("hh"); //TODO:This will not be correct for dates over 24H.
-              } else if (bracketText[0] == 'h') {
-                specialDateFormat = "hh"; //TODO:This will not be correct for dates over 24H.
-              }
-            } else {
-              bracketText += c;
-            }
-          } else if (prevUnderScore) {
-            if (forColWidth) {
-              sb.AppendFormat("\"{0}\"", c);
-            }
-            prevUnderScore = false;
-          } else {
-            if (c
-                == ';') //We use first part (for positive only at this stage)
-            {
-              secCount++;
-              if (DataType == eFormatType.DateTime || secCount == 3) {
-                //Add qoutes
-                if (DataType == eFormatType.DateTime) {
-                  SetDecimal(lstDec, sb); //Remove?
-                }
-                lstDec = new();
-                format = sb.ToString();
-                sb = new();
-              } else {
-                sb.Append(c);
-              }
-            } else {
-              clc = c.ToString().ToLower(CultureInfo.InvariantCulture)[0]; //Lowercase character
-              //Set the datetype
-              if (DataType == eFormatType.Unknown) {
-                if (c == '0' || c == '#' || c == '.') {
-                  DataType = eFormatType.Number;
-                } else if (clc == 'y'
-                    || clc == 'm'
-                    || clc == 'd'
-                    || clc == 'h'
-                    || clc == 'm'
-                    || clc == 's') {
-                  DataType = eFormatType.DateTime;
-                }
-              }
-
-              if (prevBslsh) {
-                if (c == '.' || c == ',') {
-                  sb.Append('\\');
-                }
-                sb.Append(c);
-                prevBslsh = false;
-              } else if (c == '[') {
-                bracketText = "";
-                isBracket = true;
-              } else if (c == '\\') {
-                prevBslsh = true;
-              } else if (c == '0'
-                  || c == '#'
-                  || c == '.'
-                  || c == ','
-                  || c == '%'
-                  || clc == 'd'
-                  || clc == 's') {
-                sb.Append(c);
-                if (c == '.') {
-                  lstDec.Add(sb.Length - 1);
-                }
-              } else if (clc == 'h') {
-                if (containsAmPm) {
-                  sb.Append('h');
-                  ;
-                } else {
-                  sb.Append('H');
-                }
-                useMinute = true;
-              } else if (clc == 'm') {
-                if (useMinute) {
-                  sb.Append('m');
-                } else {
-                  sb.Append('M');
-                }
-              } else if (c
-                  == '_') //Skip next but use for alignment
-              {
-                prevUnderScore = true;
-              } else if (c == '?') {
-                sb.Append(' ');
-              } else if (c == '/') {
-                if (DataType == eFormatType.Number) {
-                  int startPos = pos - 1;
-                  while (startPos >= 0
-                          && (excelFormat[startPos] == '?'
-                                  || excelFormat[startPos] == '#'
-                                  || excelFormat[startPos] == '0')) {
-                    startPos--;
-                  }
-
-                  if (startPos
-                      > 0) //RemovePart
-                  {
-                    sb.Remove(sb.Length - (pos - startPos - 1), (pos - startPos - 1));
-                  }
-
-                  int endPos = pos + 1;
-                  while (endPos < excelFormat.Length
-                          && (excelFormat[endPos] == '?'
-                                  || excelFormat[endPos] == '#'
-                                  || (excelFormat[endPos] >= '0' && excelFormat[endPos] <= '9'))) {
-                    endPos++;
-                  }
-                  pos = endPos;
-                  if (FractionFormat != "") {
-                    FractionFormat = excelFormat.Substring(startPos + 1, endPos - startPos - 1);
-                  }
-                  sb.Append('?'); //Will be replaced later on by the fraction
-                } else {
-                  sb.Append('/');
-                }
-              } else if (c == '*') {
-                //repeat char--> ignore
-                ignoreNext = true;
-              } else if (c == '@') {
-                sb.Append("{0}");
-              } else {
-                sb.Append(c);
-              }
-            }
-          }
-        }
-      }
-
-      //Add qoutes
-      if (DataType == eFormatType.DateTime) {
-        SetDecimal(lstDec, sb); //Remove?
-      }
-
-      // AM/PM format
-      if (containsAmPm) {
-        format += "tt";
-      }
-
-      if (format == "") {
-        format = sb.ToString();
-      } else {
-        text = sb.ToString();
-      }
-      if (specialDateFormat != "") {
-        format = specialDateFormat;
-      }
-
-      if (forColWidth) {
-        NetFormatForWidth = format;
-        NetTextFormatForWidth = text;
-      } else {
-        NetFormat = format;
-        NetTextFormat = text;
-      }
-      if (Culture == null) {
-        Culture = CultureInfo.CurrentCulture;
-      }
-    }
-
-    private static void SetDecimal(List<int> lstDec, StringBuilder sb) {
-      if (lstDec.Count > 1) {
-        for (int i = lstDec.Count - 1; i >= 0; i--) {
-          sb.Insert(lstDec[i] + 1, '\'');
-          sb.Insert(lstDec[i], '\'');
-        }
-      }
-    }
-
-    internal string FormatFraction(double d) {
-      int numerator,
-          denomerator;
-
-      int intPart = (int)d;
-
-      string[] fmt = FractionFormat.Split('/');
-
-      if (!int.TryParse(fmt[1], out var fixedDenominator)) {
-        fixedDenominator = 0;
-      }
-
-      if (d == 0 || double.IsNaN(d)) {
-        if (fmt[0].Trim() == "" && fmt[1].Trim() == "") {
-          return new(' ', FractionFormat.Length);
-        }
-        return 0.ToString(fmt[0]) + "/" + 1.ToString(fmt[0]);
-      }
-
-      int maxDigits = fmt[1].Length;
-      string sign = d < 0 ? "-" : "";
-      if (fixedDenominator == 0) {
-        List<double> numerators = new List<double> { 1, 0 };
-        List<double> denominators = new List<double> { 0, 1 };
-
-        if (maxDigits < 1 && maxDigits > 12) {
-          throw (new ArgumentException("Number of digits out of range (1-12)"));
-        }
-
-        int maxNum = 0;
-        for (int i = 0; i < maxDigits; i++) {
-          maxNum += 9 * (int)(Math.Pow(10, i));
-        }
-
-        double divRes = 1 / (Math.Abs(d) - intPart);
-        double result,
-            prevResult = double.NaN;
-        int listPos = 2,
-            index = 1;
-        while (true) {
-          index++;
-          double intDivRes = Math.Floor(divRes);
-          numerators.Add((intDivRes * numerators[index - 1] + numerators[index - 2]));
-          if (numerators[index] > maxNum) {
-            break;
-          }
-
-          denominators.Add((intDivRes * denominators[index - 1] + denominators[index - 2]));
-
-          result = numerators[index] / denominators[index];
-          if (denominators[index] > maxNum) {
-            break;
-          }
-          listPos = index;
-
-          if (result == prevResult) {
-            break;
-          }
-
-          if (result == d) {
-            break;
-          }
-
-          prevResult = result;
-
-          divRes = 1 / (divRes - intDivRes); //Rest
-        }
-
-        numerator = (int)numerators[listPos];
-        denomerator = (int)denominators[listPos];
-      } else {
-        numerator = (int)Math.Round((d - intPart) / (1D / fixedDenominator), 0);
-        denomerator = fixedDenominator;
-      }
-      if (numerator == denomerator || numerator == 0) {
-        if (numerator == denomerator) {
-          intPart++;
-        }
-        return sign + intPart.ToString(NetFormat).Replace("?", new(' ', FractionFormat.Length));
-      }
-      if (intPart == 0) {
-        return sign + FmtInt(numerator, fmt[0]) + "/" + FmtInt(denomerator, fmt[1]);
-      }
-      return sign
-          + intPart
-              .ToString(NetFormat)
-              .Replace("?", FmtInt(numerator, fmt[0]) + "/" + FmtInt(denomerator, fmt[1]));
-    }
-
-    private string FmtInt(double value, string format) {
-      string v = value.ToString("#");
-      string pad = "";
-      if (v.Length < format.Length) {
-        for (int i = format.Length - v.Length - 1; i >= 0; i--) {
-          if (format[i] == '?') {
-            pad += " ";
-          } else if (format[i] == ' ') {
-            pad += "0";
-          }
-        }
-      }
-      return pad + v;
-    }
-  }
-}
diff --git a/EPPlus/Style/XmlAccess/ExcelXfsXml.cs b/EPPlus/Style/XmlAccess/ExcelXfsXml.cs
deleted file mode 100644
index 45acdda..0000000
--- a/EPPlus/Style/XmlAccess/ExcelXfsXml.cs
+++ /dev/null
@@ -1,717 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		                Initial Release		        2009-10-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System;
-using System.Globalization;
-using System.Xml;
-
-namespace OfficeOpenXml.Style.XmlAccess;
-
-/// <summary>
-/// Xml access class xfs records. This is the top level style object.
-/// </summary>
-public sealed class ExcelXfs : StyleXmlHelper {
-  private readonly ExcelStyles _styles;
-
-  internal ExcelXfs(XmlNamespaceManager nameSpaceManager, ExcelStyles styles)
-      : base(nameSpaceManager) {
-    _styles = styles;
-    isBuildIn = false;
-  }
-
-  internal ExcelXfs(XmlNamespaceManager nsm, XmlNode topNode, ExcelStyles styles)
-      : base(nsm, topNode) {
-    _styles = styles;
-    _xfID = GetXmlNodeInt("@xfId");
-    if (_xfID == 0) {
-      isBuildIn = true; //Normal taggen
-    }
-    _numFmtId = GetXmlNodeInt("@numFmtId");
-    _fontId = GetXmlNodeInt("@fontId");
-    _fillId = GetXmlNodeInt("@fillId");
-    _borderId = GetXmlNodeInt("@borderId");
-    _readingOrder = GetReadingOrder(GetXmlNodeString(_readingOrderPath));
-    _indent = GetXmlNodeInt(_indentPath);
-    _shrinkToFit = GetXmlNodeString(_shrinkToFitPath) == "1" ? true : false;
-    _verticalAlignment = GetVerticalAlign(GetXmlNodeString(_verticalAlignPath));
-    _horizontalAlignment = GetHorizontalAlign(GetXmlNodeString(_horizontalAlignPath));
-    _wrapText = GetXmlNodeBool(_wrapTextPath);
-    _textRotation = GetXmlNodeInt(textRotationPath);
-    _hidden = GetXmlNodeBool(_hiddenPath);
-    _locked = GetXmlNodeBool(_lockedPath, true);
-  }
-
-  private ExcelReadingOrder GetReadingOrder(string value) {
-    switch (value) {
-      case "1":
-        return ExcelReadingOrder.LeftToRight;
-      case "2":
-        return ExcelReadingOrder.RightToLeft;
-      default:
-        return ExcelReadingOrder.ContextDependent;
-    }
-  }
-
-  private ExcelHorizontalAlignment GetHorizontalAlign(string align) =>
-    Enum.TryParse<ExcelHorizontalAlignment>(align, true, out var result)
-        ? result
-        : ExcelHorizontalAlignment.General;
-
-  private ExcelVerticalAlignment GetVerticalAlign(string align) =>
-    Enum.TryParse<ExcelVerticalAlignment>(align, true, out var result)
-        ? result
-        : ExcelVerticalAlignment.Bottom;
-
-  private int _xfID;
-
-  /// <summary>
-  /// Style index
-  /// </summary>
-  public int XfId {
-    get => _xfID;
-    set => _xfID = value;
-  }
-
-  private int _numFmtId;
-
-  internal int NumberFormatId {
-    get => _numFmtId;
-    set {
-      _numFmtId = value;
-      ApplyNumberFormat = (value > 0);
-    }
-  }
-
-  private int _fontId;
-
-  internal int FontId {
-    get => _fontId;
-    set => _fontId = value;
-  }
-
-  private int _fillId;
-
-  internal int FillId {
-    get => _fillId;
-    set => _fillId = value;
-  }
-
-  private int _borderId;
-
-  internal int BorderId {
-    get => _borderId;
-    set => _borderId = value;
-  }
-
-  private bool isBuildIn { get; set; }
-
-  internal bool ApplyNumberFormat { get; set; }
-
-  internal bool ApplyFont { get; set; }
-
-  internal bool ApplyFill { get; set; }
-
-  internal bool ApplyBorder { get; set; }
-
-  internal bool ApplyAlignment { get; set; }
-
-  internal bool ApplyProtection { get; set; }
-
-  public ExcelStyles Styles { get; private set; }
-
-  /// <summary>
-  /// Numberformat properties
-  /// </summary>
-  public ExcelNumberFormatXml Numberformat => _styles.NumberFormats[_numFmtId < 0 ? 0 : _numFmtId];
-
-  /// <summary>
-  /// Font properties
-  /// </summary>
-  public ExcelFontXml Font => _styles.Fonts[_fontId < 0 ? 0 : _fontId];
-
-  /// <summary>
-  /// Fill properties
-  /// </summary>
-  public ExcelFillXml Fill => _styles.Fills[_fillId < 0 ? 0 : _fillId];
-
-  /// <summary>
-  /// Border style properties
-  /// </summary>
-  public ExcelBorderXml Border => _styles.Borders[_borderId < 0 ? 0 : _borderId];
-
-  private const string _horizontalAlignPath = "d:alignment/@horizontal";
-  private ExcelHorizontalAlignment _horizontalAlignment = ExcelHorizontalAlignment.General;
-
-  /// <summary>
-  /// Horizontal alignment
-  /// </summary>
-  public ExcelHorizontalAlignment HorizontalAlignment {
-    get => _horizontalAlignment;
-    set => _horizontalAlignment = value;
-  }
-
-  private const string _verticalAlignPath = "d:alignment/@vertical";
-  private ExcelVerticalAlignment _verticalAlignment = ExcelVerticalAlignment.Bottom;
-
-  /// <summary>
-  /// Vertical alignment
-  /// </summary>
-  public ExcelVerticalAlignment VerticalAlignment {
-    get => _verticalAlignment;
-    set => _verticalAlignment = value;
-  }
-
-  private const string _wrapTextPath = "d:alignment/@wrapText";
-  private bool _wrapText;
-
-  /// <summary>
-  /// Wraped text
-  /// </summary>
-  public bool WrapText {
-    get => _wrapText;
-    set => _wrapText = value;
-  }
-
-  private readonly string textRotationPath = "d:alignment/@textRotation";
-  private int _textRotation;
-
-  /// <summary>
-  /// Text rotation angle
-  /// </summary>
-  public int TextRotation {
-    get => (_textRotation == int.MinValue ? 0 : _textRotation);
-    set => _textRotation = value;
-  }
-
-  private const string _lockedPath = "d:protection/@locked";
-  private bool _locked = true;
-
-  /// <summary>
-  /// Locked when sheet is protected
-  /// </summary>
-  public bool Locked {
-    get => _locked;
-    set => _locked = value;
-  }
-
-  private const string _hiddenPath = "d:protection/@hidden";
-  private bool _hidden;
-
-  /// <summary>
-  /// Hide formulas when sheet is protected
-  /// </summary>
-  public bool Hidden {
-    get => _hidden;
-    set => _hidden = value;
-  }
-
-  private const string _readingOrderPath = "d:alignment/@readingOrder";
-  private ExcelReadingOrder _readingOrder = ExcelReadingOrder.ContextDependent;
-
-  /// <summary>
-  /// Readingorder
-  /// </summary>
-  public ExcelReadingOrder ReadingOrder {
-    get => _readingOrder;
-    set => _readingOrder = value;
-  }
-
-  private const string _shrinkToFitPath = "d:alignment/@shrinkToFit";
-  private bool _shrinkToFit;
-
-  /// <summary>
-  /// Shrink to fit
-  /// </summary>
-  public bool ShrinkToFit {
-    get => _shrinkToFit;
-    set => _shrinkToFit = value;
-  }
-
-  private const string _indentPath = "d:alignment/@indent";
-  private int _indent;
-
-  /// <summary>
-  /// Indentation
-  /// </summary>
-  public int Indent {
-    get => (_indent == int.MinValue ? 0 : _indent);
-    set => _indent = value;
-  }
-
-  internal void RegisterEvent(ExcelXfs xf) {
-    //                RegisterEvent(xf, xf.Xf_ChangedEvent);
-  }
-
-  internal override string Id =>
-    XfId
-        + "|"
-        + NumberFormatId
-        + "|"
-        + FontId
-        + "|"
-        + FillId
-        + "|"
-        + BorderId
-        + VerticalAlignment
-        + "|"
-        + HorizontalAlignment
-        + "|"
-        + WrapText
-        + "|"
-        + ReadingOrder
-        + "|"
-        + isBuildIn
-        + TextRotation
-        + Locked
-        + Hidden
-        + ShrinkToFit
-        + Indent;
-
-  //return Numberformat.Id + "|" + Font.Id + "|" + Fill.Id + "|" + Border.Id + VerticalAlignment.ToString() + "|" + HorizontalAlignment.ToString() + "|" + WrapText.ToString() + "|" + ReadingOrder.ToString();
-  internal ExcelXfs Copy() {
-    return Copy(_styles);
-  }
-
-  internal ExcelXfs Copy(ExcelStyles styles) {
-    ExcelXfs newXf = new ExcelXfs(NameSpaceManager, styles);
-    newXf.NumberFormatId = _numFmtId;
-    newXf.FontId = _fontId;
-    newXf.FillId = _fillId;
-    newXf.BorderId = _borderId;
-    newXf.XfId = _xfID;
-    newXf.ReadingOrder = _readingOrder;
-    newXf.HorizontalAlignment = _horizontalAlignment;
-    newXf.VerticalAlignment = _verticalAlignment;
-    newXf.WrapText = _wrapText;
-    newXf.ShrinkToFit = _shrinkToFit;
-    newXf.Indent = _indent;
-    newXf.TextRotation = _textRotation;
-    newXf.Locked = _locked;
-    newXf.Hidden = _hidden;
-    return newXf;
-  }
-
-  internal int GetNewId(
-      ExcelStyleCollection<ExcelXfs> xfsCol,
-      StyleBase styleObject,
-      eStyleClass styleClass,
-      eStyleProperty styleProperty,
-      object value) {
-    ExcelXfs newXfs = Copy();
-    switch (styleClass) {
-      case eStyleClass.Numberformat:
-        newXfs.NumberFormatId = GetIdNumberFormat(styleProperty, value);
-        styleObject.SetIndex(newXfs.NumberFormatId);
-        break;
-      case eStyleClass.Font: {
-        newXfs.FontId = GetIdFont(styleProperty, value);
-        styleObject.SetIndex(newXfs.FontId);
-        break;
-      }
-      case eStyleClass.Fill:
-      case eStyleClass.FillBackgroundColor:
-      case eStyleClass.FillPatternColor:
-        newXfs.FillId = GetIdFill(styleClass, styleProperty, value);
-        styleObject.SetIndex(newXfs.FillId);
-        break;
-      case eStyleClass.GradientFill:
-      case eStyleClass.FillGradientColor1:
-      case eStyleClass.FillGradientColor2:
-        newXfs.FillId = GetIdGradientFill(styleClass, styleProperty, value);
-        styleObject.SetIndex(newXfs.FillId);
-        break;
-      case eStyleClass.Border:
-      case eStyleClass.BorderBottom:
-      case eStyleClass.BorderDiagonal:
-      case eStyleClass.BorderLeft:
-      case eStyleClass.BorderRight:
-      case eStyleClass.BorderTop:
-        newXfs.BorderId = GetIdBorder(styleClass, styleProperty, value);
-        styleObject.SetIndex(newXfs.BorderId);
-        break;
-      case eStyleClass.Style:
-        switch (styleProperty) {
-          case eStyleProperty.XfId:
-            newXfs.XfId = (int)value;
-            break;
-          case eStyleProperty.HorizontalAlign:
-            newXfs.HorizontalAlignment = (ExcelHorizontalAlignment)value;
-            break;
-          case eStyleProperty.VerticalAlign:
-            newXfs.VerticalAlignment = (ExcelVerticalAlignment)value;
-            break;
-          case eStyleProperty.WrapText:
-            newXfs.WrapText = (bool)value;
-            break;
-          case eStyleProperty.ReadingOrder:
-            newXfs.ReadingOrder = (ExcelReadingOrder)value;
-            break;
-          case eStyleProperty.ShrinkToFit:
-            newXfs.ShrinkToFit = (bool)value;
-            break;
-          case eStyleProperty.Indent:
-            newXfs.Indent = (int)value;
-            break;
-          case eStyleProperty.TextRotation:
-            newXfs.TextRotation = (int)value;
-            break;
-          case eStyleProperty.Locked:
-            newXfs.Locked = (bool)value;
-            break;
-          case eStyleProperty.Hidden:
-            newXfs.Hidden = (bool)value;
-            break;
-          default:
-            throw (new("Invalid property for class style."));
-        }
-        break;
-    }
-    int id = xfsCol.FindIndexById(newXfs.Id);
-    if (id < 0) {
-      return xfsCol.Add(newXfs.Id, newXfs);
-    }
-    return id;
-  }
-
-  private int GetIdBorder(eStyleClass styleClass, eStyleProperty styleProperty, object value) {
-    ExcelBorderXml border = Border.Copy();
-
-    switch (styleClass) {
-      case eStyleClass.BorderBottom:
-        SetBorderItem(border.Bottom, styleProperty, value);
-        break;
-      case eStyleClass.BorderDiagonal:
-        SetBorderItem(border.Diagonal, styleProperty, value);
-        break;
-      case eStyleClass.BorderLeft:
-        SetBorderItem(border.Left, styleProperty, value);
-        break;
-      case eStyleClass.BorderRight:
-        SetBorderItem(border.Right, styleProperty, value);
-        break;
-      case eStyleClass.BorderTop:
-        SetBorderItem(border.Top, styleProperty, value);
-        break;
-      case eStyleClass.Border:
-        if (styleProperty == eStyleProperty.BorderDiagonalUp) {
-          border.DiagonalUp = (bool)value;
-        } else if (styleProperty == eStyleProperty.BorderDiagonalDown) {
-          border.DiagonalDown = (bool)value;
-        } else {
-          throw (new("Invalid property for class Border."));
-        }
-        break;
-      default:
-        throw (new("Invalid class/property for class Border."));
-    }
-    int subId;
-    string id = border.Id;
-    subId = _styles.Borders.FindIndexById(id);
-    if (subId == int.MinValue) {
-      return _styles.Borders.Add(id, border);
-    }
-    return subId;
-  }
-
-  private void SetBorderItem(
-      ExcelBorderItemXml excelBorderItem,
-      eStyleProperty styleProperty,
-      object value) {
-    if (styleProperty == eStyleProperty.Style) {
-      excelBorderItem.Style = (ExcelBorderStyle)value;
-    } else if (styleProperty == eStyleProperty.Color
-        || styleProperty == eStyleProperty.Tint
-        || styleProperty == eStyleProperty.IndexedColor) {
-      if (excelBorderItem.Style == ExcelBorderStyle.None) {
-        throw (new("Can't set bordercolor when style is not set."));
-      }
-      excelBorderItem.Color.Rgb = value.ToString();
-    }
-  }
-
-  private int GetIdFill(eStyleClass styleClass, eStyleProperty styleProperty, object value) {
-    ExcelFillXml fill = Fill.Copy();
-
-    switch (styleProperty) {
-      case eStyleProperty.PatternType:
-        if (fill is ExcelGradientFillXml) {
-          fill = new(NameSpaceManager);
-        }
-        fill.PatternType = (ExcelFillStyle)value;
-        break;
-      case eStyleProperty.Color:
-      case eStyleProperty.Tint:
-      case eStyleProperty.IndexedColor:
-      case eStyleProperty.AutoColor:
-        if (fill is ExcelGradientFillXml) {
-          fill = new(NameSpaceManager);
-        }
-        if (fill.PatternType == ExcelFillStyle.None) {
-          throw (new ArgumentException("Can't set color when patterntype is not set."));
-        }
-        ExcelColorXml destColor;
-        if (styleClass == eStyleClass.FillPatternColor) {
-          destColor = fill.PatternColor;
-        } else {
-          destColor = fill.BackgroundColor;
-        }
-
-        if (styleProperty == eStyleProperty.Color) {
-          destColor.Rgb = value.ToString();
-        } else if (styleProperty == eStyleProperty.Tint) {
-          destColor.Tint = (decimal)value;
-        } else if (styleProperty == eStyleProperty.IndexedColor) {
-          destColor.Indexed = (int)value;
-        } else {
-          destColor.Auto = (bool)value;
-        }
-
-        break;
-      default:
-        throw (new ArgumentException("Invalid class/property for class Fill."));
-    }
-    int subId;
-    string id = fill.Id;
-    subId = _styles.Fills.FindIndexById(id);
-    if (subId == int.MinValue) {
-      return _styles.Fills.Add(id, fill);
-    }
-    return subId;
-  }
-
-  private int GetIdGradientFill(
-      eStyleClass styleClass,
-      eStyleProperty styleProperty,
-      object value) {
-    ExcelGradientFillXml fill;
-    if (Fill is ExcelGradientFillXml) {
-      fill = (ExcelGradientFillXml)Fill.Copy();
-    } else {
-      fill = new(Fill.NameSpaceManager);
-      fill.GradientColor1.Rgb = "FFFFFFFF";
-      fill.GradientColor2.Rgb = "FF4F81BD";
-      fill.Type = ExcelFillGradientType.Linear;
-      fill.Degree = 90;
-      fill.Top = double.NaN;
-      fill.Bottom = double.NaN;
-      fill.Left = double.NaN;
-      fill.Right = double.NaN;
-    }
-
-    switch (styleProperty) {
-      case eStyleProperty.GradientType:
-        fill.Type = (ExcelFillGradientType)value;
-        break;
-      case eStyleProperty.GradientDegree:
-        fill.Degree = (double)value;
-        break;
-      case eStyleProperty.GradientTop:
-        fill.Top = (double)value;
-        break;
-      case eStyleProperty.GradientBottom:
-        fill.Bottom = (double)value;
-        break;
-      case eStyleProperty.GradientLeft:
-        fill.Left = (double)value;
-        break;
-      case eStyleProperty.GradientRight:
-        fill.Right = (double)value;
-        break;
-      case eStyleProperty.Color:
-      case eStyleProperty.Tint:
-      case eStyleProperty.IndexedColor:
-      case eStyleProperty.AutoColor:
-        ExcelColorXml destColor;
-
-        if (styleClass == eStyleClass.FillGradientColor1) {
-          destColor = fill.GradientColor1;
-        } else {
-          destColor = fill.GradientColor2;
-        }
-
-        if (styleProperty == eStyleProperty.Color) {
-          destColor.Rgb = value.ToString();
-        } else if (styleProperty == eStyleProperty.Tint) {
-          destColor.Tint = (decimal)value;
-        } else if (styleProperty == eStyleProperty.IndexedColor) {
-          destColor.Indexed = (int)value;
-        } else {
-          destColor.Auto = (bool)value;
-        }
-        break;
-      default:
-        throw (new ArgumentException("Invalid class/property for class Fill."));
-    }
-    int subId;
-    string id = fill.Id;
-    subId = _styles.Fills.FindIndexById(id);
-    if (subId == int.MinValue) {
-      return _styles.Fills.Add(id, fill);
-    }
-    return subId;
-  }
-
-  private int GetIdNumberFormat(eStyleProperty styleProperty, object value) {
-    if (styleProperty == eStyleProperty.Format) {
-      ExcelNumberFormatXml item = null;
-      if (!_styles.NumberFormats.FindById(value.ToString(), ref item)) {
-        item = new(NameSpaceManager) {
-          Format = value.ToString(),
-          NumFmtId = _styles.NumberFormats.NextId++,
-        };
-        _styles.NumberFormats.Add(value.ToString(), item);
-      }
-      return item.NumFmtId;
-    }
-    throw (new("Invalid property for class Numberformat"));
-  }
-
-  private int GetIdFont(eStyleProperty styleProperty, object value) {
-    ExcelFontXml fnt = Font.Copy();
-
-    switch (styleProperty) {
-      case eStyleProperty.Name:
-        fnt.Name = value.ToString();
-        break;
-      case eStyleProperty.Size:
-        fnt.Size = (float)value;
-        break;
-      case eStyleProperty.Family:
-        fnt.Family = (int)value;
-        break;
-      case eStyleProperty.Bold:
-        fnt.Bold = (bool)value;
-        break;
-      case eStyleProperty.Italic:
-        fnt.Italic = (bool)value;
-        break;
-      case eStyleProperty.Strike:
-        fnt.Strike = (bool)value;
-        break;
-      case eStyleProperty.UnderlineType:
-        fnt.UnderLineType = (ExcelUnderLineType)value;
-        break;
-      case eStyleProperty.Color:
-        fnt.Color.Rgb = value.ToString();
-        break;
-      case eStyleProperty.VerticalAlign:
-        fnt.VerticalAlign =
-            ((ExcelVerticalAlignmentFont)value) == ExcelVerticalAlignmentFont.None
-                ? ""
-                : value.ToString().ToLower(CultureInfo.InvariantCulture);
-        break;
-      default:
-        throw (new("Invalid property for class Font"));
-    }
-    int subId;
-    string id = fnt.Id;
-    subId = _styles.Fonts.FindIndexById(id);
-    if (subId == int.MinValue) {
-      return _styles.Fonts.Add(id, fnt);
-    }
-    return subId;
-  }
-
-  internal override XmlNode CreateXmlNode(XmlNode topNode) {
-    return CreateXmlNode(topNode, false);
-  }
-
-  internal XmlNode CreateXmlNode(XmlNode topNode, bool isCellStyleXsf) {
-    TopNode = topNode;
-    var doSetXfId =
-        (!isCellStyleXsf
-            && _xfID > int.MinValue
-            && _styles.CellStyleXfs.Count > 0
-            && _styles.CellStyleXfs[_xfID].newID > int.MinValue);
-    if (_numFmtId > 0) {
-      SetXmlNodeString("@numFmtId", _numFmtId.ToString());
-      if (doSetXfId) {
-        SetXmlNodeString("@applyNumberFormat", "1");
-      }
-    }
-    if (_fontId >= 0) {
-      SetXmlNodeString("@fontId", _styles.Fonts[_fontId].newID.ToString());
-      if (doSetXfId) {
-        SetXmlNodeString("@applyFont", "1");
-      }
-    }
-    if (_fillId >= 0) {
-      SetXmlNodeString("@fillId", _styles.Fills[_fillId].newID.ToString());
-      if (doSetXfId) {
-        SetXmlNodeString("@applyFill", "1");
-      }
-    }
-    if (_borderId >= 0) {
-      SetXmlNodeString("@borderId", _styles.Borders[_borderId].newID.ToString());
-      if (doSetXfId) {
-        SetXmlNodeString("@applyBorder", "1");
-      }
-    }
-    if (_horizontalAlignment != ExcelHorizontalAlignment.General) {
-      SetXmlNodeString(_horizontalAlignPath, SetAlignString(_horizontalAlignment));
-    }
-    if (doSetXfId) {
-      SetXmlNodeString("@xfId", _styles.CellStyleXfs[_xfID].newID.ToString());
-    }
-    if (_verticalAlignment != ExcelVerticalAlignment.Bottom) {
-      SetXmlNodeString(_verticalAlignPath, SetAlignString(_verticalAlignment));
-    }
-    if (_wrapText) {
-      SetXmlNodeString(_wrapTextPath, "1");
-    }
-    if (_readingOrder != ExcelReadingOrder.ContextDependent) {
-      SetXmlNodeString(_readingOrderPath, ((int)_readingOrder).ToString());
-    }
-    if (_shrinkToFit) {
-      SetXmlNodeString(_shrinkToFitPath, "1");
-    }
-    if (_indent > 0) {
-      SetXmlNodeString(_indentPath, _indent.ToString());
-    }
-    if (_textRotation > 0) {
-      SetXmlNodeString(textRotationPath, _textRotation.ToString());
-    }
-    if (!_locked) {
-      SetXmlNodeString(_lockedPath, "0");
-    }
-    if (_hidden) {
-      SetXmlNodeString(_hiddenPath, "1");
-    }
-    return TopNode;
-  }
-
-  private string SetAlignString(Enum align) {
-    string newName = Enum.GetName(align.GetType(), align);
-    return newName.Substring(0, 1).ToLower(CultureInfo.InvariantCulture)
-        + newName.Substring(1, newName.Length - 1);
-  }
-}
diff --git a/EPPlus/Style/XmlAccess/StyleXmlHelper.cs b/EPPlus/Style/XmlAccess/StyleXmlHelper.cs
deleted file mode 100644
index f735ef3..0000000
--- a/EPPlus/Style/XmlAccess/StyleXmlHelper.cs
+++ /dev/null
@@ -1,66 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		                Initial Release		        2009-10-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System.Xml;
-
-namespace OfficeOpenXml.Style.XmlAccess;
-
-/// <summary>
-/// Xml helper class for cell style classes
-/// </summary>
-public abstract class StyleXmlHelper : XmlHelper {
-  internal StyleXmlHelper(XmlNamespaceManager nameSpaceManager)
-      : base(nameSpaceManager) {}
-
-  internal StyleXmlHelper(XmlNamespaceManager nameSpaceManager, XmlNode topNode)
-      : base(nameSpaceManager, topNode) {}
-
-  internal abstract XmlNode CreateXmlNode(XmlNode top);
-
-  internal abstract string Id { get; }
-
-  internal long useCnt = 0;
-  internal int newID = int.MinValue;
-
-  protected bool GetBoolValue(XmlNode topNode, string path) {
-    var node = topNode.SelectSingleNode(path, NameSpaceManager);
-    if (node is XmlAttribute) {
-      return node.Value != "0";
-    }
-    if (node != null
-        && ((node.Attributes["val"] != null && node.Attributes["val"].Value != "0")
-                || node.Attributes["val"] == null)) {
-      return true;
-    }
-    return false;
-  }
-}
diff --git a/EPPlus/Table/ExcelTable.cs b/EPPlus/Table/ExcelTable.cs
deleted file mode 100644
index 674bb73..0000000
--- a/EPPlus/Table/ExcelTable.cs
+++ /dev/null
@@ -1,350 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		Added		30-AUG-2010
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Xml;
-using OfficeOpenXml.Packaging;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.Table;
-
-/// <summary>
-/// Table style Enum
-/// </summary>
-public enum TableStyles {
-  None,
-  Custom,
-  Light1,
-  Light2,
-  Light3,
-  Light4,
-  Light5,
-  Light6,
-  Light7,
-  Light8,
-  Light9,
-  Light10,
-  Light11,
-  Light12,
-  Light13,
-  Light14,
-  Light15,
-  Light16,
-  Light17,
-  Light18,
-  Light19,
-  Light20,
-  Light21,
-  Medium1,
-  Medium2,
-  Medium3,
-  Medium4,
-  Medium5,
-  Medium6,
-  Medium7,
-  Medium8,
-  Medium9,
-  Medium10,
-  Medium11,
-  Medium12,
-  Medium13,
-  Medium14,
-  Medium15,
-  Medium16,
-  Medium17,
-  Medium18,
-  Medium19,
-  Medium20,
-  Medium21,
-  Medium22,
-  Medium23,
-  Medium24,
-  Medium25,
-  Medium26,
-  Medium27,
-  Medium28,
-  Dark1,
-  Dark2,
-  Dark3,
-  Dark4,
-  Dark5,
-  Dark6,
-  Dark7,
-  Dark8,
-  Dark9,
-  Dark10,
-  Dark11,
-}
-
-/// <summary>
-/// An Excel Table
-/// </summary>
-public class ExcelTable : XmlHelper, IEqualityComparer<ExcelTable> {
-  protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
-    "autoFilter",
-    "tableColumns",
-    "tableStyleInfo",
-  ];
-
-  internal ExcelTable(ZipPackageRelationship rel, ExcelWorksheet sheet)
-      : base(sheet.NameSpaceManager) {
-    WorkSheet = sheet;
-    TableUri = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri);
-    RelationshipID = rel.Id;
-    TableXml = sheet._package.GetXmlDocument(TableUri);
-    TopNode = TableXml.DocumentElement;
-    Address = new(GetXmlNodeString("@ref"));
-  }
-
-  /// <summary>
-  /// Provides access to the XML data representing the table in the package.
-  /// </summary>
-  internal XmlDocument TableXml { get; }
-
-  /// <summary>
-  /// The package internal URI to the Table Xml Document.
-  /// </summary>
-  private Uri TableUri { get; }
-
-  internal string RelationshipID { get; set; }
-
-  private const string _idPath = "@id";
-
-  internal int Id => GetXmlNodeInt(_idPath);
-
-  private const string _namePath = "@name";
-  private const string _displayNamePath = "@displayName";
-
-  /// <summary>
-  /// The name of the table object in Excel
-  /// </summary>
-  public string Name => GetXmlNodeString(_namePath);
-
-  /// <summary>
-  /// The worksheet of the table
-  /// </summary>
-  public ExcelWorksheet WorkSheet { get; }
-
-  private ExcelAddressBase _address;
-
-  /// <summary>
-  /// The address of the table
-  /// </summary>
-  public ExcelAddressBase Address {
-    get => _address;
-    set {
-      _address = value;
-      SetXmlNodeString("@ref", value.Address);
-      WriteAutoFilter(ShowTotal);
-    }
-  }
-
-  internal ExcelTableColumnCollection _cols;
-
-  /// <summary>
-  /// Collection of the columns in the table
-  /// </summary>
-  public ExcelTableColumnCollection Columns {
-    get {
-      if (_cols == null) {
-        _cols = new(this);
-      }
-      return _cols;
-    }
-  }
-
-  private const string _headerrowcountPath = "@headerRowCount";
-  private const string _autofilterPath = "d:autoFilter/@ref";
-
-  /// <summary>
-  /// If the header row is visible or not
-  /// </summary>
-  public bool ShowHeader {
-    get => GetXmlNodeInt(_headerrowcountPath) != 0;
-    set {
-      if (Address._toRow - Address._fromRow < 0 && value
-          || Address._toRow - Address._fromRow == 1 && value && ShowTotal) {
-        throw (new("Cant set ShowHeader-property. Table has too few rows"));
-      }
-
-      if (value) {
-        DeleteNode(_headerrowcountPath);
-        WriteAutoFilter(ShowTotal);
-        //for (int i = 0; i < Columns.Count; i++)
-        //{
-        //    var v = WorkSheet.GetValue<string>(Address._fromRow, Address._fromCol + i);
-        //    if (!string.IsNullOrEmpty(v) || v != _cols[i].Name)
-        //    {
-        //        _cols[i].Name = v;
-        //    }
-        //}
-      } else {
-        SetXmlNodeString(_headerrowcountPath, "0");
-        DeleteAllNode(_autofilterPath);
-      }
-    }
-  }
-
-  internal ExcelAddressBase AutoFilterAddress {
-    get {
-      string a = GetXmlNodeString(_autofilterPath);
-      if (a == "") {
-        return null;
-      }
-      return new(a);
-    }
-  }
-
-  private void WriteAutoFilter(bool showTotal) {
-    string autofilterAddress;
-    if (ShowHeader) {
-      if (showTotal) {
-        autofilterAddress = ExcelCellBase.GetAddress(
-            Address._fromRow,
-            Address._fromCol,
-            Address._toRow - 1,
-            Address._toCol);
-      } else {
-        autofilterAddress = Address.Address;
-      }
-      SetXmlNodeString(_autofilterPath, autofilterAddress);
-    }
-  }
-
-  /// <summary>
-  /// If the header row has an autofilter
-  /// </summary>
-  public bool ShowFilter => ShowHeader && AutoFilterAddress != null;
-
-  private const string _totalsrowcountPath = "@totalsRowCount";
-
-  /// <summary>
-  /// If the total row is visible or not
-  /// </summary>
-  public bool ShowTotal {
-    get => GetXmlNodeInt(_totalsrowcountPath) == 1;
-    set {
-      if (value != ShowTotal) {
-        if (value) {
-          Address = new ExcelAddress(
-              WorkSheet.Name,
-              ExcelCellBase.GetAddress(
-                  Address.Start.Row,
-                  Address.Start.Column,
-                  Address.End.Row + 1,
-                  Address.End.Column));
-        } else {
-          Address = new ExcelAddress(
-              WorkSheet.Name,
-              ExcelCellBase.GetAddress(
-                  Address.Start.Row,
-                  Address.Start.Column,
-                  Address.End.Row - 1,
-                  Address.End.Column));
-        }
-        SetXmlNodeString("@ref", Address.Address);
-        if (value) {
-          SetXmlNodeString(_totalsrowcountPath, "1");
-        } else {
-          DeleteNode(_totalsrowcountPath);
-        }
-        WriteAutoFilter(value);
-      }
-    }
-  }
-
-  private const string _stylenamePath = "d:tableStyleInfo/@name";
-
-  /// <summary>
-  /// The style name for custum styles
-  /// </summary>
-  public string StyleName => GetXmlNodeString(_stylenamePath);
-
-  private const string _showfirstcolumnPath = "d:tableStyleInfo/@showFirstColumn";
-
-  /// <summary>
-  /// Display special formatting for the first row
-  /// </summary>
-  public bool ShowFirstColumn => GetXmlNodeBool(_showfirstcolumnPath);
-
-  private const string _showlastcolumnPath = "d:tableStyleInfo/@showLastColumn";
-
-  /// <summary>
-  /// Display special formatting for the last row
-  /// </summary>
-  public bool ShowLastColumn => GetXmlNodeBool(_showlastcolumnPath);
-
-  private const string _showrowstripesPath = "d:tableStyleInfo/@showRowStripes";
-
-  /// <summary>
-  /// Display banded rows
-  /// </summary>
-  public bool ShowRowStripes => GetXmlNodeBool(_showrowstripesPath);
-
-  private const string _showcolumnstripesPath = "d:tableStyleInfo/@showColumnStripes";
-
-  /// <summary>
-  /// Display banded columns
-  /// </summary>
-  public bool ShowColumnStripes => GetXmlNodeBool(_showcolumnstripesPath);
-
-  private const string _totalsrowcellstylePath = "@totalsRowCellStyle";
-
-  /// <summary>
-  /// Named style used for the total row
-  /// </summary>
-  public string TotalsRowCellStyle => GetXmlNodeString(_totalsrowcellstylePath);
-
-  private const string _datacellstylePath = "@dataCellStyle";
-
-  /// <summary>
-  /// Named style used for the data cells
-  /// </summary>
-  public string DataCellStyleName => GetXmlNodeString(_datacellstylePath);
-
-  private const string _headerrowcellstylePath = "@headerRowCellStyle";
-
-  /// <summary>
-  /// Named style used for the header row
-  /// </summary>
-  public string HeaderRowCellStyle => GetXmlNodeString(_headerrowcellstylePath);
-
-  public bool Equals(ExcelTable x, ExcelTable y) {
-    return x.WorkSheet == y.WorkSheet && x.Id == y.Id && x.TableXml.OuterXml == y.TableXml.OuterXml;
-  }
-
-  public int GetHashCode(ExcelTable obj) {
-    return obj.TableXml.OuterXml.GetHashCode();
-  }
-}
diff --git a/EPPlus/Table/ExcelTableCollection.cs b/EPPlus/Table/ExcelTableCollection.cs
deleted file mode 100644
index 5a7941c..0000000
--- a/EPPlus/Table/ExcelTableCollection.cs
+++ /dev/null
@@ -1,124 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		Added		30-AUG-2010
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Xml;
-
-namespace OfficeOpenXml.Table;
-
-/// <summary>
-/// A collection of table objects
-/// </summary>
-public class ExcelTableCollection : IEnumerable<ExcelTable> {
-  private readonly List<ExcelTable> _tables = new();
-  internal Dictionary<string, int> _tableNames = new(StringComparer.InvariantCultureIgnoreCase);
-  private readonly ExcelWorksheet _ws;
-
-  internal ExcelTableCollection(ExcelWorksheet ws) {
-    var pck = ws._package.Package;
-    _ws = ws;
-    foreach (XmlElement node in ws.WorksheetXml.SelectNodes(
-        "//d:tableParts/d:tablePart",
-        ws.NameSpaceManager)) {
-      var rel = ws.Part.GetRelationship(node.GetAttribute("id", ExcelPackage._schemaRelationships));
-      var tbl = new ExcelTable(rel, ws);
-      _tableNames.Add(tbl.Name, _tables.Count);
-      _tables.Add(tbl);
-    }
-  }
-
-  internal string GetNewTableName() {
-    string name = "Table1";
-    int i = 2;
-    while (_ws.Workbook.ExistsTableName(name)) {
-      name = string.Format("Table{0}", i++);
-    }
-    return name;
-  }
-
-  /// <summary>
-  /// Number of items in the collection
-  /// </summary>
-  public int Count => _tables.Count;
-
-  /// <summary>
-  /// Get the table object from a range.
-  /// </summary>
-  /// <param name="range">The range</param>
-  /// <returns>The table. Null if no range matches</returns>
-  public ExcelTable GetFromRange(ExcelRangeBase range) {
-    foreach (var tbl in range.Worksheet.Tables) {
-      if (tbl.Address._address == range._address) {
-        return tbl;
-      }
-    }
-    return null;
-  }
-
-  /// <summary>
-  /// The table Index. Base 0.
-  /// </summary>
-  /// <param name="index"></param>
-  /// <returns></returns>
-  public ExcelTable this[int index] {
-    get {
-      if (index < 0 || index >= _tables.Count) {
-        throw (new ArgumentOutOfRangeException("Table index out of range"));
-      }
-      return _tables[index];
-    }
-  }
-
-  /// <summary>
-  /// Indexer
-  /// </summary>
-  /// <param name="name">The name of the table</param>
-  /// <returns>The table. Null if the table name is not found in the collection</returns>
-  public ExcelTable this[string name] {
-    get {
-      if (_tableNames.ContainsKey(name)) {
-        return _tables[_tableNames[name]];
-      }
-      return null;
-    }
-  }
-
-  public IEnumerator<ExcelTable> GetEnumerator() {
-    return _tables.GetEnumerator();
-  }
-
-  IEnumerator IEnumerable.GetEnumerator() {
-    return _tables.GetEnumerator();
-  }
-}
diff --git a/EPPlus/Table/ExcelTableColumn.cs b/EPPlus/Table/ExcelTableColumn.cs
deleted file mode 100644
index 6680424..0000000
--- a/EPPlus/Table/ExcelTableColumn.cs
+++ /dev/null
@@ -1,203 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		Added		30-AUG-2010
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System;
-using System.Globalization;
-using System.Xml;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.Table;
-
-/// <summary>
-/// Build-in table row functions
-/// </summary>
-public enum RowFunctions {
-  Average,
-  Count,
-  CountNums,
-  Custom,
-  Max,
-  Min,
-  None,
-  StdDev,
-  Sum,
-  Var,
-}
-
-/// <summary>
-/// A table column
-/// </summary>
-public class ExcelTableColumn : XmlHelper {
-  internal ExcelTable _tbl;
-
-  internal ExcelTableColumn(XmlNamespaceManager ns, XmlNode topNode, ExcelTable tbl, int pos)
-      : base(ns, topNode) {
-    _tbl = tbl;
-    Position = pos;
-  }
-
-  /// <summary>
-  /// The column id
-  /// </summary>
-  public int Id {
-    get => GetXmlNodeInt("@id");
-    set => SetXmlNodeString("@id", value.ToString());
-  }
-
-  /// <summary>
-  /// The position of the column
-  /// </summary>
-  public int Position { get; private set; }
-
-  /// <summary>
-  /// The name of the column
-  /// </summary>
-  public string Name {
-    get {
-      var n = GetXmlNodeString("@name");
-      if (string.IsNullOrEmpty(n)) {
-        if (_tbl.ShowHeader) {
-          n = ConvertUtil.ExcelDecodeString(
-              _tbl.WorkSheet.GetValue<string>(
-                  _tbl.Address._fromRow,
-                  _tbl.Address._fromCol + Position));
-        } else {
-          n = "Column" + (Position + 1);
-        }
-      }
-      return n;
-    }
-    set {
-      var v = ConvertUtil.ExcelEncodeString(value);
-      SetXmlNodeString("@name", v);
-      if (_tbl.ShowHeader) {
-        _tbl.WorkSheet.SetValue(_tbl.Address._fromRow, _tbl.Address._fromCol + Position, value);
-      }
-      _tbl.WorkSheet.SetTableTotalFunction(_tbl, this);
-    }
-  }
-
-  /// <summary>
-  /// A string text in the total row
-  /// </summary>
-  public string TotalsRowLabel {
-    get => GetXmlNodeString("@totalsRowLabel");
-    set => SetXmlNodeString("@totalsRowLabel", value);
-  }
-
-  /// <summary>
-  /// Build-in total row functions.
-  /// To set a custom Total row formula use the TotalsRowFormula property
-  /// <seealso cref="TotalsRowFormula"/>
-  /// </summary>
-  public RowFunctions TotalsRowFunction {
-    get {
-      if (GetXmlNodeString("@totalsRowFunction") == "") {
-        return RowFunctions.None;
-      }
-      return (RowFunctions)
-        Enum.Parse(typeof(RowFunctions), GetXmlNodeString("@totalsRowFunction"), true);
-    }
-    set {
-      if (value == RowFunctions.Custom) {
-        throw (new("Use the TotalsRowFormula-property to set a custom table formula"));
-      }
-      string s = value.ToString();
-      s = s.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + s.Substring(1, s.Length - 1);
-      SetXmlNodeString("@totalsRowFunction", s);
-      _tbl.WorkSheet.SetTableTotalFunction(_tbl, this);
-    }
-  }
-
-  private const string _totalsrowformulaPath = "d:totalsRowFormula";
-
-  /// <summary>
-  /// Sets a custom Totals row Formula.
-  /// Be carefull with this property since it is not validated.
-  /// <example>
-  /// tbl.Columns[9].TotalsRowFormula = string.Format("SUM([{0}])",tbl.Columns[9].Name);
-  /// </example>
-  /// </summary>
-  public string TotalsRowFormula {
-    get => GetXmlNodeString(_totalsrowformulaPath);
-    set {
-      if (value.StartsWith("=")) {
-        value = value.Substring(1, value.Length - 1);
-      }
-      SetXmlNodeString("@totalsRowFunction", "custom");
-      SetXmlNodeString(_totalsrowformulaPath, value);
-      _tbl.WorkSheet.SetTableTotalFunction(_tbl, this);
-    }
-  }
-
-  private const string _datacellstylePath = "@dataCellStyle";
-
-  /// <summary>
-  /// The named style for datacells in the column
-  /// </summary>
-  public string DataCellStyleName {
-    get => GetXmlNodeString(_datacellstylePath);
-    set {
-      if (_tbl.WorkSheet.Workbook.Styles.NamedStyles.FindIndexById(value) < 0) {
-        throw (new(string.Format("Named style {0} does not exist.", value)));
-      }
-      SetXmlNodeString(TopNode, _datacellstylePath, value, true);
-
-      int fromRow = _tbl.Address._fromRow + (_tbl.ShowHeader ? 1 : 0),
-          toRow = _tbl.Address._toRow - (_tbl.ShowTotal ? 1 : 0),
-          col = _tbl.Address._fromCol + Position;
-
-      if (fromRow <= toRow) {
-        _tbl.WorkSheet.Cells[fromRow, col, toRow, col].StyleName = value;
-      }
-    }
-  }
-
-  private const string _calculatedcolumnformulaPath = "d:calculatedColumnFormula";
-
-  /// <summary>
-  /// Sets a calculated column Formula.
-  /// Be carefull with this property since it is not validated.
-  /// <example>
-  /// tbl.Columns[9].CalculatedColumnFormula = string.Format("SUM(MyDataTable[[#This Row],[{0}]])",tbl.Columns[9].Name);
-  /// </example>
-  /// </summary>
-  public string CalculatedColumnFormula {
-    get => GetXmlNodeString(_calculatedcolumnformulaPath);
-    set {
-      if (value.StartsWith("=")) {
-        value = value.Substring(1, value.Length - 1);
-      }
-      SetXmlNodeString(_calculatedcolumnformulaPath, value);
-    }
-  }
-}
diff --git a/EPPlus/Table/ExcelTableColumnCollection.cs b/EPPlus/Table/ExcelTableColumnCollection.cs
deleted file mode 100644
index e74adbe..0000000
--- a/EPPlus/Table/ExcelTableColumnCollection.cs
+++ /dev/null
@@ -1,116 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		Added		30-AUG-2010
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Xml;
-
-namespace OfficeOpenXml.Table;
-
-/// <summary>
-/// A collection of table columns
-/// </summary>
-public class ExcelTableColumnCollection : IEnumerable<ExcelTableColumn> {
-  private readonly List<ExcelTableColumn> _cols = new();
-  private readonly Dictionary<string, int> _colNames = new(
-      StringComparer.InvariantCultureIgnoreCase);
-
-  public ExcelTableColumnCollection(ExcelTable table) {
-    Table = table;
-    foreach (XmlNode node in table.TableXml.SelectNodes(
-        "//d:table/d:tableColumns/d:tableColumn",
-        table.NameSpaceManager)) {
-      _cols.Add(new(table.NameSpaceManager, node, table, _cols.Count));
-      _colNames.Add(_cols[_cols.Count - 1].Name, _cols.Count - 1);
-    }
-  }
-
-  /// <summary>
-  /// A reference to the table object
-  /// </summary>
-  public ExcelTable Table { get; private set; }
-
-  /// <summary>
-  /// Number of items in the collection
-  /// </summary>
-  public int Count => _cols.Count;
-
-  /// <summary>
-  /// The column Index. Base 0.
-  /// </summary>
-  /// <param name="index"></param>
-  /// <returns></returns>
-  public ExcelTableColumn this[int index] {
-    get {
-      if (index < 0 || index >= _cols.Count) {
-        throw (new ArgumentOutOfRangeException("Column index out of range"));
-      }
-      return _cols[index];
-    }
-  }
-
-  /// <summary>
-  /// Indexer
-  /// </summary>
-  /// <param name="name">The name of the table</param>
-  /// <returns>The table column. Null if the table name is not found in the collection</returns>
-  public ExcelTableColumn this[string name] {
-    get {
-      if (_colNames.ContainsKey(name)) {
-        return _cols[_colNames[name]];
-      }
-      return null;
-    }
-  }
-
-  IEnumerator<ExcelTableColumn> IEnumerable<ExcelTableColumn>.GetEnumerator() {
-    return _cols.GetEnumerator();
-  }
-
-  IEnumerator IEnumerable.GetEnumerator() {
-    return _cols.GetEnumerator();
-  }
-
-  internal string GetUniqueName(string name) {
-    if (_colNames.ContainsKey(name)) {
-      string newName;
-      var i = 2;
-      do {
-        newName = name + (i++).ToString(CultureInfo.InvariantCulture);
-      } while (_colNames.ContainsKey(newName));
-      return newName;
-    }
-    return name;
-  }
-}
diff --git a/EPPlus/Table/PivotTable/ExcelPivotCacheDefinition.cs b/EPPlus/Table/PivotTable/ExcelPivotCacheDefinition.cs
deleted file mode 100644
index 44543ee..0000000
--- a/EPPlus/Table/PivotTable/ExcelPivotCacheDefinition.cs
+++ /dev/null
@@ -1,235 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		Added		21-MAR-2011
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System;
-using System.Linq;
-using System.Xml;
-using OfficeOpenXml.Packaging;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.Table.PivotTable;
-
-public enum eSourceType {
-  /// <summary>
-  /// Indicates that the cache contains data that consolidates ranges.
-  /// </summary>
-  Consolidation,
-
-  /// <summary>
-  /// Indicates that the cache contains data from an external data source.
-  /// </summary>
-  External,
-
-  /// <summary>
-  /// Indicates that the cache contains a scenario summary report
-  /// </summary>
-  Scenario,
-
-  /// <summary>
-  /// Indicates that the cache contains worksheet data
-  /// </summary>
-  Worksheet,
-}
-
-/// <summary>
-/// Cache definition. This class defines the source data. Note that one cache definition can be shared between many pivot tables.
-/// </summary>
-public class ExcelPivotCacheDefinition : XmlHelper {
-  internal ExcelPivotCacheDefinition(XmlNamespaceManager ns, ExcelPivotTable pivotTable)
-      : base(ns, null) {
-    foreach (var r in pivotTable.Part.GetRelationshipsByType(
-        ExcelPackage._schemaRelationships + "/pivotCacheDefinition")) {
-      Relationship = r;
-    }
-    CacheDefinitionUri = UriHelper.ResolvePartUri(Relationship.SourceUri, Relationship.TargetUri);
-
-    var pck = pivotTable.WorkSheet._package.Package;
-    Part = pck.GetPart(CacheDefinitionUri);
-    LoadXmlSafe(CacheDefinitionXml, Part.GetStream());
-
-    TopNode = CacheDefinitionXml.DocumentElement;
-    PivotTable = pivotTable;
-    if (CacheSource == eSourceType.Worksheet) {
-      var worksheetName = GetXmlNodeString(_sourceWorksheetPath);
-      if (pivotTable.WorkSheet.Workbook.Worksheets.Any(t => t.Name == worksheetName)) {
-        _sourceRange = pivotTable
-            .WorkSheet
-            .Workbook
-            .Worksheets[worksheetName].Cells[GetXmlNodeString(_sourceAddressPath)];
-      }
-    }
-  }
-
-  /// <summary>
-  /// Reference to the internal package part
-  /// </summary>
-  internal ZipPackagePart Part { get; set; }
-
-  /// <summary>
-  /// Provides access to the XML data representing the cache definition in the package.
-  /// </summary>
-  public XmlDocument CacheDefinitionXml { get; private set; } = new();
-
-  /// <summary>
-  /// The package internal URI to the pivottable cache definition Xml Document.
-  /// </summary>
-  public Uri CacheDefinitionUri { get; internal set; }
-
-  internal Uri CacheRecordUri { get; set; }
-
-  internal ZipPackageRelationship Relationship { get; set; }
-
-  internal ZipPackageRelationship RecordRelationship { get; set; }
-
-  internal string RecordRelationshipID {
-    get => GetXmlNodeString("@r:id");
-    set => SetXmlNodeString("@r:id", value);
-  }
-
-  /// <summary>
-  /// Referece to the PivoTable object
-  /// </summary>
-  public ExcelPivotTable PivotTable { get; private set; }
-
-  private const string _sourceWorksheetPath = "d:cacheSource/d:worksheetSource/@sheet";
-  private const string _sourceNamePath = "d:cacheSource/d:worksheetSource/@name";
-  private const string _sourceAddressPath = "d:cacheSource/d:worksheetSource/@ref";
-  internal ExcelRangeBase _sourceRange;
-
-  /// <summary>
-  /// The source data range when the pivottable has a worksheet datasource.
-  /// The number of columns in the range must be intact if this property is changed.
-  /// The range must be in the same workbook as the pivottable.
-  /// </summary>
-  public ExcelRangeBase SourceRange {
-    get {
-      if (_sourceRange == null) {
-        if (CacheSource == eSourceType.Worksheet) {
-          var ws = PivotTable.WorkSheet.Workbook.Worksheets[GetXmlNodeString(_sourceWorksheetPath)];
-          if (ws
-              == null) //Not worksheet, check name or table name
-          {
-            var name = GetXmlNodeString(_sourceNamePath);
-            foreach (var n in PivotTable.WorkSheet.Workbook.Names) {
-              if (name.Equals(n.Name, StringComparison.InvariantCultureIgnoreCase)) {
-                _sourceRange = n;
-                return _sourceRange;
-              }
-            }
-            foreach (var w in PivotTable.WorkSheet.Workbook.Worksheets) {
-              if (w.Tables._tableNames.ContainsKey(name)) {
-                _sourceRange = w.Cells[w.Tables[name].Address.Address];
-                break;
-              }
-              foreach (var n in w.Names) {
-                if (name.Equals(n.Name, StringComparison.InvariantCultureIgnoreCase)) {
-                  _sourceRange = n;
-                  break;
-                }
-              }
-            }
-          } else {
-            _sourceRange = ws.Cells[GetXmlNodeString(_sourceAddressPath)];
-          }
-        } else {
-          throw (new ArgumentException("The cachesource is not a worksheet"));
-        }
-      }
-      return _sourceRange;
-    }
-    set {
-      if (PivotTable.WorkSheet.Workbook != value.Worksheet.Workbook) {
-        throw (new ArgumentException("Range must be in the same package as the pivottable"));
-      }
-
-      var sr = SourceRange;
-      if (value.End.Column - value.Start.Column != sr.End.Column - sr.Start.Column) {
-        throw (new ArgumentException(
-                "Can not change the number of columns(fields) in the SourceRange"));
-      }
-
-      SetXmlNodeString(_sourceWorksheetPath, value.Worksheet.Name);
-      SetXmlNodeString(_sourceAddressPath, value.FirstAddress);
-      _sourceRange = value;
-    }
-  }
-
-  /// <summary>
-  /// Type of source data
-  /// </summary>
-  public eSourceType CacheSource {
-    get {
-      var s = GetXmlNodeString("d:cacheSource/@type");
-      if (s == "") {
-        return eSourceType.Worksheet;
-      }
-      return (eSourceType)Enum.Parse(typeof(eSourceType), s, true);
-    }
-  }
-
-  private string GetStartXml(ExcelRangeBase sourceAddress) {
-    string xml =
-        "<pivotCacheDefinition xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" r:id=\"\" refreshOnLoad=\"1\" refreshedBy=\"SomeUser\" refreshedDate=\"40504.582403125001\" createdVersion=\"1\" refreshedVersion=\"3\" recordCount=\"5\" upgradeOnRefresh=\"1\">";
-
-    xml += "<cacheSource type=\"worksheet\">";
-    xml += string.Format(
-        "<worksheetSource ref=\"{0}\" sheet=\"{1}\" /> ",
-        sourceAddress.Address,
-        sourceAddress.WorkSheet);
-    xml += "</cacheSource>";
-    xml += string.Format(
-        "<cacheFields count=\"{0}\">",
-        sourceAddress._toCol - sourceAddress._fromCol + 1);
-    var sourceWorksheet = PivotTable.WorkSheet.Workbook.Worksheets[sourceAddress.WorkSheet];
-    for (int col = sourceAddress._fromCol; col <= sourceAddress._toCol; col++) {
-      if (sourceWorksheet == null
-          || sourceWorksheet._values.GetValue(sourceAddress._fromRow, col) == null
-          || sourceWorksheet._values.GetValue(sourceAddress._fromRow, col).ToString().Trim()
-              == "") {
-        xml += string.Format(
-            "<cacheField name=\"Column{0}\" numFmtId=\"0\">",
-            col - sourceAddress._fromCol + 1);
-      } else {
-        xml += string.Format(
-            "<cacheField name=\"{0}\" numFmtId=\"0\">",
-            sourceWorksheet._values.GetValue(sourceAddress._fromRow, col));
-      }
-      //xml += "<sharedItems containsNonDate=\"0\" containsString=\"0\" containsBlank=\"1\" /> ";
-      xml += "<sharedItems containsBlank=\"1\" /> ";
-      xml += "</cacheField>";
-    }
-    xml += "</cacheFields>";
-    xml += "</pivotCacheDefinition>";
-
-    return xml;
-  }
-}
diff --git a/EPPlus/Table/PivotTable/ExcelPivotTable.cs b/EPPlus/Table/PivotTable/ExcelPivotTable.cs
deleted file mode 100644
index 47031ca..0000000
--- a/EPPlus/Table/PivotTable/ExcelPivotTable.cs
+++ /dev/null
@@ -1,645 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		Added		21-MAR-2011
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System;
-using System.Collections.Immutable;
-using System.Text.RegularExpressions;
-using System.Xml;
-using OfficeOpenXml.Packaging;
-using OfficeOpenXml.Utils;
-
-namespace OfficeOpenXml.Table.PivotTable;
-
-/// <summary>
-/// An Excel Pivottable
-/// </summary>
-public class ExcelPivotTable : XmlHelper {
-  protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
-    "location",
-    "pivotFields",
-    "rowFields",
-    "rowItems",
-    "colFields",
-    "colItems",
-    "pageFields",
-    "pageItems",
-    "dataFields",
-    "dataItems",
-    "formats",
-    "pivotTableStyleInfo",
-  ];
-
-  internal ExcelPivotTable(ZipPackageRelationship rel, ExcelWorksheet sheet)
-      : base(sheet.NameSpaceManager) {
-    WorkSheet = sheet;
-    PivotTableUri = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri);
-    Relationship = rel;
-    var package = sheet._package;
-    PivotTableXml = package.GetXmlDocument(PivotTableUri);
-    TopNode = PivotTableXml.DocumentElement;
-    Address = new(GetXmlNodeString("d:location/@ref"));
-
-    CacheDefinition = new(sheet.NameSpaceManager, this);
-    LoadFields();
-
-    //Add row fields.
-    foreach (XmlElement rowElem in TopNode.SelectNodes("d:rowFields/d:field", NameSpaceManager)) {
-      if (int.TryParse(rowElem.GetAttribute("x"), out var x) && x >= 0) {
-        RowFields.AddInternal(Fields[x]);
-      } else {
-        rowElem.ParentNode.RemoveChild(rowElem);
-      }
-    }
-
-    ////Add column fields.
-    foreach (XmlElement colElem in TopNode.SelectNodes("d:colFields/d:field", NameSpaceManager)) {
-      if (int.TryParse(colElem.GetAttribute("x"), out var x) && x >= 0) {
-        ColumnFields.AddInternal(Fields[x]);
-      } else {
-        colElem.ParentNode.RemoveChild(colElem);
-      }
-    }
-
-    //Add Page elements
-    //int index = 0;
-    foreach (XmlElement pageElem in TopNode.SelectNodes(
-        "d:pageFields/d:pageField",
-        NameSpaceManager)) {
-      if (int.TryParse(pageElem.GetAttribute("fld"), out var fld) && fld >= 0) {
-        var field = Fields[fld];
-        field._pageFieldSettings = new(NameSpaceManager, pageElem, field, fld);
-        PageFields.AddInternal(field);
-      }
-    }
-
-    //Add data elements
-    //index = 0;
-    foreach (XmlElement dataElem in TopNode.SelectNodes(
-        "d:dataFields/d:dataField",
-        NameSpaceManager)) {
-      if (int.TryParse(dataElem.GetAttribute("fld"), out var fld) && fld >= 0) {
-        var field = Fields[fld];
-        var dataField = new ExcelPivotTableDataField(NameSpaceManager, dataElem, field);
-        DataFields.AddInternal(dataField);
-      }
-    }
-  }
-
-  private void LoadFields() {
-    //Fields.Clear();
-    //int ix=0;
-    //foreach(XmlElement fieldNode in PivotXml.SelectNodes("//d:pivotFields/d:pivotField",NameSpaceManager))
-    //{
-    //    Fields.AddInternal(new ExcelPivotTableField(NameSpaceManager, fieldNode, this, ix++));
-    //}
-
-    int index = 0;
-    //Add fields.
-    foreach (XmlElement fieldElem in TopNode.SelectNodes(
-        "d:pivotFields/d:pivotField",
-        NameSpaceManager)) {
-      var fld = new ExcelPivotTableField(NameSpaceManager, fieldElem, this, index, index++);
-      Fields.AddInternal(fld);
-    }
-
-    //Add fields.
-    index = 0;
-    foreach (XmlElement fieldElem in CacheDefinition.TopNode.SelectNodes(
-        "d:cacheFields/d:cacheField",
-        NameSpaceManager)) {
-      var fld = Fields[index++];
-      fld.SetCacheFieldNode(fieldElem);
-    }
-  }
-
-  private XmlDocument GetStartXml(
-      string name,
-      int id,
-      ExcelAddressBase address,
-      ExcelAddressBase sourceAddress) {
-    string xml = $"""
-         <pivotTableDefinition xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" name="
-         {name}" cacheId="{id
-         }" dataOnRows="1" applyNumberFormats="0" applyBorderFormats="0" applyFontFormats="0" applyPatternFormats="0" applyAlignmentFormats="0" applyWidthHeightFormats="1" dataCaption="Data"  createdVersion="4" showMemberPropertyTips="0" useAutoFormatting="1" itemPrintTitles="1" indent="0" compact="0" compactData="0" gridDropZones="1">
-
-         """;
-    xml +=
-        $"""<location ref="{address.FirstAddress
-    }" firstHeaderRow="1" firstDataRow="1" firstDataCol="1" />""";
-    xml += $"""<pivotFields count="{sourceAddress._toCol - sourceAddress._fromCol + 1}">""";
-    for (int col = sourceAddress._fromCol; col <= sourceAddress._toCol; col++) {
-      xml += """<pivotField showAll="0" />""";
-    }
-    xml += "</pivotFields>";
-    xml +=
-        """<pivotTableStyleInfo name="PivotStyleMedium9" showRowHeaders="1" showColHeaders="1" showRowStripes="0" showColStripes="0" showLastColumn="1" />""";
-    xml += "</pivotTableDefinition>";
-    var result = new XmlDocument();
-    result.LoadXml(xml);
-    return result;
-  }
-
-  internal ZipPackagePart Part { get; }
-
-  /// <summary>
-  /// Provides access to the XML data representing the pivottable in the package.
-  /// </summary>
-  public XmlDocument PivotTableXml { get; private set; }
-
-  /// <summary>
-  /// The package internal URI to the pivottable Xml Document.
-  /// </summary>
-  public Uri PivotTableUri { get; internal set; }
-
-  internal ZipPackageRelationship Relationship { get; set; }
-
-  //const string ID_PATH = "@id";
-  //internal int Id
-  //{
-  //    get
-  //    {
-  //        return GetXmlNodeInt(ID_PATH);
-  //    }
-  //    set
-  //    {
-  //        SetXmlNodeString(ID_PATH, value.ToString());
-  //    }
-  //}
-  private const string _namePath = "@name";
-  private const string _displayNamePath = "@displayName";
-
-  /// <summary>
-  /// Name of the pivottable object in Excel
-  /// </summary>
-  public string Name {
-    get => GetXmlNodeString(_namePath);
-    set {
-      if (WorkSheet.Workbook.ExistsTableName(value)) {
-        throw (new ArgumentException("PivotTable name is not unique"));
-      }
-      string prevName = Name;
-      if (WorkSheet.Tables._tableNames.ContainsKey(prevName)) {
-        int ix = WorkSheet.Tables._tableNames[prevName];
-        WorkSheet.Tables._tableNames.Remove(prevName);
-        WorkSheet.Tables._tableNames.Add(value, ix);
-      }
-      SetXmlNodeString(_namePath, value);
-      SetXmlNodeString(_displayNamePath, CleanDisplayName(value));
-    }
-  }
-
-  /// <summary>
-  /// Reference to the pivot table cache definition object
-  /// </summary>
-  public ExcelPivotCacheDefinition CacheDefinition { get; }
-
-  private string CleanDisplayName(string name) {
-    return Regex.Replace(name, @"[^\w\.-_]", "_");
-  }
-
-  /// <summary>
-  /// The worksheet where the pivottable is located
-  /// </summary>
-  public ExcelWorksheet WorkSheet { get; set; }
-
-  /// <summary>
-  /// The location of the pivot table
-  /// </summary>
-  public ExcelAddressBase Address { get; internal set; }
-
-  /// <summary>
-  /// If multiple datafields are displayed in the row area or the column area
-  /// </summary>
-  public bool DataOnRows {
-    get => GetXmlNodeBool("@dataOnRows");
-    set => SetXmlNodeBool("@dataOnRows", value);
-  }
-
-  /// <summary>
-  /// if true apply legacy table autoformat number format properties.
-  /// </summary>
-  public bool ApplyNumberFormats {
-    get => GetXmlNodeBool("@applyNumberFormats");
-    set => SetXmlNodeBool("@applyNumberFormats", value);
-  }
-
-  /// <summary>
-  /// If true apply legacy table autoformat border properties
-  /// </summary>
-  public bool ApplyBorderFormats {
-    get => GetXmlNodeBool("@applyBorderFormats");
-    set => SetXmlNodeBool("@applyBorderFormats", value);
-  }
-
-  /// <summary>
-  /// If true apply legacy table autoformat font properties
-  /// </summary>
-  public bool ApplyFontFormats {
-    get => GetXmlNodeBool("@applyFontFormats");
-    set => SetXmlNodeBool("@applyFontFormats", value);
-  }
-
-  /// <summary>
-  /// If true apply legacy table autoformat pattern properties
-  /// </summary>
-  public bool ApplyPatternFormats {
-    get => GetXmlNodeBool("@applyPatternFormats");
-    set => SetXmlNodeBool("@applyPatternFormats", value);
-  }
-
-  /// <summary>
-  /// If true apply legacy table autoformat width/height properties.
-  /// </summary>
-  public bool ApplyWidthHeightFormats {
-    get => GetXmlNodeBool("@applyWidthHeightFormats");
-    set => SetXmlNodeBool("@applyWidthHeightFormats", value);
-  }
-
-  /// <summary>
-  /// Show member property information
-  /// </summary>
-  public bool ShowMemberPropertyTips {
-    get => GetXmlNodeBool("@showMemberPropertyTips");
-    set => SetXmlNodeBool("@showMemberPropertyTips", value);
-  }
-
-  /// <summary>
-  /// Show the drill indicators
-  /// </summary>
-  public bool ShowCalcMember {
-    get => GetXmlNodeBool("@showCalcMbrs");
-    set => SetXmlNodeBool("@showCalcMbrs", value);
-  }
-
-  /// <summary>
-  /// If the user is prevented from drilling down on a PivotItem or aggregate value
-  /// </summary>
-  public bool EnableDrill {
-    get => GetXmlNodeBool("@enableDrill", true);
-    set => SetXmlNodeBool("@enableDrill", value);
-  }
-
-  /// <summary>
-  /// Show the drill down buttons
-  /// </summary>
-  public bool ShowDrill {
-    get => GetXmlNodeBool("@showDrill", true);
-    set => SetXmlNodeBool("@showDrill", value);
-  }
-
-  /// <summary>
-  /// If the tooltips should be displayed for PivotTable data cells.
-  /// </summary>
-  public bool ShowDataTips {
-    get => GetXmlNodeBool("@showDataTips", true);
-    set => SetXmlNodeBool("@showDataTips", value, true);
-  }
-
-  /// <summary>
-  /// If the row and column titles from the PivotTable should be printed.
-  /// </summary>
-  public bool FieldPrintTitles {
-    get => GetXmlNodeBool("@fieldPrintTitles");
-    set => SetXmlNodeBool("@fieldPrintTitles", value);
-  }
-
-  /// <summary>
-  /// If the row and column titles from the PivotTable should be printed.
-  /// </summary>
-  public bool ItemPrintTitles {
-    get => GetXmlNodeBool("@itemPrintTitles");
-    set => SetXmlNodeBool("@itemPrintTitles", value);
-  }
-
-  /// <summary>
-  /// If the grand totals should be displayed for the PivotTable columns
-  /// </summary>
-  public bool ColumGrandTotals {
-    get => GetXmlNodeBool("@colGrandTotals");
-    set => SetXmlNodeBool("@colGrandTotals", value);
-  }
-
-  /// <summary>
-  /// If the grand totals should be displayed for the PivotTable rows
-  /// </summary>
-  public bool RowGrandTotals {
-    get => GetXmlNodeBool("@rowGrandTotals");
-    set => SetXmlNodeBool("@rowGrandTotals", value);
-  }
-
-  /// <summary>
-  /// If the drill indicators expand collapse buttons should be printed.
-  /// </summary>
-  public bool PrintDrill {
-    get => GetXmlNodeBool("@printDrill");
-    set => SetXmlNodeBool("@printDrill", value);
-  }
-
-  /// <summary>
-  /// Indicates whether to show error messages in cells.
-  /// </summary>
-  public bool ShowError {
-    get => GetXmlNodeBool("@showError");
-    set => SetXmlNodeBool("@showError", value);
-  }
-
-  /// <summary>
-  /// The string to be displayed in cells that contain errors.
-  /// </summary>
-  public string ErrorCaption {
-    get => GetXmlNodeString("@errorCaption");
-    set => SetXmlNodeString("@errorCaption", value);
-  }
-
-  /// <summary>
-  /// Specifies the name of the value area field header in the PivotTable.
-  /// This caption is shown when the PivotTable when two or more fields are in the values area.
-  /// </summary>
-  public string DataCaption {
-    get => GetXmlNodeString("@dataCaption");
-    set => SetXmlNodeString("@dataCaption", value);
-  }
-
-  /// <summary>
-  /// Show field headers
-  /// </summary>
-  public bool ShowHeaders {
-    get => GetXmlNodeBool("@showHeaders");
-    set => SetXmlNodeBool("@showHeaders", value);
-  }
-
-  /// <summary>
-  /// The number of page fields to display before starting another row or column
-  /// </summary>
-  public int PageWrap {
-    get => GetXmlNodeInt("@pageWrap");
-    set {
-      if (value < 0) {
-        throw new("Value can't be negative");
-      }
-      SetXmlNodeString("@pageWrap", value.ToString());
-    }
-  }
-
-  /// <summary>
-  /// A boolean that indicates whether legacy auto formatting has been applied to the PivotTable view
-  /// </summary>
-  public bool UseAutoFormatting {
-    get => GetXmlNodeBool("@useAutoFormatting");
-    set => SetXmlNodeBool("@useAutoFormatting", value);
-  }
-
-  /// <summary>
-  /// A boolean that indicates whether the in-grid drop zones should be displayed at runtime, and whether classic layout is applied
-  /// </summary>
-  public bool GridDropZones {
-    get => GetXmlNodeBool("@gridDropZones");
-    set => SetXmlNodeBool("@gridDropZones", value);
-  }
-
-  /// <summary>
-  /// Specifies the indentation increment for compact axis and can be used to set the Report Layout to Compact Form
-  /// </summary>
-  public int Indent {
-    get => GetXmlNodeInt("@indent");
-    set => SetXmlNodeString("@indent", value.ToString());
-  }
-
-  /// <summary>
-  /// A boolean that indicates whether data fields in the PivotTable should be displayed in outline form
-  /// </summary>
-  public bool OutlineData {
-    get => GetXmlNodeBool("@outlineData");
-    set => SetXmlNodeBool("@outlineData", value);
-  }
-
-  /// <summary>
-  /// a boolean that indicates whether new fields should have their outline flag set to true
-  /// </summary>
-  public bool Outline {
-    get => GetXmlNodeBool("@outline");
-    set => SetXmlNodeBool("@outline", value);
-  }
-
-  /// <summary>
-  /// A boolean that indicates whether the fields of a PivotTable can have multiple filters set on them
-  /// </summary>
-  public bool MultipleFieldFilters {
-    get => GetXmlNodeBool("@multipleFieldFilters");
-    set => SetXmlNodeBool("@multipleFieldFilters", value);
-  }
-
-  /// <summary>
-  /// A boolean that indicates whether new fields should have their compact flag set to true
-  /// </summary>
-  public bool Compact {
-    get => GetXmlNodeBool("@compact");
-    set => SetXmlNodeBool("@compact", value);
-  }
-
-  /// <summary>
-  /// A boolean that indicates whether the field next to the data field in the PivotTable should be displayed in the same column of the spreadsheet
-  /// </summary>
-  public bool CompactData {
-    get => GetXmlNodeBool("@compactData");
-    set => SetXmlNodeBool("@compactData", value);
-  }
-
-  /// <summary>
-  /// Specifies the string to be displayed for grand totals.
-  /// </summary>
-  public string GrandTotalCaption {
-    get => GetXmlNodeString("@grandTotalCaption");
-    set => SetXmlNodeString("@grandTotalCaption", value);
-  }
-
-  /// <summary>
-  /// Specifies the string to be displayed in row header in compact mode.
-  /// </summary>
-  public string RowHeaderCaption {
-    get => GetXmlNodeString("@rowHeaderCaption");
-    set => SetXmlNodeString("@rowHeaderCaption", value);
-  }
-
-  /// <summary>
-  /// Specifies the string to be displayed in cells with no value
-  /// </summary>
-  public string MissingCaption {
-    get => GetXmlNodeString("@missingCaption");
-    set => SetXmlNodeString("@missingCaption", value);
-  }
-
-  private const string _firstheaderrowPath = "d:location/@firstHeaderRow";
-
-  /// <summary>
-  /// Specifies the first row of the PivotTable header, relative to the top left cell in the ref value
-  /// </summary>
-  public int FirstHeaderRow {
-    get => GetXmlNodeInt(_firstheaderrowPath);
-    set => SetXmlNodeString(_firstheaderrowPath, value.ToString());
-  }
-
-  private const string _firstdatarowPath = "d:location/@firstDataRow";
-
-  /// <summary>
-  /// Specifies the first column of the PivotTable data, relative to the top left cell in the ref value
-  /// </summary>
-  public int FirstDataRow {
-    get => GetXmlNodeInt(_firstdatarowPath);
-    set => SetXmlNodeString(_firstdatarowPath, value.ToString());
-  }
-
-  private const string _firstdatacolPath = "d:location/@firstDataCol";
-
-  /// <summary>
-  /// Specifies the first column of the PivotTable data, relative to the top left cell in the ref value
-  /// </summary>
-  public int FirstDataCol {
-    get => GetXmlNodeInt(_firstdatacolPath);
-    set => SetXmlNodeString(_firstdatacolPath, value.ToString());
-  }
-
-  private ExcelPivotTableFieldCollection _fields;
-
-  /// <summary>
-  /// The fields in the table
-  /// </summary>
-  public ExcelPivotTableFieldCollection Fields {
-    get {
-      if (_fields == null) {
-        _fields = new(this, "");
-      }
-      return _fields;
-    }
-  }
-
-  private ExcelPivotTableRowColumnFieldCollection _rowFields;
-
-  /// <summary>
-  /// Row label fields
-  /// </summary>
-  public ExcelPivotTableRowColumnFieldCollection RowFields {
-    get {
-      if (_rowFields == null) {
-        _rowFields = new(this, "rowFields");
-      }
-      return _rowFields;
-    }
-  }
-
-  private ExcelPivotTableRowColumnFieldCollection _columnFields;
-
-  /// <summary>
-  /// Column label fields
-  /// </summary>
-  public ExcelPivotTableRowColumnFieldCollection ColumnFields {
-    get {
-      if (_columnFields == null) {
-        _columnFields = new(this, "colFields");
-      }
-      return _columnFields;
-    }
-  }
-
-  private ExcelPivotTableDataFieldCollection _dataFields;
-
-  /// <summary>
-  /// Value fields
-  /// </summary>
-  public ExcelPivotTableDataFieldCollection DataFields {
-    get {
-      if (_dataFields == null) {
-        _dataFields = new(this);
-      }
-      return _dataFields;
-    }
-  }
-
-  private ExcelPivotTableRowColumnFieldCollection _pageFields;
-
-  /// <summary>
-  /// Report filter fields
-  /// </summary>
-  public ExcelPivotTableRowColumnFieldCollection PageFields {
-    get {
-      if (_pageFields == null) {
-        _pageFields = new(this, "pageFields");
-      }
-      return _pageFields;
-    }
-  }
-
-  private const string _stylenamePath = "d:pivotTableStyleInfo/@name";
-
-  /// <summary>
-  /// Pivot style name. Used for custom styles
-  /// </summary>
-  public string StyleName {
-    get => GetXmlNodeString(_stylenamePath);
-    set {
-      if (value.StartsWith("PivotStyle")) {
-        try {
-          _tableStyle = (TableStyles)
-            Enum.Parse(typeof(TableStyles), value.Substring(10, value.Length - 10), true);
-        } catch {
-          _tableStyle = TableStyles.Custom;
-        }
-      } else if (value == "None") {
-        _tableStyle = TableStyles.None;
-        value = "";
-      } else {
-        _tableStyle = TableStyles.Custom;
-      }
-      SetXmlNodeString(_stylenamePath, value, true);
-    }
-  }
-
-  private TableStyles _tableStyle = TableStyles.Medium6;
-
-  /// <summary>
-  /// The table style. If this property is cusom the style from the StyleName propery is used.
-  /// </summary>
-  public TableStyles TableStyle {
-    get => _tableStyle;
-    set {
-      _tableStyle = value;
-      if (value != TableStyles.Custom) {
-        SetXmlNodeString(_stylenamePath, "PivotStyle" + value);
-      }
-    }
-  }
-
-  internal int CacheID {
-    get => GetXmlNodeInt("@cacheId");
-    set => SetXmlNodeString("@cacheId", value.ToString());
-  }
-}
diff --git a/EPPlus/Table/PivotTable/ExcelPivotTableCollection.cs b/EPPlus/Table/PivotTable/ExcelPivotTableCollection.cs
deleted file mode 100644
index fe9cc63..0000000
--- a/EPPlus/Table/PivotTable/ExcelPivotTableCollection.cs
+++ /dev/null
@@ -1,93 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		Added		21-MAR-2011
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-
-namespace OfficeOpenXml.Table.PivotTable;
-
-/// <summary>
-/// A collection of pivottable objects
-/// </summary>
-public class ExcelPivotTableCollection : IEnumerable<ExcelPivotTable> {
-  private readonly List<ExcelPivotTable> _pivotTables = new();
-  internal readonly Dictionary<string, int> _pivotTableNames = new();
-
-  internal ExcelPivotTableCollection(ExcelWorksheet ws) {
-    foreach (var rel in ws.Part.GetRelationships()) {
-      if (rel.RelationshipType == ExcelPackage._schemaRelationships + "/pivotTable") {
-        var tbl = new ExcelPivotTable(rel, ws);
-        _pivotTableNames.Add(tbl.Name, _pivotTables.Count);
-        _pivotTables.Add(tbl);
-      }
-    }
-  }
-
-  public int Count => _pivotTables.Count;
-
-  /// <summary>
-  /// The pivottable Index. Base 0.
-  /// </summary>
-  /// <param name="index"></param>
-  /// <returns></returns>
-  public ExcelPivotTable this[int index] {
-    get {
-      if (index < 0 || index >= _pivotTables.Count) {
-        throw (new ArgumentOutOfRangeException("PivotTable index out of range"));
-      }
-      return _pivotTables[index];
-    }
-  }
-
-  /// <summary>
-  /// Pivottabes accesed by name
-  /// </summary>
-  /// <param name="name">The name of the pivottable</param>
-  /// <returns>The Pivotable. Null if the no match is found</returns>
-  public ExcelPivotTable this[string name] {
-    get {
-      if (_pivotTableNames.ContainsKey(name)) {
-        return _pivotTables[_pivotTableNames[name]];
-      }
-      return null;
-    }
-  }
-
-  public IEnumerator<ExcelPivotTable> GetEnumerator() {
-    return _pivotTables.GetEnumerator();
-  }
-
-  IEnumerator IEnumerable.GetEnumerator() {
-    return _pivotTables.GetEnumerator();
-  }
-}
diff --git a/EPPlus/Table/PivotTable/ExcelPivotTableDataField.cs b/EPPlus/Table/PivotTable/ExcelPivotTableDataField.cs
deleted file mode 100644
index bfe8c52..0000000
--- a/EPPlus/Table/PivotTable/ExcelPivotTableDataField.cs
+++ /dev/null
@@ -1,190 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		Added		21-MAR-2011
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System;
-using System.Globalization;
-using System.Xml;
-using OfficeOpenXml.Style.XmlAccess;
-
-namespace OfficeOpenXml.Table.PivotTable;
-
-/// <summary>
-/// A pivo table data field
-/// </summary>
-public class ExcelPivotTableDataField : XmlHelper {
-  internal ExcelPivotTableDataField(
-      XmlNamespaceManager ns,
-      XmlNode topNode,
-      ExcelPivotTableField field)
-      : base(ns, topNode) {
-    if (topNode.Attributes.Count == 0) {
-      Index = field.Index;
-      BaseField = 0;
-      BaseItem = 0;
-    }
-
-    Field = field;
-  }
-
-  /// <summary>
-  /// The field
-  /// </summary>
-  public ExcelPivotTableField Field { get; private set; }
-
-  /// <summary>
-  /// The index of the datafield
-  /// </summary>
-  public int Index {
-    get => GetXmlNodeInt("@fld");
-    internal set => SetXmlNodeString("@fld", value.ToString());
-  }
-
-  /// <summary>
-  /// The name of the datafield
-  /// </summary>
-  public string Name {
-    get => GetXmlNodeString("@name");
-    set {
-      if (Field._table.DataFields.ExistsDfName(value, this)) {
-        throw (new InvalidOperationException("Duplicate datafield name"));
-      }
-      SetXmlNodeString("@name", value);
-    }
-  }
-
-  /// <summary>
-  /// Field index. Reference to the field collection
-  /// </summary>
-  public int BaseField {
-    get => GetXmlNodeInt("@baseField");
-    set => SetXmlNodeString("@baseField", value.ToString());
-  }
-
-  /// <summary>
-  /// Specifies the index to the base item when the ShowDataAs calculation is in use
-  /// </summary>
-  public int BaseItem {
-    get => GetXmlNodeInt("@baseItem");
-    set => SetXmlNodeString("@baseItem", value.ToString());
-  }
-
-  /// <summary>
-  /// Number format id.
-  /// </summary>
-  internal int NumFmtId {
-    get => GetXmlNodeInt("@numFmtId");
-    set => SetXmlNodeString("@numFmtId", value.ToString());
-  }
-
-  /// <summary>
-  /// Number format for the data column
-  /// </summary>
-  public string Format {
-    get {
-      foreach (var nf in Field._table.WorkSheet.Workbook.Styles.NumberFormats) {
-        if (nf.NumFmtId == NumFmtId) {
-          return nf.Format;
-        }
-      }
-      return Field._table.WorkSheet.Workbook.Styles.NumberFormats[0].Format;
-    }
-    set {
-      var styles = Field._table.WorkSheet.Workbook.Styles;
-
-      ExcelNumberFormatXml nf = null;
-      if (!styles.NumberFormats.FindById(value, ref nf)) {
-        nf = new(NameSpaceManager) {
-          Format = value,
-          NumFmtId = styles.NumberFormats.NextId++,
-        };
-        styles.NumberFormats.Add(value, nf);
-      }
-      NumFmtId = nf.NumFmtId;
-    }
-  }
-
-  /// <summary>
-  /// Type of aggregate function
-  /// </summary>
-  public DataFieldFunctions Function {
-    get {
-      string s = GetXmlNodeString("@subtotal");
-      if (s == "") {
-        return DataFieldFunctions.None;
-      }
-      return (DataFieldFunctions)Enum.Parse(typeof(DataFieldFunctions), s, true);
-    }
-    set {
-      string v;
-      switch (value) {
-        case DataFieldFunctions.None:
-          DeleteNode("@subtotal");
-          return;
-        case DataFieldFunctions.CountNums:
-          v = "CountNums";
-          break;
-        case DataFieldFunctions.StdDev:
-          v = "stdDev";
-          break;
-        case DataFieldFunctions.StdDevP:
-          v = "stdDevP";
-          break;
-        default:
-          v = value.ToString().ToLower(CultureInfo.InvariantCulture);
-          break;
-      }
-      SetXmlNodeString("@subtotal", v);
-    }
-  }
-  /////Since we have no items, Excel will crash when we use showDataAs options that require baseItem's
-  //public eShowDataAs ShowDataAs
-  //{
-  //    get
-  //    {
-  //        string s = GetXmlNodeString("@showDataAs");
-  //        if (s == "")
-  //        {
-  //            return eShowDataAs.Normal;
-  //        }
-  //        else
-  //        {
-  //            return (eShowDataAs)Enum.Parse(typeof(eShowDataAs), s, true);
-  //        }
-  //    }
-  //    set
-  //    {
-  //        string v = value.ToString();
-  //        v = v.Substring(0, 1).ToLower() + v.Substring(1);
-  //        SetXmlNodeString("@showDataAs", v);
-  //    }
-  //}
-}
diff --git a/EPPlus/Table/PivotTable/ExcelPivotTableField.cs b/EPPlus/Table/PivotTable/ExcelPivotTableField.cs
deleted file mode 100644
index 05570f2..0000000
--- a/EPPlus/Table/PivotTable/ExcelPivotTableField.cs
+++ /dev/null
@@ -1,566 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		Added		21-MAR-2011
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System;
-using System.Globalization;
-using System.Xml;
-
-namespace OfficeOpenXml.Table.PivotTable;
-
-/// <summary>
-/// Defines the axis for a PivotTable
-/// </summary>
-public enum ePivotFieldAxis {
-  /// <summary>
-  /// None
-  /// </summary>
-  None = -1,
-
-  /// <summary>
-  /// Column axis
-  /// </summary>
-  Column,
-
-  /// <summary>
-  /// Page axis (Include Count Filter)
-  ///
-  /// </summary>
-  Page,
-
-  /// <summary>
-  /// Row axis
-  /// </summary>
-  Row,
-
-  /// <summary>
-  /// Values axis
-  /// </summary>
-  Values,
-}
-
-/// <summary>
-/// Build-in table row functions
-/// </summary>
-public enum DataFieldFunctions {
-  Average,
-  Count,
-  CountNums,
-  Max,
-  Min,
-  Product,
-  None,
-  StdDev,
-  StdDevP,
-  Sum,
-  Var,
-  VarP,
-}
-
-/// <summary>
-/// Defines the data formats for a field in the PivotTable
-/// </summary>
-public enum eShowDataAs {
-  /// <summary>
-  /// Indicates the field is shown as the "difference from" a value.
-  /// </summary>
-  Difference,
-
-  /// <summary>
-  /// Indicates the field is shown as the "index.
-  /// </summary>
-  Index,
-
-  /// <summary>
-  /// Indicates that the field is shown as its normal datatype.
-  /// </summary>
-  Normal,
-
-  /// <summary>
-  /// /Indicates the field is show as the "percentage of" a value
-  /// </summary>
-  Percent,
-
-  /// <summary>
-  /// Indicates the field is shown as the "percentage difference from" a value.
-  /// </summary>
-  PercentDiff,
-
-  /// <summary>
-  /// Indicates the field is shown as the percentage of column.
-  /// </summary>
-  PercentOfCol,
-
-  /// <summary>
-  /// Indicates the field is shown as the percentage of row
-  /// </summary>
-  PercentOfRow,
-
-  /// <summary>
-  /// Indicates the field is shown as percentage of total.
-  /// </summary>
-  PercentOfTotal,
-
-  /// <summary>
-  /// Indicates the field is shown as running total in the table.
-  /// </summary>
-  RunTotal,
-}
-
-/// <summary>
-/// Built-in subtotal functions
-/// </summary>
-[Flags]
-public enum eSubTotalFunctions {
-  None = 1,
-  Count = 2,
-  CountA = 4,
-  Avg = 8,
-  Default = 16,
-  Min = 32,
-  Max = 64,
-  Product = 128,
-  StdDev = 256,
-  StdDevP = 512,
-  Sum = 1024,
-  Var = 2048,
-  VarP = 4096,
-}
-
-/// <summary>
-/// Data grouping
-/// </summary>
-[Flags]
-public enum eDateGroupBy {
-  Years = 1,
-  Quarters = 2,
-  Months = 4,
-  Days = 8,
-  Hours = 16,
-  Minutes = 32,
-  Seconds = 64,
-}
-
-/// <summary>
-/// Sorting
-/// </summary>
-public enum eSortType {
-  None,
-  Ascending,
-  Descending,
-}
-
-/// <summary>
-/// A pivot table field.
-/// </summary>
-public class ExcelPivotTableField : XmlHelper {
-  internal ExcelPivotTable _table;
-
-  internal ExcelPivotTableField(
-      XmlNamespaceManager ns,
-      XmlNode topNode,
-      ExcelPivotTable table,
-      int index,
-      int baseIndex)
-      : base(ns, topNode) {
-    Index = index;
-    BaseIndex = baseIndex;
-    _table = table;
-  }
-
-  public int Index { get; set; }
-
-  internal int BaseIndex { get; set; }
-
-  /// <summary>
-  /// Name of the field
-  /// </summary>
-  public string Name {
-    get {
-      string v = GetXmlNodeString("@name");
-      if (v == "") {
-        return _cacheFieldHelper.GetXmlNodeString("@name");
-      }
-      return v;
-    }
-    set => SetXmlNodeString("@name", value);
-  }
-
-  /// <summary>
-  /// Compact mode
-  /// </summary>
-  public bool Compact {
-    get => GetXmlNodeBool("@compact");
-    set => SetXmlNodeBool("@compact", value);
-  }
-
-  /// <summary>
-  /// A boolean that indicates whether the items in this field should be shown in Outline form
-  /// </summary>
-  public bool Outline {
-    get => GetXmlNodeBool("@outline");
-    set => SetXmlNodeBool("@outline", value);
-  }
-
-  /// <summary>
-  /// The custom text that is displayed for the subtotals label
-  /// </summary>
-  public bool SubtotalTop {
-    get => GetXmlNodeBool("@subtotalTop");
-    set => SetXmlNodeBool("@subtotalTop", value);
-  }
-
-  /// <summary>
-  /// A boolean that indicates whether to show all items for this field
-  /// </summary>
-  public bool ShowAll {
-    get => GetXmlNodeBool("@showAll");
-    set => SetXmlNodeBool("@showAll", value);
-  }
-
-  /// <summary>
-  /// The type of sort that is applied to this field
-  /// </summary>
-  public eSortType Sort {
-    get {
-      string v = GetXmlNodeString("@sortType");
-      return v == "" ? eSortType.None : (eSortType)Enum.Parse(typeof(eSortType), v, true);
-    }
-    set {
-      if (value == eSortType.None) {
-        DeleteNode("@sortType");
-      } else {
-        SetXmlNodeString("@sortType", value.ToString().ToLower(CultureInfo.InvariantCulture));
-      }
-    }
-  }
-
-  /// <summary>
-  /// A boolean that indicates whether manual filter is in inclusive mode
-  /// </summary>
-  public bool IncludeNewItemsInFilter {
-    get => GetXmlNodeBool("@includeNewItemsInFilter");
-    set => SetXmlNodeBool("@includeNewItemsInFilter", value);
-  }
-
-  /// <summary>
-  /// Enumeration of the different subtotal operations that can be applied to page, row or column fields
-  /// </summary>
-  public eSubTotalFunctions SubTotalFunctions {
-    get {
-      eSubTotalFunctions ret = 0;
-      XmlNodeList nl = TopNode.SelectNodes("d:items/d:item/@t", NameSpaceManager);
-      if (nl.Count == 0) {
-        return eSubTotalFunctions.None;
-      }
-      foreach (XmlAttribute item in nl) {
-        try {
-          ret |= (eSubTotalFunctions)Enum.Parse(typeof(eSubTotalFunctions), item.Value, true);
-        } catch (ArgumentException ex) {
-          throw new ArgumentException(
-              "Unable to parse value of "
-                  + item.Value
-                  + " to a valid pivot table subtotal function",
-              ex);
-        }
-      }
-      return ret;
-    }
-    set {
-      if ((value & eSubTotalFunctions.None) == eSubTotalFunctions.None
-          && (value != eSubTotalFunctions.None)) {
-        throw (new ArgumentException("Value None can not be combined with other values."));
-      }
-      if ((value & eSubTotalFunctions.Default) == eSubTotalFunctions.Default
-          && (value != eSubTotalFunctions.Default)) {
-        throw (new ArgumentException("Value Default can not be combined with other values."));
-      }
-
-      // remove old attribute
-      XmlNodeList nl = TopNode.SelectNodes("d:items/d:item/@t", NameSpaceManager);
-      if (nl.Count > 0) {
-        foreach (XmlAttribute item in nl) {
-          DeleteNode("@" + item.Value + "Subtotal");
-          item.OwnerElement.ParentNode.RemoveChild(item.OwnerElement);
-        }
-      }
-
-      if (value == eSubTotalFunctions.None) {
-        // for no subtotals, set defaultSubtotal to off
-        SetXmlNodeBool("@defaultSubtotal", false);
-        TopNode.InnerXml = "";
-      } else {
-        string innerXml = "";
-        int count = 0;
-        foreach (eSubTotalFunctions e in Enum.GetValues(typeof(eSubTotalFunctions))) {
-          if ((value & e) == e) {
-            var newTotalType = e.ToString();
-            var totalType =
-                char.ToLower(newTotalType[0], CultureInfo.InvariantCulture)
-                    + newTotalType.Substring(1);
-            // add new attribute
-            SetXmlNodeBool("@" + totalType + "Subtotal", true);
-            innerXml += "<item t=\"" + totalType + "\" />";
-            count++;
-          }
-        }
-        TopNode.InnerXml = string.Format("<items count=\"{0}\">{1}</items>", count, innerXml);
-      }
-    }
-  }
-
-  /// <summary>
-  /// Type of axis
-  /// </summary>
-  public ePivotFieldAxis Axis {
-    get {
-      switch (GetXmlNodeString("@axis")) {
-        case "axisRow":
-          return ePivotFieldAxis.Row;
-        case "axisCol":
-          return ePivotFieldAxis.Column;
-        case "axisPage":
-          return ePivotFieldAxis.Page;
-        case "axisValues":
-          return ePivotFieldAxis.Values;
-        default:
-          return ePivotFieldAxis.None;
-      }
-    }
-    internal set {
-      switch (value) {
-        case ePivotFieldAxis.Row:
-          SetXmlNodeString("@axis", "axisRow");
-          break;
-        case ePivotFieldAxis.Column:
-          SetXmlNodeString("@axis", "axisCol");
-          break;
-        case ePivotFieldAxis.Values:
-          SetXmlNodeString("@axis", "axisValues");
-          break;
-        case ePivotFieldAxis.Page:
-          SetXmlNodeString("@axis", "axisPage");
-          break;
-        default:
-          DeleteNode("@axis");
-          break;
-      }
-    }
-  }
-
-  /// <summary>
-  /// If the field is a row field
-  /// </summary>
-  public bool IsRowField {
-    get =>
-      (TopNode.SelectSingleNode(
-              string.Format("../../d:rowFields/d:field[@x={0}]", Index),
-              NameSpaceManager) != null);
-    internal set {
-      if (value) {
-        var rowsNode = TopNode.SelectSingleNode("../../d:rowFields", NameSpaceManager);
-        if (rowsNode == null) {
-          _table.CreateNode("d:rowFields");
-        }
-        rowsNode = TopNode.SelectSingleNode("../../d:rowFields", NameSpaceManager);
-
-        AppendField(rowsNode, Index, "field", "x");
-        if (BaseIndex == Index) {
-          TopNode.InnerXml = "<items count=\"1\"><item t=\"default\" /></items>";
-        } else {
-          TopNode.InnerXml = "<items count=\"0\"></items>";
-        }
-      } else {
-        XmlElement node =
-            TopNode.SelectSingleNode(
-                string.Format("../../d:rowFields/d:field[@x={0}]", Index),
-                NameSpaceManager) as XmlElement;
-        if (node != null) {
-          node.ParentNode.RemoveChild(node);
-        }
-      }
-    }
-  }
-
-  /// <summary>
-  /// If the field is a column field
-  /// </summary>
-  public bool IsColumnField {
-    get =>
-      (TopNode.SelectSingleNode(
-              string.Format("../../d:colFields/d:field[@x={0}]", Index),
-              NameSpaceManager) != null);
-    internal set {
-      if (value) {
-        var columnsNode = TopNode.SelectSingleNode("../../d:colFields", NameSpaceManager);
-        if (columnsNode == null) {
-          _table.CreateNode("d:colFields");
-        }
-        columnsNode = TopNode.SelectSingleNode("../../d:colFields", NameSpaceManager);
-
-        AppendField(columnsNode, Index, "field", "x");
-        if (BaseIndex == Index) {
-          TopNode.InnerXml = "<items count=\"1\"><item t=\"default\" /></items>";
-        } else {
-          TopNode.InnerXml = "<items count=\"0\"></items>";
-        }
-      } else {
-        XmlElement node =
-            TopNode.SelectSingleNode(
-                string.Format("../../d:colFields/d:field[@x={0}]", Index),
-                NameSpaceManager) as XmlElement;
-        if (node != null) {
-          node.ParentNode.RemoveChild(node);
-        }
-      }
-    }
-  }
-
-  /// <summary>
-  /// If the field is a datafield
-  /// </summary>
-  public bool IsDataField => GetXmlNodeBool("@dataField", false);
-
-  /// <summary>
-  /// If the field is a page field.
-  /// </summary>
-  public bool IsPageField {
-    get => (Axis == ePivotFieldAxis.Page);
-    internal set {
-      if (value) {
-        var dataFieldsNode = TopNode.SelectSingleNode("../../d:pageFields", NameSpaceManager);
-        if (dataFieldsNode == null) {
-          _table.CreateNode("d:pageFields");
-          dataFieldsNode = TopNode.SelectSingleNode("../../d:pageFields", NameSpaceManager);
-        }
-
-        TopNode.InnerXml = "<items count=\"1\"><item t=\"default\" /></items>";
-
-        XmlElement node = AppendField(dataFieldsNode, Index, "pageField", "fld");
-        _pageFieldSettings = new(NameSpaceManager, node, this, Index);
-      } else {
-        _pageFieldSettings = null;
-        XmlElement node =
-            TopNode.SelectSingleNode(
-                string.Format("../../d:pageFields/d:pageField[@fld={0}]", Index),
-                NameSpaceManager) as XmlElement;
-        if (node != null) {
-          node.ParentNode.RemoveChild(node);
-        }
-      }
-    }
-  }
-
-  //public ExcelPivotGrouping DateGrouping
-  //{
-
-  //}
-  internal ExcelPivotTablePageFieldSettings _pageFieldSettings;
-
-  public ExcelPivotTablePageFieldSettings PageFieldSettings => _pageFieldSettings;
-
-  internal eDateGroupBy DateGrouping { get; set; }
-
-  private ExcelPivotTableFieldGroup _grouping;
-
-  /// <summary>
-  /// Grouping settings.
-  /// Null if the field has no grouping otherwise ExcelPivotTableFieldNumericGroup or ExcelPivotTableFieldNumericGroup.
-  /// </summary>
-  public ExcelPivotTableFieldGroup Grouping => _grouping;
-
-  internal XmlElement AppendField(
-      XmlNode rowsNode,
-      int index,
-      string fieldNodeText,
-      string indexAttrText) {
-    XmlElement prevField = null,
-        newElement;
-    foreach (XmlElement field in rowsNode.ChildNodes) {
-      string x = field.GetAttribute(indexAttrText);
-      if (int.TryParse(x, out var fieldIndex)) {
-        if (fieldIndex
-            == index) //Row already exists
-        {
-          return field;
-        }
-        //else if (fieldIndex > index)
-        //{
-        //    newElement = rowsNode.OwnerDocument.CreateElement(fieldNodeText, ExcelPackage.schemaMain);
-        //    newElement.SetAttribute(indexAttrText, index.ToString());
-        //    rowsNode.InsertAfter(newElement, field);
-        //}
-      }
-      prevField = field;
-    }
-    newElement = rowsNode.OwnerDocument.CreateElement(fieldNodeText, ExcelPackage._schemaMain);
-    newElement.SetAttribute(indexAttrText, index.ToString());
-    rowsNode.InsertAfter(newElement, prevField);
-
-    return newElement;
-  }
-
-  internal XmlHelperInstance _cacheFieldHelper;
-
-  internal void SetCacheFieldNode(XmlNode cacheField) {
-    _cacheFieldHelper = new(NameSpaceManager, cacheField);
-    var groupNode = cacheField.SelectSingleNode("d:fieldGroup", NameSpaceManager);
-    if (groupNode != null) {
-      var groupBy = groupNode.SelectSingleNode("d:rangePr/@groupBy", NameSpaceManager);
-      if (groupBy == null) {
-        _grouping = new ExcelPivotTableFieldNumericGroup(NameSpaceManager, cacheField);
-      } else {
-        DateGrouping = (eDateGroupBy)Enum.Parse(typeof(eDateGroupBy), groupBy.Value, true);
-        _grouping = new ExcelPivotTableFieldDateGroup(NameSpaceManager, groupNode);
-      }
-    }
-  }
-
-  internal ExcelPivotTableFieldCollectionBase<ExcelPivotTableFieldItem> _items;
-
-  /// <summary>
-  /// Pivottable field Items. Used for grouping.
-  /// </summary>
-  public ExcelPivotTableFieldCollectionBase<ExcelPivotTableFieldItem> Items {
-    get {
-      if (_items == null) {
-        _items = new(_table);
-        foreach (XmlNode node in TopNode.SelectNodes("d:items//d:item", NameSpaceManager)) {
-          var item = new ExcelPivotTableFieldItem(NameSpaceManager, node, this);
-          if (item.T == "") {
-            _items.AddInternal(item);
-          }
-        }
-      }
-      return _items;
-    }
-  }
-}
diff --git a/EPPlus/Table/PivotTable/ExcelPivotTableFieldCollection.cs b/EPPlus/Table/PivotTable/ExcelPivotTableFieldCollection.cs
deleted file mode 100644
index 5f7053d..0000000
--- a/EPPlus/Table/PivotTable/ExcelPivotTableFieldCollection.cs
+++ /dev/null
@@ -1,302 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		Added		21-MAR-2011
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Xml;
-
-namespace OfficeOpenXml.Table.PivotTable;
-
-/// <summary>
-/// Base collection class for pivottable fields
-/// </summary>
-/// <typeparam name="T"></typeparam>
-public class ExcelPivotTableFieldCollectionBase<T> : IEnumerable<T> {
-  protected ExcelPivotTable _table;
-  internal List<T> _list = new();
-
-  internal ExcelPivotTableFieldCollectionBase(ExcelPivotTable table) {
-    _table = table;
-  }
-
-  public IEnumerator<T> GetEnumerator() {
-    return _list.GetEnumerator();
-  }
-
-  IEnumerator IEnumerable.GetEnumerator() {
-    return _list.GetEnumerator();
-  }
-
-  public int Count => _list.Count;
-
-  internal void AddInternal(T field) {
-    _list.Add(field);
-  }
-
-  internal void Clear() {
-    _list.Clear();
-  }
-
-  public T this[int index] {
-    get {
-      if (index < 0 || index >= _list.Count) {
-        throw (new ArgumentOutOfRangeException("Index out of range"));
-      }
-      return _list[index];
-    }
-  }
-}
-
-public class ExcelPivotTableFieldCollection
-    : ExcelPivotTableFieldCollectionBase<ExcelPivotTableField> {
-  internal ExcelPivotTableFieldCollection(ExcelPivotTable table, string topNode)
-      : base(table) {}
-
-  /// <summary>
-  /// Indexer by name
-  /// </summary>
-  /// <param name="name"></param>
-  /// <returns></returns>
-  public ExcelPivotTableField this[string name] {
-    get {
-      foreach (var field in _list) {
-        if (field.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)) {
-          return field;
-        }
-      }
-      return null;
-    }
-  }
-
-  /// <summary>
-  /// Returns the date group field.
-  /// </summary>
-  /// <param name="groupBy">The type of grouping</param>
-  /// <returns>The matching field. If none is found null is returned</returns>
-  public ExcelPivotTableField GetDateGroupField(eDateGroupBy groupBy) {
-    foreach (var fld in _list) {
-      if (fld.Grouping is ExcelPivotTableFieldDateGroup group && (group.GroupBy) == groupBy) {
-        return fld;
-      }
-    }
-    return null;
-  }
-
-  /// <summary>
-  /// Returns the numeric group field.
-  /// </summary>
-  /// <returns>The matching field. If none is found null is returned</returns>
-  public ExcelPivotTableField GetNumericGroupField() {
-    foreach (var fld in _list) {
-      if (fld.Grouping is ExcelPivotTableFieldNumericGroup) {
-        return fld;
-      }
-    }
-    return null;
-  }
-}
-
-/// <summary>
-/// Collection class for Row and column fields in a Pivottable
-/// </summary>
-public class ExcelPivotTableRowColumnFieldCollection
-    : ExcelPivotTableFieldCollectionBase<ExcelPivotTableField> {
-  internal string _topNode;
-
-  internal ExcelPivotTableRowColumnFieldCollection(ExcelPivotTable table, string topNode)
-      : base(table) {
-    _topNode = topNode;
-  }
-
-  /// <summary>
-  /// Add a new row/column field
-  /// </summary>
-  /// <param name="field">The field</param>
-  /// <returns>The new field</returns>
-  public ExcelPivotTableField Add(ExcelPivotTableField field) {
-    SetFlag(field, true);
-    _list.Add(field);
-    return field;
-  }
-
-  /// <summary>
-  /// Insert a new row/column field
-  /// </summary>
-  /// <param name="field">The field</param>
-  /// <param name="index">The position to insert the field</param>
-  /// <returns>The new field</returns>
-  internal ExcelPivotTableField Insert(ExcelPivotTableField field, int index) {
-    SetFlag(field, true);
-    _list.Insert(index, field);
-    return field;
-  }
-
-  private void SetFlag(ExcelPivotTableField field, bool value) {
-    switch (_topNode) {
-      case "rowFields":
-        if (field.IsColumnField || field.IsPageField) {
-          throw (new(
-                  "This field is a column or page field. Can't add it to the RowFields collection"));
-        }
-        field.IsRowField = value;
-        field.Axis = ePivotFieldAxis.Row;
-        break;
-      case "colFields":
-        if (field.IsRowField || field.IsPageField) {
-          throw (new(
-                  "This field is a row or page field. Can't add it to the ColumnFields collection"));
-        }
-        field.IsColumnField = value;
-        field.Axis = ePivotFieldAxis.Column;
-        break;
-      case "pageFields":
-        if (field.IsColumnField || field.IsRowField) {
-          throw (new("Field is a column or row field. Can't add it to the PageFields collection"));
-        }
-        if (_table.Address._fromRow < 3) {
-          throw (new(
-                  string.Format(
-                      "A pivot table with page fields must be located above row 3. Currenct location is {0}",
-                      _table.Address.Address)));
-        }
-        field.IsPageField = value;
-        field.Axis = ePivotFieldAxis.Page;
-        break;
-      case "dataFields":
-
-        break;
-    }
-  }
-
-  /// <summary>
-  /// Remove a field
-  /// </summary>
-  /// <param name="field"></param>
-  public void Remove(ExcelPivotTableField field) {
-    if (!_list.Contains(field)) {
-      throw new ArgumentException("Field not in collection");
-    }
-    SetFlag(field, false);
-    _list.Remove(field);
-  }
-
-  /// <summary>
-  /// Remove a field at a specific position
-  /// </summary>
-  /// <param name="index"></param>
-  public void RemoveAt(int index) {
-    if (index > -1 && index < _list.Count) {
-      throw (new IndexOutOfRangeException());
-    }
-    SetFlag(_list[index], false);
-    _list.RemoveAt(index);
-  }
-}
-
-/// <summary>
-/// Collection class for data fields in a Pivottable
-/// </summary>
-public class ExcelPivotTableDataFieldCollection
-    : ExcelPivotTableFieldCollectionBase<ExcelPivotTableDataField> {
-  internal ExcelPivotTableDataFieldCollection(ExcelPivotTable table)
-      : base(table) {}
-
-  /// <summary>
-  /// Add a new datafield
-  /// </summary>
-  /// <param name="field">The field</param>
-  /// <returns>The new datafield</returns>
-  public ExcelPivotTableDataField Add(ExcelPivotTableField field) {
-    var dataFieldsNode = field.TopNode.SelectSingleNode(
-        "../../d:dataFields",
-        field.NameSpaceManager);
-    if (dataFieldsNode == null) {
-      _table.CreateNode("d:dataFields");
-      dataFieldsNode = field.TopNode.SelectSingleNode("../../d:dataFields", field.NameSpaceManager);
-    }
-
-    XmlElement node = _table.PivotTableXml.CreateElement("dataField", ExcelPackage._schemaMain);
-    node.SetAttribute("fld", field.Index.ToString());
-    dataFieldsNode.AppendChild(node);
-
-    //XmlElement node = field.AppendField(dataFieldsNode, field.Index, "dataField", "fld");
-    field.SetXmlNodeBool("@dataField", true, false);
-
-    var dataField = new ExcelPivotTableDataField(field.NameSpaceManager, node, field);
-    ValidateDupName(dataField);
-
-    _list.Add(dataField);
-    return dataField;
-  }
-
-  private void ValidateDupName(ExcelPivotTableDataField dataField) {
-    if (ExistsDfName(dataField.Field.Name, null)) {
-      var index = 2;
-      string name;
-      do {
-        name = dataField.Field.Name + "_" + index++;
-      } while (ExistsDfName(name, null));
-      dataField.Name = name;
-    }
-  }
-
-  internal bool ExistsDfName(string name, ExcelPivotTableDataField datafield) {
-    foreach (var df in _list) {
-      if (((!string.IsNullOrEmpty(df.Name)
-                      && df.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)
-                      || (string.IsNullOrEmpty(df.Name)
-                              && df.Field.Name.Equals(
-                                  name,
-                                  StringComparison.InvariantCultureIgnoreCase))))
-          && datafield != df) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  /// <summary>
-  /// Remove a datafield
-  /// </summary>
-  /// <param name="dataField"></param>
-  public void Remove(ExcelPivotTableDataField dataField) {
-    XmlElement node =
-        dataField.Field.TopNode.SelectSingleNode(
-            string.Format("../../d:dataFields/d:dataField[@fld={0}]", dataField.Index),
-            dataField.NameSpaceManager) as XmlElement;
-    if (node != null) {
-      node.ParentNode.RemoveChild(node);
-    }
-    _list.Remove(dataField);
-  }
-}
diff --git a/EPPlus/Table/PivotTable/ExcelPivotTableFieldGroup.cs b/EPPlus/Table/PivotTable/ExcelPivotTableFieldGroup.cs
deleted file mode 100644
index 99fbd3c..0000000
--- a/EPPlus/Table/PivotTable/ExcelPivotTableFieldGroup.cs
+++ /dev/null
@@ -1,109 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		Added		21-MAR-2011
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System;
-using System.Globalization;
-using System.Xml;
-
-namespace OfficeOpenXml.Table.PivotTable;
-
-/// <summary>
-/// Base class for pivot table field groups
-/// </summary>
-public class ExcelPivotTableFieldGroup : XmlHelper {
-  internal ExcelPivotTableFieldGroup(XmlNamespaceManager ns, XmlNode topNode)
-      : base(ns, topNode) {}
-}
-
-/// <summary>
-/// A date group
-/// </summary>
-public class ExcelPivotTableFieldDateGroup : ExcelPivotTableFieldGroup {
-  internal ExcelPivotTableFieldDateGroup(XmlNamespaceManager ns, XmlNode topNode)
-      : base(ns, topNode) {}
-
-  private const string _groupByPath = "d:fieldGroup/d:rangePr/@groupBy";
-
-  /// <summary>
-  /// How to group the date field
-  /// </summary>
-  public eDateGroupBy GroupBy {
-    get {
-      string v = GetXmlNodeString(_groupByPath);
-      if (v != "") {
-        return (eDateGroupBy)Enum.Parse(typeof(eDateGroupBy), v, true);
-      }
-      throw (new("Invalid date Groupby"));
-    }
-    private set =>
-      SetXmlNodeString(_groupByPath, value.ToString().ToLower(CultureInfo.InvariantCulture));
-  }
-
-  /// <summary>
-  /// Auto detect start date
-  /// </summary>
-  public bool AutoStart => GetXmlNodeBool("@autoStart", false);
-
-  /// <summary>
-  /// Auto detect end date
-  /// </summary>
-  public bool AutoEnd => GetXmlNodeBool("@autoStart", false);
-}
-
-/// <summary>
-/// A pivot table field numeric grouping
-/// </summary>
-public class ExcelPivotTableFieldNumericGroup : ExcelPivotTableFieldGroup {
-  internal ExcelPivotTableFieldNumericGroup(XmlNamespaceManager ns, XmlNode topNode)
-      : base(ns, topNode) {}
-
-  private const string _startPath = "d:fieldGroup/d:rangePr/@startNum";
-
-  /// <summary>
-  /// Start value
-  /// </summary>
-  public double Start => (double)GetXmlNodeDoubleNull(_startPath);
-
-  private const string _endPath = "d:fieldGroup/d:rangePr/@endNum";
-
-  /// <summary>
-  /// End value
-  /// </summary>
-  public double End => (double)GetXmlNodeDoubleNull(_endPath);
-
-  private const string _groupIntervalPath = "d:fieldGroup/d:rangePr/@groupInterval";
-
-  /// <summary>
-  /// Interval
-  /// </summary>
-  public double Interval => (double)GetXmlNodeDoubleNull(_groupIntervalPath);
-}
diff --git a/EPPlus/Table/PivotTable/ExcelPivotTableFieldItem.cs b/EPPlus/Table/PivotTable/ExcelPivotTableFieldItem.cs
deleted file mode 100644
index b300b73..0000000
--- a/EPPlus/Table/PivotTable/ExcelPivotTableFieldItem.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		Added		21-MAR-2011
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System;
-using System.Xml;
-
-namespace OfficeOpenXml.Table.PivotTable;
-
-/// <summary>
-/// A field Item. Used for grouping
-/// </summary>
-public class ExcelPivotTableFieldItem : XmlHelper {
-  private readonly ExcelPivotTableField _field;
-
-  internal ExcelPivotTableFieldItem(
-      XmlNamespaceManager ns,
-      XmlNode topNode,
-      ExcelPivotTableField field)
-      : base(ns, topNode) {
-    _field = field;
-  }
-
-  /// <summary>
-  /// The text. Unique values only
-  /// </summary>
-  public string Text {
-    get => GetXmlNodeString("@n");
-    set {
-      if (string.IsNullOrEmpty(value)) {
-        DeleteNode("@n");
-        return;
-      }
-      foreach (var item in _field.Items) {
-        if (item.Text == value) {
-          throw (new ArgumentException("Duplicate Text"));
-        }
-      }
-      SetXmlNodeString("@n", value);
-    }
-  }
-
-  internal int X => GetXmlNodeInt("@x");
-
-  internal string T => GetXmlNodeString("@t");
-}
diff --git a/EPPlus/Table/PivotTable/ExcelPivotTablePageFieldSettings.cs b/EPPlus/Table/PivotTable/ExcelPivotTablePageFieldSettings.cs
deleted file mode 100644
index fe6f762..0000000
--- a/EPPlus/Table/PivotTable/ExcelPivotTablePageFieldSettings.cs
+++ /dev/null
@@ -1,93 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		Added		21-MAR-2011
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System.Xml;
-
-namespace OfficeOpenXml.Table.PivotTable;
-
-/// <summary>
-/// A page / report filter field
-/// </summary>
-public class ExcelPivotTablePageFieldSettings : XmlHelper {
-  private ExcelPivotTableField _field;
-
-  internal ExcelPivotTablePageFieldSettings(
-      XmlNamespaceManager ns,
-      XmlNode topNode,
-      ExcelPivotTableField field,
-      int index)
-      : base(ns, topNode) {
-    if (GetXmlNodeString("@hier") == "") {
-      Hier = -1;
-    }
-    _field = field;
-  }
-
-  internal int Index {
-    get => GetXmlNodeInt("@fld");
-    set => SetXmlNodeString("@fld", value.ToString());
-  }
-
-  /// <summary>
-  /// The Name of the field
-  /// </summary>
-  public string Name {
-    get => GetXmlNodeString("@name");
-    set => SetXmlNodeString("@name", value);
-  }
-
-  /***** Dont work. Need items to be populated. ****/
-  ///// <summary>
-  ///// The selected item
-  ///// </summary>
-  //public int SelectedItem
-  //{
-  //    get
-  //    {
-  //        return GetXmlNodeInt("@item");
-  //    }
-  //    set
-  //    {
-  //        if (value < 0) throw new InvalidOperationException("Can't be negative");
-  //        SetXmlNodeString("@item", value.ToString());
-  //    }
-  //}
-  internal int NumFmtId {
-    get => GetXmlNodeInt("@numFmtId");
-    set => SetXmlNodeString("@numFmtId", value.ToString());
-  }
-
-  internal int Hier {
-    get => GetXmlNodeInt("@hier");
-    set => SetXmlNodeString("@hier", value.ToString());
-  }
-}
diff --git a/EPPlus/Utils/AddressUtility.cs b/EPPlus/Utils/AddressUtility.cs
deleted file mode 100644
index 05fadd1..0000000
--- a/EPPlus/Utils/AddressUtility.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System.Text.RegularExpressions;
-
-namespace OfficeOpenXml.Utils;
-
-public static class AddressUtility {
-  public static string ParseEntireColumnSelections(string address) {
-    string parsedAddress = address;
-    var matches = Regex.Matches(address, "[A-Z]+:[A-Z]+");
-    foreach (Match match in matches) {
-      AddRowNumbersToEntireColumnRange(ref parsedAddress, match.Value);
-    }
-    return parsedAddress;
-  }
-
-  private static void AddRowNumbersToEntireColumnRange(ref string address, string range) {
-    var parsedRange = string.Format("{0}{1}", range, ExcelPackage.MaxRows);
-    var splitArr = parsedRange.Split(new[] { ':' });
-    address = address.Replace(range, string.Format("{0}1:{1}", splitArr[0], splitArr[1]));
-  }
-}
diff --git a/EPPlus/Utils/Argument.cs b/EPPlus/Utils/Argument.cs
deleted file mode 100644
index 8519db1..0000000
--- a/EPPlus/Utils/Argument.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-01
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-namespace OfficeOpenXml.Utils;
-
-internal class Argument<T> : IArgument<T> {
-  public Argument(T value) {
-    _value = value;
-  }
-
-  private readonly T _value;
-
-  T IArgument<T>.Value => _value;
-}
diff --git a/EPPlus/Utils/ArgumentExtensions.cs b/EPPlus/Utils/ArgumentExtensions.cs
deleted file mode 100644
index 6bba854..0000000
--- a/EPPlus/Utils/ArgumentExtensions.cs
+++ /dev/null
@@ -1,83 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-01
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using System;
-
-namespace OfficeOpenXml.Utils;
-
-/// <summary>
-/// Extension methods for guarding
-/// </summary>
-public static class ArgumentExtensions {
-  /// <summary>
-  /// Throws an ArgumentNullException if argument is null
-  /// </summary>
-  /// <typeparam name="T">Argument type</typeparam>
-  /// <param name="argument">Argument to check</param>
-  /// <param name="argumentName">parameter/argument name</param>
-  /// <exception cref="ArgumentNullException"></exception>
-  public static void IsNotNull<T>(this IArgument<T> argument, string argumentName)
-      where T : class {
-    argumentName = string.IsNullOrEmpty(argumentName) ? "value" : argumentName;
-    if (argument.Value == null) {
-      throw new ArgumentNullException(argumentName);
-    }
-  }
-
-  /// <summary>
-  /// Throws an <see cref="ArgumentNullException"/> if the string argument is null or empty
-  /// </summary>
-  /// <param name="argument">Argument to check</param>
-  /// <param name="argumentName">parameter/argument name</param>
-  /// <exception cref="ArgumentNullException"></exception>
-  public static void IsNotNullOrEmpty(this IArgument<string> argument, string argumentName) {
-    if (string.IsNullOrEmpty(argument.Value)) {
-      throw new ArgumentNullException(argumentName);
-    }
-  }
-
-  /// <summary>
-  /// Throws an ArgumentOutOfRangeException if the value of the argument is out of the supplied range
-  /// </summary>
-  /// <typeparam name="T">Type implementing <see cref="IComparable"/></typeparam>
-  /// <param name="argument">The argument to check</param>
-  /// <param name="min">Min value of the supplied range</param>
-  /// <param name="max">Max value of the supplied range</param>
-  /// <param name="argumentName">parameter/argument name</param>
-  /// <exception cref="ArgumentOutOfRangeException"></exception>
-  public static void IsInRange<T>(this IArgument<T> argument, T min, T max, string argumentName)
-      where T : IComparable {
-    if (!(argument.Value.CompareTo(min) >= 0 && argument.Value.CompareTo(max) <= 0)) {
-      throw new ArgumentOutOfRangeException(argumentName);
-    }
-  }
-}
diff --git a/EPPlus/Utils/ConvertUtil.cs b/EPPlus/Utils/ConvertUtil.cs
deleted file mode 100644
index 2802caa..0000000
--- a/EPPlus/Utils/ConvertUtil.cs
+++ /dev/null
@@ -1,171 +0,0 @@
-using System;
-using System.Globalization;
-using System.IO;
-using System.Text;
-using System.Text.RegularExpressions;
-
-namespace OfficeOpenXml.Utils;
-
-internal static class ConvertUtil {
-  internal static bool IsNumeric(object candidate) {
-    if (candidate == null) {
-      return false;
-    }
-    return (candidate.GetType().IsPrimitive
-            || candidate is double
-            || candidate is decimal
-            || candidate is DateTime
-            || candidate is TimeSpan
-            || candidate is long);
-  }
-
-  internal static bool IsNumericString(object candidate) {
-    if (candidate != null) {
-      return Regex.IsMatch(candidate.ToString(), @"^[\d]+(\,[\d])?");
-    }
-    return false;
-  }
-
-  /// <summary>
-  /// Convert an object value to a double
-  /// </summary>
-  /// <param name="v"></param>
-  /// <param name="ignoreBool"></param>
-  /// <returns></returns>
-  internal static double GetValueDouble(object v, bool ignoreBool = false) {
-    double d;
-    try {
-      if (ignoreBool && v is bool) {
-        return 0;
-      }
-      if (IsNumeric(v)) {
-        if (v is DateTime time) {
-          d = time.ToOADate();
-        } else if (v is TimeSpan span) {
-          d = DateTime.FromOADate(0).Add(span).ToOADate();
-        } else {
-          d = Convert.ToDouble(v, CultureInfo.InvariantCulture);
-        }
-      } else {
-        d = 0;
-      }
-    } catch {
-      d = 0;
-    }
-    return d;
-  }
-
-  /// <summary>
-  /// OOXML requires that "," , and &amp; be escaped, but ' and " should *not* be escaped, nor should
-  /// any extended Unicode characters. This function only encodes the required characters.
-  /// System.Security.SecurityElement.Escape() escapes ' and " as  &apos; and &quot;, so it cannot
-  /// be used reliably. System.Web.HttpUtility.HtmlEncode overreaches as well and uses the numeric
-  /// escape equivalent.
-  /// </summary>
-  /// <param name="s"></param>
-  /// <returns></returns>
-  internal static string ExcelEscapeString(string s) {
-    return s.Replace("&", "&amp;").Replace("<", "&lt;").Replace(">", "&gt;");
-  }
-
-  /// <summary>
-  /// Return true if preserve space attribute is set.
-  /// </summary>
-  /// <param name="sw"></param>
-  /// <param name="t"></param>
-  /// <returns></returns>
-  internal static void ExcelEncodeString(StreamWriter sw, string t) {
-    if (Regex.IsMatch(t, "(_x[0-9A-F]{4,4}_)")) {
-      var match = Regex.Match(t, "(_x[0-9A-F]{4,4}_)");
-      int indexAdd = 0;
-      while (match.Success) {
-        t = t.Insert(match.Index + indexAdd, "_x005F");
-        indexAdd += 6;
-        match = match.NextMatch();
-      }
-    }
-    for (int i = 0; i < t.Length; i++) {
-      if (t[i] <= 0x1f
-          && t[i] != '\t'
-          && t[i] != '\n'
-          && t[i]
-              != '\r') //Not Tab, CR or LF
-      {
-        sw.Write("_x00{0}_", (t[i] < 0xf ? "0" : "") + ((int)t[i]).ToString("X"));
-      } else {
-        sw.Write(t[i]);
-      }
-    }
-  }
-
-  /// <summary>
-  /// Return true if preserve space attribute is set.
-  /// </summary>
-  /// <param name="sb"></param>
-  /// <param name="t"></param>
-  /// <returns></returns>
-  internal static void ExcelEncodeString(StringBuilder sb, string t, bool encodeTabCrlf = false) {
-    if (Regex.IsMatch(t, "(_x[0-9A-F]{4,4}_)")) {
-      var match = Regex.Match(t, "(_x[0-9A-F]{4,4}_)");
-      int indexAdd = 0;
-      while (match.Success) {
-        t = t.Insert(match.Index + indexAdd, "_x005F");
-        indexAdd += 6;
-        match = match.NextMatch();
-      }
-    }
-    for (int i = 0; i < t.Length; i++) {
-      if (t[i] <= 0x1f
-          && ((t[i] != '\t' && t[i] != '\n' && t[i] != '\r' && encodeTabCrlf == false)
-                  || encodeTabCrlf)) //Not Tab, CR or LF
-      {
-        sb.AppendFormat("_x00{0}_", (t[i] < 0xf ? "0" : "") + ((int)t[i]).ToString("X"));
-      } else {
-        sb.Append(t[i]);
-      }
-    }
-  }
-
-  /// <summary>
-  /// Return true if preserve space attribute is set.
-  /// </summary>
-  /// <param name="sb"></param>
-  /// <param name="t"></param>
-  /// <returns></returns>
-  internal static string ExcelEncodeString(string t) {
-    StringBuilder sb = new StringBuilder();
-    t = t.Replace("\r\n", "\n"); //For some reason can't table name have cr in them. Replace with nl
-    ExcelEncodeString(sb, t, true);
-    return sb.ToString();
-  }
-
-  internal static string ExcelDecodeString(string t) {
-    var match = Regex.Match(t, "(_x005F|_x[0-9A-F]{4,4}_)");
-    if (!match.Success) {
-      return t;
-    }
-
-    var useNextValue = false;
-    var ret = new StringBuilder();
-    var prevIndex = 0;
-    while (match.Success) {
-      if (prevIndex < match.Index) {
-        ret.Append(t.Substring(prevIndex, match.Index - prevIndex));
-      }
-      if (!useNextValue && match.Value == "_x005F") {
-        useNextValue = true;
-      } else {
-        if (useNextValue) {
-          ret.Append(match.Value);
-          useNextValue = false;
-        } else {
-          ret.Append((char)int.Parse(match.Value.Substring(2, 4), NumberStyles.AllowHexSpecifier));
-        }
-      }
-      prevIndex = match.Index + match.Length;
-      match = match.NextMatch();
-    }
-    ret.Append(t.Substring(prevIndex, t.Length - prevIndex));
-    return ret.ToString();
-  }
-}
diff --git a/EPPlus/Utils/IArgument.cs b/EPPlus/Utils/IArgument.cs
deleted file mode 100644
index 8c4f614..0000000
--- a/EPPlus/Utils/IArgument.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-01
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-namespace OfficeOpenXml.Utils;
-
-/// <summary>
-/// An argument
-/// </summary>
-/// <typeparam name="T">Argument Type</typeparam>
-public interface IArgument<T> {
-  T Value { get; }
-}
diff --git a/EPPlus/Utils/IExcelCell.cs b/EPPlus/Utils/IExcelCell.cs
deleted file mode 100644
index b1087c3..0000000
--- a/EPPlus/Utils/IExcelCell.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Jan Källman		                Initial Release		        2009-10-01
- * Jan Källman		License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System;
-
-namespace OfficeOpenXml.Style;
-
-internal interface IExcelCell {
-  object Value { get; set; }
-
-  string StyleName { get; }
-
-  int StyleID { get; set; }
-
-  ExcelStyle Style { get; }
-
-  Uri Hyperlink { get; set; }
-
-  string Formula { get; set; }
-
-  string FormulaR1C1 { get; set; }
-}
diff --git a/EPPlus/Utils/IValidationResult.cs b/EPPlus/Utils/IValidationResult.cs
deleted file mode 100644
index 61ef1c1..0000000
--- a/EPPlus/Utils/IValidationResult.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace OfficeOpenXml.Utils;
-
-public interface IValidationResult {
-  void IsTrue();
-
-  void IsFalse();
-}
diff --git a/EPPlus/Utils/Require.cs b/EPPlus/Utils/Require.cs
deleted file mode 100644
index 17b98d8..0000000
--- a/EPPlus/Utils/Require.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm   		                Added       		        2011-01-01
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-namespace OfficeOpenXml.Utils;
-
-/// <summary>
-/// Utility for validation
-/// </summary>
-public static class Require {
-  public static IArgument<T> Argument<T>(T argument) {
-    return new Argument<T>(argument);
-  }
-}
diff --git a/EPPlus/Utils/SqRefUtility.cs b/EPPlus/Utils/SqRefUtility.cs
deleted file mode 100644
index 5115bd3..0000000
--- a/EPPlus/Utils/SqRefUtility.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using System.Text.RegularExpressions;
-
-namespace OfficeOpenXml.Utils;
-
-/// <summary>
-/// Class for handling translation between ExcelAddresses and sqref addresses.
-/// </summary>
-public static class SqRefUtility {
-  /// <summary>
-  /// Transforms an address to a valid sqRef address.
-  /// </summary>
-  /// <param name="address">The address to transform</param>
-  /// <returns>A valid SqRef address</returns>
-  public static string ToSqRefAddress(string address) {
-    Require.Argument(address).IsNotNullOrEmpty(address);
-    address = address.Replace(",", " ");
-    address = new Regex("[ ]+").Replace(address, " ");
-    return address;
-  }
-
-  /// <summary>
-  /// Transforms an sqRef address into a excel address
-  /// </summary>
-  /// <param name="address">The address to transform</param>
-  /// <returns>A valid excel address</returns>
-  public static string FromSqRefAddress(string address) {
-    Require.Argument(address).IsNotNullOrEmpty(address);
-    address = address.Replace(" ", ",");
-    return address;
-  }
-}
diff --git a/EPPlus/Utils/UriHelper.cs b/EPPlus/Utils/UriHelper.cs
deleted file mode 100644
index 8f9c04b..0000000
--- a/EPPlus/Utils/UriHelper.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-using System;
-
-namespace OfficeOpenXml.Utils;
-
-internal class UriHelper {
-  internal static Uri ResolvePartUri(Uri sourceUri, Uri targetUri) {
-    if (targetUri.OriginalString.StartsWith("/")) {
-      return targetUri;
-    }
-    string[] source = sourceUri.OriginalString.Split('/');
-    string[] target = targetUri.OriginalString.Split('/');
-
-    int t = target.Length - 1;
-    int s;
-    if (sourceUri.OriginalString.EndsWith(
-        "/")) //is the source a directory?
-    {
-      s = source.Length - 1;
-    } else {
-      s = source.Length - 2;
-    }
-
-    string file = target[t--];
-
-    while (t >= 0) {
-      if (target[t] == ".") {
-        break;
-      }
-      if (target[t] == "..") {
-        s--;
-        t--;
-      } else {
-        file = target[t--] + "/" + file;
-      }
-    }
-    if (s >= 0) {
-      for (int i = s; i >= 0; i--) {
-        file = source[i] + "/" + file;
-      }
-    }
-    return new(file, UriKind.RelativeOrAbsolute);
-  }
-
-  internal static Uri GetRelativeUri(Uri worksheetUri, Uri uri) {
-    string[] source = worksheetUri.OriginalString.Split('/');
-    string[] target = uri.OriginalString.Split('/');
-
-    int slen;
-    if (worksheetUri.OriginalString.EndsWith("/")) {
-      slen = source.Length;
-    } else {
-      slen = source.Length - 1;
-    }
-    int i = 0;
-    while (i < slen && i < target.Length && source[i] == target[i]) {
-      i++;
-    }
-
-    string dirUp = "";
-    for (int s = i; s < slen; s++) {
-      dirUp += "../";
-    }
-    string file = "";
-    for (int t = i; t < target.Length; t++) {
-      file += (file == "" ? "" : "/") + target[t];
-    }
-    return new(dirUp + file, UriKind.Relative);
-  }
-}
diff --git a/EPPlus/Utils/ValidationResult.cs b/EPPlus/Utils/ValidationResult.cs
deleted file mode 100644
index 9985fa5..0000000
--- a/EPPlus/Utils/ValidationResult.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using System;
-
-namespace OfficeOpenXml.Utils;
-
-public class ValidationResult : IValidationResult {
-  public ValidationResult(bool result)
-      : this(result, null) {}
-
-  public ValidationResult(bool result, string errorMessage) {
-    _result = result;
-    _errorMessage = errorMessage;
-  }
-
-  private readonly bool _result;
-  private readonly string _errorMessage;
-
-  private void Throw() {
-    if (string.IsNullOrEmpty(_errorMessage)) {
-      throw new InvalidOperationException();
-    }
-    throw new InvalidOperationException(_errorMessage);
-  }
-
-  void IValidationResult.IsTrue() {
-    if (!_result) {
-      Throw();
-    }
-  }
-
-  void IValidationResult.IsFalse() {
-    if (_result) {
-      Throw();
-    }
-  }
-}
diff --git a/EPPlus/XmlHelper.cs b/EPPlus/XmlHelper.cs
deleted file mode 100644
index b311997..0000000
--- a/EPPlus/XmlHelper.cs
+++ /dev/null
@@ -1,628 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						         Date
- * ******************************************************************************
- * Jan Källman		    Initial Release		         2009-10-01
- * Jan Källman		    License changed GPL-->LGPL 2011-12-27
- * Eyal Seagull       Add "CreateComplexNode"    2012-04-03
- * Eyal Seagull       Add "DeleteTopNode"        2012-04-13
- *******************************************************************************/
-
-using System;
-using System.Collections.Immutable;
-using System.Globalization;
-using System.IO;
-using System.Text;
-using System.Xml;
-using OfficeOpenXml.Style;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// Help class containing XML functions.
-/// Can be Inherited
-/// </summary>
-public abstract class XmlHelper {
-  internal delegate int ChangedEventHandler(StyleBase sender, StyleChangeEventArgs e);
-
-  internal XmlHelper(XmlNamespaceManager nameSpaceManager) {
-    TopNode = null;
-    NameSpaceManager = nameSpaceManager;
-  }
-
-  internal XmlHelper(XmlNamespaceManager nameSpaceManager, XmlNode topNode) {
-    TopNode = topNode;
-    NameSpaceManager = nameSpaceManager;
-  }
-
-  //internal bool ChangedFlag;
-  internal XmlNamespaceManager NameSpaceManager { get; set; }
-
-  internal XmlNode TopNode { get; set; }
-
-  /// <summary>
-  /// Schema order list
-  /// </summary>
-  protected virtual ImmutableArray<string> SchemaNodeOrder => ImmutableArray<string>.Empty;
-
-  internal XmlNode CreateNode(string path) {
-    if (path == "") {
-      return TopNode;
-    }
-    return CreateNode(path, false);
-  }
-
-  internal XmlNode CreateNode(string path, bool insertFirst) {
-    XmlNode node = TopNode;
-    XmlNode prependNode = null;
-    foreach (string subPath in path.Split('/')) {
-      XmlNode subNode = node.SelectSingleNode(subPath, NameSpaceManager);
-      if (subNode == null) {
-        string nodeName;
-        string nodePrefix;
-
-        string nameSpaceUri;
-        string[] nameSplit = subPath.Split(':');
-
-        if (SchemaNodeOrder.Length > 0 && subPath[0] != '@') {
-          insertFirst = false;
-          prependNode = GetPrependNode(subPath, node);
-        }
-
-        if (nameSplit.Length > 1) {
-          nodePrefix = nameSplit[0];
-          if (nodePrefix[0] == '@') {
-            nodePrefix = nodePrefix.Substring(1, nodePrefix.Length - 1);
-          }
-          nameSpaceUri = NameSpaceManager.LookupNamespace(nodePrefix);
-          nodeName = nameSplit[1];
-        } else {
-          nodePrefix = "";
-          nameSpaceUri = "";
-          nodeName = nameSplit[0];
-        }
-        if (subPath.StartsWith("@")) {
-          XmlAttribute addedAtt = node.OwnerDocument.CreateAttribute(
-              subPath.Substring(1, subPath.Length - 1),
-              nameSpaceUri); //nameSpaceURI
-          node.Attributes.Append(addedAtt);
-        } else {
-          if (nodePrefix == "") {
-            subNode = node.OwnerDocument.CreateElement(nodeName, nameSpaceUri);
-          } else {
-            if (nodePrefix == ""
-                || (node.OwnerDocument != null
-                        && node.OwnerDocument.DocumentElement != null
-                        && node.OwnerDocument.DocumentElement.NamespaceURI == nameSpaceUri
-                        && node.OwnerDocument.DocumentElement.Prefix == "")) {
-              subNode = node.OwnerDocument.CreateElement(nodeName, nameSpaceUri);
-            } else {
-              subNode = node.OwnerDocument.CreateElement(nodePrefix, nodeName, nameSpaceUri);
-            }
-          }
-          if (prependNode != null) {
-            node.InsertBefore(subNode, prependNode);
-            prependNode = null;
-          } else if (insertFirst) {
-            node.PrependChild(subNode);
-          } else {
-            node.AppendChild(subNode);
-          }
-        }
-      }
-      node = subNode;
-    }
-    return node;
-  }
-
-  /// <summary>
-  /// Options to insert a node in the XmlDocument
-  /// </summary>
-  internal enum eNodeInsertOrder {
-    /// <summary>
-    /// Insert as first node of "topNode"
-    /// </summary>
-    First,
-
-    /// <summary>
-    /// Insert as the last child of "topNode"
-    /// </summary>
-    Last,
-
-    /// <summary>
-    /// Insert after the "referenceNode"
-    /// </summary>
-    After,
-
-    /// <summary>
-    /// Insert before the "referenceNode"
-    /// </summary>
-    Before,
-
-    /// <summary>
-    /// Use the Schema List to insert in the right order. If the Schema list
-    /// is null or empty, consider "Last" as the selected option
-    /// </summary>
-    SchemaOrder,
-  }
-
-  /// <summary>
-  /// Create a complex node. Insert the node according to the <paramref name="path"/>
-  /// using the <paramref name="topNode"/> as the parent
-  /// </summary>
-  /// <param name="topNode"></param>
-  /// <param name="path"></param>
-  /// <returns></returns>
-  internal XmlNode CreateComplexNode(XmlNode topNode, string path) {
-    return CreateComplexNode(topNode, path, eNodeInsertOrder.SchemaOrder, null);
-  }
-
-  /// <summary>
-  /// Creates complex XML nodes
-  /// </summary>
-  /// <remarks>
-  /// 1. "d:conditionalFormatting"
-  ///		1.1. Creates/find the first "conditionalFormatting" node
-  ///
-  /// 2. "d:conditionalFormatting/@sqref"
-  ///		2.1. Creates/find the first "conditionalFormatting" node
-  ///		2.2. Creates (if not exists) the @sqref attribute
-  ///
-  /// 3. "d:conditionalFormatting/@id='7'/@sqref='A9:B99'"
-  ///		3.1. Creates/find the first "conditionalFormatting" node
-  ///		3.2. Creates/update its @id attribute to "7"
-  ///		3.3. Creates/update its @sqref attribute to "A9:B99"
-  ///
-  /// 4. "d:conditionalFormatting[@id='7']/@sqref='X1:X5'"
-  ///		4.1. Creates/find the first "conditionalFormatting" node with @id=7
-  ///		4.2. Creates/update its @sqref attribute to "X1:X5"
-  ///
-  /// 5. "d:conditionalFormatting[@id='7']/@id='8'/@sqref='X1:X5'/d:cfRule/@id='AB'"
-  ///		5.1. Creates/find the first "conditionalFormatting" node with @id=7
-  ///		5.2. Set its @id attribute to "8"
-  ///		5.2. Creates/update its @sqref attribute and set it to "X1:X5"
-  ///		5.3. Creates/find the first "cfRule" node (inside the node)
-  ///		5.4. Creates/update its @id attribute to "AB"
-  ///
-  /// 6. "d:cfRule/@id=''"
-  ///		6.1. Creates/find the first "cfRule" node
-  ///		6.1. Remove the @id attribute
-  ///	</remarks>
-  /// <param name="topNode"></param>
-  /// <param name="path"></param>
-  /// <param name="nodeInsertOrder"></param>
-  /// <param name="referenceNode"></param>
-  /// <returns>The last node creates/found</returns>
-  internal XmlNode CreateComplexNode(
-      XmlNode topNode,
-      string path,
-      eNodeInsertOrder nodeInsertOrder,
-      XmlNode referenceNode) {
-    // Path is obrigatory
-    if ((path == null) || (path == string.Empty)) {
-      return topNode;
-    }
-
-    XmlNode node = topNode;
-
-    //TODO: BUG: when the "path" contains "/" in an attrribue value, it gives an error.
-
-    // Separate the XPath to Nodes and Attributes
-    foreach (string subPath in path.Split('/')) {
-      // The subPath can be any one of those:
-      // nodeName
-      // x:nodeName
-      // nodeName[find criteria]
-      // x:nodeName[find criteria]
-      // @attribute
-      // @attribute='attribute value'
-
-      // Check if the subPath has at least one character
-      if (subPath.Length > 0) {
-        // Check if the subPath is an attribute (with or without value)
-        if (subPath.StartsWith("@")) {
-          // @attribute										--> Create attribute
-          // @attribute=''								--> Remove attribute
-          // @attribute='attribute value' --> Create attribute + update value
-          string[] attributeSplit = subPath.Split('=');
-          string attributeName = attributeSplit[0].Substring(1, attributeSplit[0].Length - 1);
-          string attributeValue = null; // Null means no attribute value
-
-          // Check if we have an attribute value to set
-          if (attributeSplit.Length > 1) {
-            // Remove the ' or " from the attribute value
-            attributeValue = attributeSplit[1].Replace("'", "").Replace("\"", "");
-          }
-
-          // Get the attribute (if exists)
-          XmlAttribute attribute = (XmlAttribute)(node.Attributes.GetNamedItem(attributeName));
-
-          // Remove the attribute if value is empty (not null)
-          if (attributeValue == string.Empty) {
-            // Only if the attribute exists
-            if (attribute != null) {
-              node.Attributes.Remove(attribute);
-            }
-          } else {
-            // Create the attribue if does not exists
-            if (attribute == null) {
-              // Create the attribute
-              attribute = node.OwnerDocument.CreateAttribute(attributeName);
-
-              // Add it to the current node
-              node.Attributes.Append(attribute);
-            }
-
-            // Update the attribute value
-            if (attributeValue != null) {
-              node.Attributes[attributeName].Value = attributeValue;
-            }
-          }
-        } else {
-          // nodeName
-          // x:nodeName
-          // nodeName[find criteria]
-          // x:nodeName[find criteria]
-
-          // Look for the node (with or without filter criteria)
-          XmlNode subNode = node.SelectSingleNode(subPath, NameSpaceManager);
-
-          // Check if the node does not exists
-          if (subNode == null) {
-            string nodeName;
-            string nodePrefix;
-            string[] nameSplit = subPath.Split(':');
-            string nameSpaceUri;
-
-            // Check if the name has a prefix like "d:nodeName"
-            if (nameSplit.Length > 1) {
-              nodePrefix = nameSplit[0];
-              nameSpaceUri = NameSpaceManager.LookupNamespace(nodePrefix);
-              nodeName = nameSplit[1];
-            } else {
-              nodePrefix = string.Empty;
-              nameSpaceUri = string.Empty;
-              nodeName = nameSplit[0];
-            }
-
-            // Check if we have a criteria part in the node name
-            if (nodeName.IndexOf("[") > 0) {
-              // remove the criteria from the node name
-              nodeName = nodeName.Substring(0, nodeName.IndexOf("["));
-            }
-
-            if (nodePrefix == string.Empty) {
-              subNode = node.OwnerDocument.CreateElement(nodeName, nameSpaceUri);
-            } else {
-              if (node.OwnerDocument != null
-                  && node.OwnerDocument.DocumentElement != null
-                  && node.OwnerDocument.DocumentElement.NamespaceURI == nameSpaceUri
-                  && node.OwnerDocument.DocumentElement.Prefix == string.Empty) {
-                subNode = node.OwnerDocument.CreateElement(nodeName, nameSpaceUri);
-              } else {
-                subNode = node.OwnerDocument.CreateElement(nodePrefix, nodeName, nameSpaceUri);
-              }
-            }
-
-            // Check if we need to use the "SchemaOrder"
-            if (nodeInsertOrder == eNodeInsertOrder.SchemaOrder) {
-              // Check if the Schema Order List is empty
-              if (SchemaNodeOrder.Length == 0) {
-                // Use the "Insert Last" option when Schema Order List is empty
-                nodeInsertOrder = eNodeInsertOrder.Last;
-              } else {
-                // Find the prepend node in order to insert
-                referenceNode = GetPrependNode(nodeName, node);
-
-                if (referenceNode != null) {
-                  nodeInsertOrder = eNodeInsertOrder.Before;
-                } else {
-                  nodeInsertOrder = eNodeInsertOrder.Last;
-                }
-              }
-            }
-
-            switch (nodeInsertOrder) {
-              case eNodeInsertOrder.After:
-                node.InsertAfter(subNode, referenceNode);
-                referenceNode = null;
-                break;
-
-              case eNodeInsertOrder.Before:
-                node.InsertBefore(subNode, referenceNode);
-                referenceNode = null;
-                break;
-
-              case eNodeInsertOrder.First:
-                node.PrependChild(subNode);
-                break;
-
-              case eNodeInsertOrder.Last:
-                node.AppendChild(subNode);
-                break;
-            }
-          }
-
-          // Make the newly created node the top node when the rest of the path
-          // is being evaluated. So newly created nodes will be the children of the
-          // one we just created.
-          node = subNode;
-        }
-      }
-    }
-
-    // Return the last created/found node
-    return node;
-  }
-
-  /// <summary>
-  /// return Prepend node
-  /// </summary>
-  /// <param name="nodeName">name of the node to check</param>
-  /// <param name="node">Topnode to check children</param>
-  /// <returns></returns>
-  private XmlNode GetPrependNode(string nodeName, XmlNode node) {
-    int pos = GetNodePos(nodeName);
-    if (pos < 0) {
-      return null;
-    }
-    XmlNode prependNode = null;
-    foreach (XmlNode childNode in node.ChildNodes) {
-      int childPos = GetNodePos(childNode.Name);
-      if (childPos
-          > -1) //Found?
-      {
-        if (childPos
-            > pos) //Position is before
-        {
-          prependNode = childNode;
-          break;
-        }
-      }
-    }
-    return prependNode;
-  }
-
-  private int GetNodePos(string nodeName) {
-    int ix = nodeName.IndexOf(":");
-    if (ix > 0) {
-      nodeName = nodeName.Substring(ix + 1, nodeName.Length - (ix + 1));
-    }
-    for (int i = 0; i < SchemaNodeOrder.Length; i++) {
-      if (nodeName == SchemaNodeOrder[i]) {
-        return i;
-      }
-    }
-    return -1;
-  }
-
-  internal void DeleteAllNode(string path) {
-    string[] split = path.Split('/');
-    XmlNode node = TopNode;
-    foreach (string s in split) {
-      node = node.SelectSingleNode(s, NameSpaceManager);
-      if (node != null) {
-        if (node is XmlAttribute attribute) {
-          attribute.OwnerElement.Attributes.Remove(attribute);
-        } else {
-          node.ParentNode.RemoveChild(node);
-        }
-      } else {
-        break;
-      }
-    }
-  }
-
-  internal void DeleteNode(string path) {
-    var node = TopNode.SelectSingleNode(path, NameSpaceManager);
-    if (node != null) {
-      if (node is XmlAttribute att) {
-        att.OwnerElement.Attributes.Remove(att);
-      } else {
-        node.ParentNode.RemoveChild(node);
-      }
-    }
-  }
-
-  internal void SetXmlNodeString(string path, string value) {
-    SetXmlNodeString(TopNode, path, value, false, false);
-  }
-
-  internal void SetXmlNodeString(string path, string value, bool removeIfBlank) {
-    SetXmlNodeString(TopNode, path, value, removeIfBlank, false);
-  }
-
-  internal void SetXmlNodeString(XmlNode node, string path, string value, bool removeIfBlank) {
-    SetXmlNodeString(node, path, value, removeIfBlank, false);
-  }
-
-  internal void SetXmlNodeString(
-      XmlNode node,
-      string path,
-      string value,
-      bool removeIfBlank,
-      bool insertFirst) {
-    if (node == null) {
-      return;
-    }
-    if (value == "" && removeIfBlank) {
-      DeleteAllNode(path);
-    } else {
-      XmlNode nameNode = node.SelectSingleNode(path, NameSpaceManager);
-      if (nameNode == null) {
-        CreateNode(path, insertFirst);
-        nameNode = node.SelectSingleNode(path, NameSpaceManager);
-      }
-      //if (nameNode.InnerText != value) HasChanged();
-      nameNode.InnerText = value;
-    }
-  }
-
-  internal void SetXmlNodeBool(string path, bool value) {
-    SetXmlNodeString(TopNode, path, value ? "1" : "0", false, false);
-  }
-
-  internal void SetXmlNodeBool(string path, bool value, bool removeIf) {
-    if (value == removeIf) {
-      var node = TopNode.SelectSingleNode(path, NameSpaceManager);
-      if (node != null) {
-        if (node is XmlAttribute attribute) {
-          var elem = attribute.OwnerElement;
-          elem.ParentNode.RemoveChild(elem);
-        } else {
-          TopNode.RemoveChild(node);
-        }
-      }
-    } else {
-      SetXmlNodeString(TopNode, path, value ? "1" : "0", false, false);
-    }
-  }
-
-  internal bool ExistNode(string path) {
-    if (TopNode == null || TopNode.SelectSingleNode(path, NameSpaceManager) == null) {
-      return false;
-    }
-    return true;
-  }
-
-  internal bool? GetXmlNodeBoolNullable(string path) {
-    var value = GetXmlNodeString(path);
-    if (string.IsNullOrEmpty(value)) {
-      return null;
-    }
-    return GetXmlNodeBool(path);
-  }
-
-  internal bool GetXmlNodeBool(string path) {
-    return GetXmlNodeBool(path, false);
-  }
-
-  internal bool GetXmlNodeBool(string path, bool blankValue) {
-    string value = GetXmlNodeString(path);
-    if (value == "1"
-        || value == "-1"
-        || value.Equals("true", StringComparison.InvariantCultureIgnoreCase)) {
-      return true;
-    }
-    if (value == "") {
-      return blankValue;
-    }
-    return false;
-  }
-
-  internal int GetXmlNodeInt(string path) {
-    if (int.TryParse(GetXmlNodeString(path), out var i)) {
-      return i;
-    }
-    return int.MinValue;
-  }
-
-  internal int? GetXmlNodeIntNull(string path) {
-    string s = GetXmlNodeString(path);
-    if (s != "" && int.TryParse(s, out var i)) {
-      return i;
-    }
-    return null;
-  }
-
-  internal decimal GetXmlNodeDecimal(string path) {
-    if (decimal.TryParse(
-        GetXmlNodeString(path),
-        NumberStyles.Any,
-        CultureInfo.InvariantCulture,
-        out var d)) {
-      return d;
-    }
-    return 0;
-  }
-
-  internal decimal? GetXmlNodeDecimalNull(string path) {
-    if (decimal.TryParse(
-        GetXmlNodeString(path),
-        NumberStyles.Any,
-        CultureInfo.InvariantCulture,
-        out var d)) {
-      return d;
-    }
-    return null;
-  }
-
-  internal double? GetXmlNodeDoubleNull(string path) {
-    string s = GetXmlNodeString(path);
-    if (s == "") {
-      return null;
-    }
-    if (double.TryParse(s, NumberStyles.Number, CultureInfo.InvariantCulture, out var v)) {
-      return v;
-    }
-    return null;
-  }
-
-  internal double GetXmlNodeDouble(string path) {
-    string s = GetXmlNodeString(path);
-    if (s == "") {
-      return double.NaN;
-    }
-    if (double.TryParse(s, NumberStyles.Number, CultureInfo.InvariantCulture, out var v)) {
-      return v;
-    }
-    return double.NaN;
-  }
-
-  internal string GetXmlNodeString(XmlNode node, string path) {
-    if (node == null) {
-      return "";
-    }
-
-    XmlNode nameNode = node.SelectSingleNode(path, NameSpaceManager);
-
-    if (nameNode != null) {
-      if (nameNode.NodeType == XmlNodeType.Attribute) {
-        return nameNode.Value ?? "";
-      }
-      return nameNode.InnerText;
-    }
-    return "";
-  }
-
-  internal string GetXmlNodeString(string path) {
-    return GetXmlNodeString(TopNode, path);
-  }
-
-  internal static void LoadXmlSafe(XmlDocument xmlDoc, Stream stream) {
-    XmlReaderSettings settings = new XmlReaderSettings();
-    //Disable entity parsing (to aviod xmlbombs, External Entity Attacks etc).
-    settings.ProhibitDtd = true;
-    XmlReader reader = XmlReader.Create(stream, settings);
-    xmlDoc.Load(reader);
-  }
-
-  internal static void LoadXmlSafe(XmlDocument xmlDoc, string xml, Encoding encoding) {
-    var stream = new MemoryStream(encoding.GetBytes(xml));
-    LoadXmlSafe(xmlDoc, stream);
-  }
-}
diff --git a/EPPlus/XmlHelperFactory.cs b/EPPlus/XmlHelperFactory.cs
deleted file mode 100644
index 0af078b..0000000
--- a/EPPlus/XmlHelperFactory.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011  Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author							Change						Date
- * ******************************************************************************
- * Mats Alm 		    Initial Release		        2011-05-01
- * Jan Källman		    License changed GPL-->LGPL  2011-12-27
- *******************************************************************************/
-
-using System.Xml;
-
-namespace OfficeOpenXml;
-
-internal class XmlHelperInstance : XmlHelper {
-  internal XmlHelperInstance(XmlNamespaceManager namespaceManager)
-      : base(namespaceManager) {}
-
-  internal XmlHelperInstance(XmlNamespaceManager namespaceManager, XmlNode topNode)
-      : base(namespaceManager, topNode) {}
-}
-
-internal static class XmlHelperFactory {
-  internal static XmlHelper Create(XmlNamespaceManager namespaceManager) {
-    return new XmlHelperInstance(namespaceManager);
-  }
-
-  internal static XmlHelper Create(XmlNamespaceManager namespaceManager, XmlNode topNode) {
-    return new XmlHelperInstance(namespaceManager, topNode);
-  }
-}
diff --git a/NetCoreTests/ExcelPackageTest.cs b/NetCoreTests/ExcelPackageTest.cs
index 369e55a..77a5c6b 100644
--- a/NetCoreTests/ExcelPackageTest.cs
+++ b/NetCoreTests/ExcelPackageTest.cs
@@ -1,9 +1,8 @@
 using System.IO;
 using System.Linq;
+using AppsheetEpplus;
 using FluentAssertions;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
-using OfficeOpenXml;
-using OfficeOpenXml.DataValidation;
 
 namespace NetCoreTests;
 
diff --git a/NetCoreTests/NetCoreTests.csproj b/NetCoreTests/NetCoreTests.csproj
index 275008e..6218500 100644
--- a/NetCoreTests/NetCoreTests.csproj
+++ b/NetCoreTests/NetCoreTests.csproj
@@ -11,8 +11,9 @@
     <PackageReference Include="System.Net.Http" Version="4.3.4" />
     <PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
 
-    <ProjectReference Include="..\EPPlus\EPPlusSDK.csproj"/>
-
     <None Include="TestWorkbooks/**" CopyToOutputDirectory="PreserveNewest"/>
   </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\AppsheetEpplus\AppsheetEpplus.csproj" />
+  </ItemGroup>
 </Project>
diff --git a/NetCoreTests/TimeTest.cs b/NetCoreTests/TimeTest.cs
index 8ce92f5..a94ce94 100644
--- a/NetCoreTests/TimeTest.cs
+++ b/NetCoreTests/TimeTest.cs
@@ -2,9 +2,9 @@
 using System.IO;
 using System.Linq;
 using System.Text;
+using AppsheetEpplus;
 using FluentAssertions;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
-using OfficeOpenXml;
 
 namespace NetCoreTests;