diff --git a/.github/workflows/UploadCoverageReport.yml b/.github/workflows/UploadCoverageReport.yml
index eee9d4aec9..3f8fee4256 100644
--- a/.github/workflows/UploadCoverageReport.yml
+++ b/.github/workflows/UploadCoverageReport.yml
@@ -8,6 +8,9 @@ name: UploadCoverageReport
       - master
   pull_request:
 
+env:
+  REPORT_PATH: "coverage/coverage-final.json"
+
 jobs:
   UploadCoverageReport:
     runs-on: ubuntu-latest
@@ -25,9 +28,18 @@ jobs:
       - name: Generate coverage report
         run: npm test -- --coverage
 
-      - name: Upload coverage to codecov
-        uses: codecov/codecov-action@v3
+      - name: Upload coverage to codecov (tokenless)
+        if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository
+        uses: codecov/codecov-action@v4
+        with:
+          files: "${{ env.REPORT_PATH }}"
+          fail_ci_if_error: true
+
+      - name: Upload coverage to codecov (with token)
+        if: "! github.event.pull_request.head.repo.fork "
+        uses: codecov/codecov-action@v4
         with:
-          files: "coverage/coverage-final.json"
+          token: ${{ secrets.CODECOV_TOKEN }}
+          files: "${{ env.REPORT_PATH }}"
           fail_ci_if_error: true
 ...
diff --git a/Backtracking/tests/RatInAMaze.test.js b/Backtracking/tests/RatInAMaze.test.js
index 6cc5b31aae..52f620027b 100644
--- a/Backtracking/tests/RatInAMaze.test.js
+++ b/Backtracking/tests/RatInAMaze.test.js
@@ -6,7 +6,6 @@ describe('RatInAMaze', () => {
 
     for (const value of values) {
       // we deliberately want to check whether this constructor call fails or not
-      // eslint-disable-next-line no-new
       expect(() => {
         new RatInAMaze(value)
       }).toThrow()
@@ -15,7 +14,6 @@ describe('RatInAMaze', () => {
 
   it('should fail for an empty array', () => {
     // we deliberately want to check whether this constructor call fails or not
-    // eslint-disable-next-line no-new
     expect(() => {
       new RatInAMaze([])
     }).toThrow()
@@ -28,7 +26,6 @@ describe('RatInAMaze', () => {
     ]
 
     // we deliberately want to check whether this constructor call fails or not
-    // eslint-disable-next-line no-new
     expect(() => {
       new RatInAMaze(array)
     }).toThrow()
@@ -39,7 +36,6 @@ describe('RatInAMaze', () => {
 
     for (const value of values) {
       // we deliberately want to check whether this constructor call fails or not
-      // eslint-disable-next-line no-new
       expect(() => {
         new RatInAMaze(value)
       }).toThrow()
diff --git a/Backtracking/tests/Sudoku.test.js b/Backtracking/tests/Sudoku.test.js
index 8cbe187089..c70f7de67a 100644
--- a/Backtracking/tests/Sudoku.test.js
+++ b/Backtracking/tests/Sudoku.test.js
@@ -27,7 +27,6 @@ const solved = [
 describe('Sudoku', () => {
   it('should create a valid board successfully', () => {
     // we deliberately want to check whether this constructor call fails or not
-    // eslint-disable-next-line no-new
     expect(() => {
       new Sudoku(data)
     }).not.toThrow()
diff --git a/Compression/RLE.js b/Compression/RLE.js
new file mode 100644
index 0000000000..81a1538646
--- /dev/null
+++ b/Compression/RLE.js
@@ -0,0 +1,38 @@
+/*
+ * RLE (Run Length Encoding) is a simple form of data compression.
+ * The basic idea is to represent repeated successive characters as a single count and character.
+ * For example, the string "AAAABBBCCDAA" would be encoded as "4A3B2C1D2A".
+ *
+ * @author - [ddaniel27](https://github.com/ddaniel27)
+ */
+
+function Compress(str) {
+  let compressed = ''
+  let count = 1
+
+  for (let i = 0; i < str.length; i++) {
+    if (str[i] !== str[i + 1]) {
+      compressed += count + str[i]
+      count = 1
+      continue
+    }
+
+    count++
+  }
+
+  return compressed
+}
+
+function Decompress(str) {
+  let decompressed = ''
+  let match = [...str.matchAll(/(\d+)(\D)/g)] // match all groups of digits followed by a non-digit character
+
+  match.forEach((item) => {
+    let [count, char] = [item[1], item[2]]
+    decompressed += char.repeat(count)
+  })
+
+  return decompressed
+}
+
+export { Compress, Decompress }
diff --git a/Compression/test/RLE.test.js b/Compression/test/RLE.test.js
new file mode 100644
index 0000000000..0094b5b7e2
--- /dev/null
+++ b/Compression/test/RLE.test.js
@@ -0,0 +1,13 @@
+import { Compress, Decompress } from '../RLE'
+
+describe('Test RLE Compressor/Decompressor', () => {
+  it('Test - 1, Pass long repetitive strings', () => {
+    expect(Compress('AAAAAAAAAAAAAA')).toBe('14A')
+    expect(Compress('AAABBQQQQQFG')).toBe('3A2B5Q1F1G')
+  })
+
+  it('Test - 2, Pass compressed strings', () => {
+    expect(Decompress('14A')).toBe('AAAAAAAAAAAAAA')
+    expect(Decompress('3A2B5Q1F1G')).toBe('AAABBQQQQQFG')
+  })
+})
diff --git a/Conversions/HexToDecimal.js b/Conversions/HexToDecimal.js
index 31ae13932f..e402421399 100644
--- a/Conversions/HexToDecimal.js
+++ b/Conversions/HexToDecimal.js
@@ -1,4 +1,7 @@
 function hexToInt(hexNum) {
+  if (!/^[0-9A-F]+$/.test(hexNum)) {
+    throw new Error('Invalid hex string.')
+  }
   const numArr = hexNum.split('') // converts number to array
   return numArr.map((item, index) => {
     switch (item) {
@@ -29,4 +32,4 @@ function hexToDecimal(hexNum) {
   }, 0)
 }
 
-export { hexToInt, hexToDecimal }
+export { hexToDecimal }
diff --git a/Conversions/test/HexToDecimal.test.js b/Conversions/test/HexToDecimal.test.js
new file mode 100644
index 0000000000..816c70511d
--- /dev/null
+++ b/Conversions/test/HexToDecimal.test.js
@@ -0,0 +1,24 @@
+import { hexToDecimal } from '../HexToDecimal'
+
+describe('Testing HexToDecimal', () => {
+  it.each([
+    ['0', 0],
+    ['1', 1],
+    ['A', 10],
+    ['B', 11],
+    ['C', 12],
+    ['D', 13],
+    ['E', 14],
+    ['F', 15],
+    ['10', 16],
+    ['859', 2137],
+    ['4D2', 1234],
+    ['81323ABD92', 554893491602]
+  ])('check with %s', (hexStr, expected) => {
+    expect(hexToDecimal(hexStr)).toBe(expected)
+  })
+
+  it.each(['a', '-1', 'G', ''])('throws for %s', (hexStr) => {
+    expect(() => hexToDecimal(hexStr)).toThrowError()
+  })
+})
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 6c1fa7aeb8..5e8e1f401a 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -35,6 +35,8 @@
   * [ROT13](Ciphers/ROT13.js)
   * [VigenereCipher](Ciphers/VigenereCipher.js)
   * [XORCipher](Ciphers/XORCipher.js)
+* **Compression**
+  * [RLE](Compression/RLE.js)
 * **Conversions**
   * [ArbitraryBase](Conversions/ArbitraryBase.js)
   * [ArrayBufferToBase64](Conversions/ArrayBufferToBase64.js)
@@ -252,7 +254,6 @@
   * [RowEchelon](Maths/RowEchelon.js)
   * [ShorsAlgorithm](Maths/ShorsAlgorithm.js)
   * [SieveOfEratosthenes](Maths/SieveOfEratosthenes.js)
-  * [SieveOfEratosthenesIntArray](Maths/SieveOfEratosthenesIntArray.js)
   * [Signum](Maths/Signum.js)
   * [SimpsonIntegration](Maths/SimpsonIntegration.js)
   * [Softmax](Maths/Softmax.js)
@@ -285,6 +286,7 @@
   * [Problem016](Project-Euler/Problem016.js)
   * [Problem017](Project-Euler/Problem017.js)
   * [Problem018](Project-Euler/Problem018.js)
+  * [Problem019](Project-Euler/Problem019.js)
   * [Problem020](Project-Euler/Problem020.js)
   * [Problem021](Project-Euler/Problem021.js)
   * [Problem023](Project-Euler/Problem023.js)
diff --git a/Data-Structures/Array/QuickSelect.js b/Data-Structures/Array/QuickSelect.js
index d01555ed95..53c8c8e855 100644
--- a/Data-Structures/Array/QuickSelect.js
+++ b/Data-Structures/Array/QuickSelect.js
@@ -12,7 +12,6 @@
  */
 
 function QuickSelect(items, kth) {
-  // eslint-disable-line no-unused-vars
   if (kth < 1 || kth > items.length) {
     throw new RangeError('Index Out of Bound')
   }
diff --git a/Data-Structures/Queue/QueueUsing2Stacks.js b/Data-Structures/Queue/QueueUsing2Stacks.js
index 256f11060d..9a51ee3a72 100644
--- a/Data-Structures/Queue/QueueUsing2Stacks.js
+++ b/Data-Structures/Queue/QueueUsing2Stacks.js
@@ -29,24 +29,6 @@ class Queue {
       return top
     }
   }
-
-  // display elements of the inputstack
-  listIn(output = (value) => console.log(value)) {
-    let i = 0
-    while (i < this.inputStack.length) {
-      output(this.inputStack[i])
-      i++
-    }
-  }
-
-  // display element of the outputstack
-  listOut(output = (value) => console.log(value)) {
-    let i = 0
-    while (i < this.outputStack.length) {
-      output(this.outputStack[i])
-      i++
-    }
-  }
 }
 
 export { Queue }
diff --git a/Data-Structures/Tree/BinarySearchTree.js b/Data-Structures/Tree/BinarySearchTree.js
index abbcc3fb62..8a65c8e650 100644
--- a/Data-Structures/Tree/BinarySearchTree.js
+++ b/Data-Structures/Tree/BinarySearchTree.js
@@ -36,13 +36,13 @@ const Node = (function Node() {
     visit(output = (value) => console.log(value)) {
       // Recursively go left
       if (this.left !== null) {
-        this.left.visit()
+        this.left.visit(output)
       }
       // Print out value
       output(this.value)
       // Recursively go right
       if (this.right !== null) {
-        this.right.visit()
+        this.right.visit(output)
       }
     }
 
@@ -116,20 +116,23 @@ const Tree = (function () {
     }
 
     // Inorder traversal
-    traverse() {
+    traverse(output = (value) => console.log(value)) {
       if (!this.root) {
         // No nodes are there in the tree till now
         return
       }
-      this.root.visit()
+      this.root.visit(output)
     }
 
     // Start by searching the root
     search(val) {
-      const found = this.root.search(val)
-      if (found !== null) {
-        return found.value
+      if (this.root) {
+        const found = this.root.search(val)
+        if (found !== null) {
+          return found.value
+        }
       }
+
       // not found
       return null
     }
diff --git a/Data-Structures/Tree/test/BinarySearchTree.test.js b/Data-Structures/Tree/test/BinarySearchTree.test.js
new file mode 100644
index 0000000000..4c6c353592
--- /dev/null
+++ b/Data-Structures/Tree/test/BinarySearchTree.test.js
@@ -0,0 +1,66 @@
+import { Tree } from '../BinarySearchTree.js'
+
+describe('Binary Search Tree', () => {
+  let tree
+
+  beforeEach(() => {
+    tree = new Tree()
+    tree.addValue(10)
+    tree.addValue(5)
+    tree.addValue(15)
+    tree.addValue(3)
+    tree.addValue(8)
+  })
+
+  test('should add values to the tree', () => {
+    tree.addValue(12)
+
+    expect(tree.search(12)).toBe(12)
+    expect(tree.search(5)).toBe(5)
+    expect(tree.search(15)).toBe(15)
+  })
+
+  test('should perform in-order traversal', () => {
+    const values = []
+    const output = (val) => values.push(val)
+    tree.traverse(output)
+    expect(values).toEqual([3, 5, 8, 10, 15])
+  })
+
+  test('should remove leaf nodes correctly', () => {
+    tree.removeValue(5)
+    expect(tree.search(5)).toBeNull()
+  })
+
+  test('should remove nodes with one child correctly', () => {
+    tree.addValue(12)
+    tree.removeValue(15)
+
+    expect(tree.search(15)).toBeNull()
+    expect(tree.search(12)).toBe(12)
+  })
+
+  test('should remove nodes with two children correctly', () => {
+    tree.addValue(18)
+    tree.removeValue(15)
+
+    expect(tree.search(15)).toBeNull()
+    expect(tree.search(18)).toBe(18)
+  })
+
+  test('should return null for non-existent values', () => {
+    expect(tree.search(20)).toBeNull()
+    expect(tree.search(0)).toBeNull()
+  })
+
+  test('should handle removal of root node correctly', () => {
+    tree.removeValue(10)
+    expect(tree.search(10)).toBeNull()
+  })
+
+  test('should handle empty tree gracefully', () => {
+    const newTree = new Tree()
+    newTree.removeValue(22) // Should not throw
+    expect(newTree.search(22)).toBeNull()
+  })
+})
diff --git a/Dynamic-Programming/NumberOfSubsetEqualToGivenSum.js b/Dynamic-Programming/NumberOfSubsetEqualToGivenSum.js
index 48905c39e2..fd8e70c4d6 100644
--- a/Dynamic-Programming/NumberOfSubsetEqualToGivenSum.js
+++ b/Dynamic-Programming/NumberOfSubsetEqualToGivenSum.js
@@ -1,5 +1,5 @@
 /*
-Given an array of non-negative integers and a value sum,
+Given an array of positive integers and a value sum,
 determine the total number of the subset with sum
 equal to the given sum.
 */
@@ -7,6 +7,13 @@ equal to the given sum.
   Given solution is O(n*sum) Time complexity and O(sum) Space complexity
 */
 function NumberOfSubsetSum(array, sum) {
+  if (sum < 0) {
+    throw new Error('The sum must be non-negative.')
+  }
+
+  if (!array.every((num) => num > 0)) {
+    throw new Error('All of the inputs of the array must be positive.')
+  }
   const dp = [] // create an dp array where dp[i] denote number of subset with sum equal to i
   for (let i = 1; i <= sum; i++) {
     dp[i] = 0
@@ -23,10 +30,4 @@ function NumberOfSubsetSum(array, sum) {
   return dp[sum]
 }
 
-// example
-
-// const array = [1, 1, 2, 2, 3, 1, 1]
-// const sum = 4
-// const result = NumberOfSubsetSum(array, sum)
-
 export { NumberOfSubsetSum }
diff --git a/Dynamic-Programming/tests/NumberOfSubsetEqualToGivenSum.test.js b/Dynamic-Programming/tests/NumberOfSubsetEqualToGivenSum.test.js
new file mode 100644
index 0000000000..23eed33ebe
--- /dev/null
+++ b/Dynamic-Programming/tests/NumberOfSubsetEqualToGivenSum.test.js
@@ -0,0 +1,25 @@
+import { NumberOfSubsetSum } from '../NumberOfSubsetEqualToGivenSum'
+
+describe('Testing NumberOfSubsetSum', () => {
+  it.each([
+    [[], 0, 1],
+    [[], 1, 0],
+    [[1], 2, 0],
+    [[1, 2, 3, 4, 5], 0, 1],
+    [[1, 1, 1, 1, 1], 5, 1],
+    [[1, 1, 1, 1, 1], 4, 5],
+    [[1, 2, 3, 3], 6, 3],
+    [[10, 20, 30, 1], 31, 2],
+    [[1, 1, 2, 2, 3, 1, 1], 4, 18]
+  ])('check with %j and %i', (arr, sum, expected) => {
+    expect(NumberOfSubsetSum(arr, sum)).toBe(expected)
+  })
+
+  it.each([
+    [[1, 2], -1],
+    [[0, 2], 2],
+    [[1, -1], 0]
+  ])('throws for %j and %i', (arr, sum) => {
+    expect(() => NumberOfSubsetSum(arr, sum)).toThrowError()
+  })
+})
diff --git a/Maths/AverageMean.js b/Maths/AverageMean.js
index 75f7b1b58e..8ae3b55992 100644
--- a/Maths/AverageMean.js
+++ b/Maths/AverageMean.js
@@ -13,11 +13,7 @@ const mean = (nums) => {
     throw new TypeError('Invalid Input')
   }
 
-  // This loop sums all values in the 'nums' array using forEach loop
-  const sum = nums.reduce((sum, cur) => sum + cur, 0)
-
-  // Divide sum by the length of the 'nums' array.
-  return sum / nums.length
+  return nums.reduce((sum, cur) => sum + cur, 0) / nums.length
 }
 
 export { mean }
diff --git a/Maths/SieveOfEratosthenes.js b/Maths/SieveOfEratosthenes.js
index 01e141f2f0..681d8ba904 100644
--- a/Maths/SieveOfEratosthenes.js
+++ b/Maths/SieveOfEratosthenes.js
@@ -1,25 +1,26 @@
-const sieveOfEratosthenes = (n) => {
-  /*
-   * Calculates prime numbers till a number n
-   * :param n: Number up to which to calculate primes
-   * :return: A boolean list containing only primes
-   */
-  const primes = new Array(n + 1)
-  primes.fill(true) // set all as true initially
-  primes[0] = primes[1] = false // Handling case for 0 and 1
-  const sqrtn = Math.ceil(Math.sqrt(n))
-  for (let i = 2; i <= sqrtn; i++) {
-    if (primes[i]) {
-      for (let j = i * i; j <= n; j += i) {
-        /*
-        Optimization.
-        Let j start from i * i, not 2 * i, because smaller multiples of i have been marked false.
+/**
+ * @function sieveOfEratosthenes
+ * @description Function to get all the prime numbers below a given number using sieve of eratosthenes algorithm
+ * @param {Number} max The limit below which all the primes are required to be
+ * @returns {Number[]} An array of all the prime numbers below max
+ * @see [Sieve of Eratosthenes](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes)
+ * @example
+ * sieveOfEratosthenes(1) // ====> []
+ * @example
+ * sieveOfEratosthenes(20) // ====> [2, 3, 5, 7, 11, 13, 17, 19]
+ *
+ */
+function sieveOfEratosthenes(max) {
+  const sieve = []
+  const primes = []
 
-        For example, let i = 4.
-        We do not have to check from 8(4 * 2) to 12(4 * 3)
-        because they have been already marked false when i=2 and i=3.
-        */
-        primes[j] = false
+  for (let i = 2; i <= max; ++i) {
+    if (!sieve[i]) {
+      // If i has not been marked then it is prime
+      primes.push(i)
+      for (let j = i << 1; j <= max; j += i) {
+        // Mark all multiples of i as non-prime
+        sieve[j] = true
       }
     }
   }
diff --git a/Maths/SieveOfEratosthenesIntArray.js b/Maths/SieveOfEratosthenesIntArray.js
deleted file mode 100644
index 56336ce7d8..0000000000
--- a/Maths/SieveOfEratosthenesIntArray.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/**
- * Function to get all prime numbers below a given number
- * This function returns an array of prime numbers
- * @see {@link https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes}
- */
-
-function sieveOfEratosthenes(max) {
-  const sieve = []
-  const primes = []
-
-  for (let i = 2; i <= max; ++i) {
-    if (!sieve[i]) {
-      // If i has not been marked then it is prime
-      primes.push(i)
-      for (let j = i << 1; j <= max; j += i) {
-        // Mark all multiples of i as non-prime
-        sieve[j] = true
-      }
-    }
-  }
-  return primes
-}
-
-export { sieveOfEratosthenes }
diff --git a/Maths/test/EulerMethod.manual-test.js b/Maths/test/EulerMethod.manual-test.js
index 27b4631a80..e1959280a5 100644
--- a/Maths/test/EulerMethod.manual-test.js
+++ b/Maths/test/EulerMethod.manual-test.js
@@ -15,7 +15,6 @@ function plotLine(label, points, width, height) {
 
   // Chart-class from chartjs
   const chart = new Chart(canvas, {
-    // eslint-disable-line
     type: 'scatter',
     data: {
       datasets: [
diff --git a/Maths/test/FindMinIterator.test.js b/Maths/test/FindMinIterator.test.js
index 7b7229b106..792cb7695e 100644
--- a/Maths/test/FindMinIterator.test.js
+++ b/Maths/test/FindMinIterator.test.js
@@ -22,13 +22,12 @@ describe('FindMinIterator', () => {
   })
 
   test('given empty generator then min is undefined', () => {
-    const src = function* () {} // eslint-disable-line
+    const src = function* () {}
     expect(FindMinIterator(src())).toBeUndefined()
   })
 
   test('given generator then min is found', () => {
     const src = function* () {
-      // eslint-disable-line
       yield 1
       yield -1
       yield 0
@@ -38,7 +37,6 @@ describe('FindMinIterator', () => {
 
   test('given string generator then min string length is found', () => {
     const src = function* () {
-      // eslint-disable-line
       yield 'abc'
       yield 'de'
       yield 'qwerty'
diff --git a/Maths/test/SieveOfEratosthenes.test.js b/Maths/test/SieveOfEratosthenes.test.js
index 056693d39b..1a10b8bc7f 100644
--- a/Maths/test/SieveOfEratosthenes.test.js
+++ b/Maths/test/SieveOfEratosthenes.test.js
@@ -1,14 +1,29 @@
 import { sieveOfEratosthenes } from '../SieveOfEratosthenes'
-import { PrimeCheck } from '../PrimeCheck'
-
-describe('should return an array of prime booleans', () => {
-  it('should have each element in the array as a prime boolean', () => {
-    const n = 30
-    const primes = sieveOfEratosthenes(n)
-    primes.forEach((primeBool, index) => {
-      if (primeBool) {
-        expect(PrimeCheck(index)).toBeTruthy()
-      }
-    })
+
+describe('sieveOfEratosthenes', () => {
+  test('returns an empty array for max < 2', () => {
+    expect(sieveOfEratosthenes(1)).toEqual([])
+  })
+
+  test('returns [2] for max = 2', () => {
+    expect(sieveOfEratosthenes(2)).toEqual([2])
+  })
+
+  test('returns [2, 3] for max = 3', () => {
+    expect(sieveOfEratosthenes(3)).toEqual([2, 3])
+  })
+
+  test('returns [2, 3, 5, 7] for max = 10', () => {
+    expect(sieveOfEratosthenes(10)).toEqual([2, 3, 5, 7])
+  })
+
+  test('returns [2, 3, 5, 7, 11, 13, 17, 19] for max = 20', () => {
+    expect(sieveOfEratosthenes(20)).toEqual([2, 3, 5, 7, 11, 13, 17, 19])
+  })
+
+  test('returns [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] for max = 30', () => {
+    expect(sieveOfEratosthenes(30)).toEqual([
+      2, 3, 5, 7, 11, 13, 17, 19, 23, 29
+    ])
   })
 })
diff --git a/Maths/test/SieveOfEratosthenesIntArray.test.js b/Maths/test/SieveOfEratosthenesIntArray.test.js
deleted file mode 100644
index e3a3be3002..0000000000
--- a/Maths/test/SieveOfEratosthenesIntArray.test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { sieveOfEratosthenes } from '../SieveOfEratosthenesIntArray'
-import { PrimeCheck } from '../PrimeCheck'
-
-describe('should return an array of prime numbers', () => {
-  it('should have each element in the array as a prime numbers', () => {
-    const n = 100
-    const primes = sieveOfEratosthenes(n)
-    primes.forEach((prime) => {
-      expect(PrimeCheck(prime)).toBeTruthy()
-    })
-  })
-})
diff --git a/Project-Euler/Problem005.js b/Project-Euler/Problem005.js
index fe8901c94c..92f3df9b68 100644
--- a/Project-Euler/Problem005.js
+++ b/Project-Euler/Problem005.js
@@ -5,11 +5,9 @@ Smallest multiple
 What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?
 */
 
-export const findSmallestMultiple = () => {
-  const divisors = [
-    20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2
-  ]
-  let num = 21
+export const findSmallestMultiple = (maxDivisor) => {
+  const divisors = Array.from({ length: maxDivisor }, (_, i) => i + 1)
+  let num = maxDivisor + 1
   let result
 
   while (!result) {
diff --git a/Project-Euler/Problem019.js b/Project-Euler/Problem019.js
new file mode 100644
index 0000000000..5b488c7f96
--- /dev/null
+++ b/Project-Euler/Problem019.js
@@ -0,0 +1,48 @@
+/**
+ * Problem 19 - Counting Sundays
+ *
+ * @see {@link https://projecteuler.net/problem=19}
+ *
+ * You are given the following information, but you may prefer to do some research for yourself.
+ * 1 Jan 1900 was a Monday.
+ * Thirty days has September,
+ * April, June and November.
+ * All the rest have thirty-one,
+ * Saving February alone,
+ * Which has twenty-eight, rain or shine.
+ * And on leap years, twenty-nine.
+ * A leap year occurs on any year evenly divisible by 4, but not on a century unless it is divisible by 400.
+ * How many Sundays fell on the first of the month during the twentieth century (1 Jan 1901 to 31 Dec 2000)?
+ *
+ * @author ddaniel27
+ */
+import { isLeapYear } from '../Maths/LeapYear'
+
+function problem19() {
+  let sundaysCount = 0 // Count of Sundays
+  let dayOfWeek = 2 // 1st Jan 1900 was a Monday, so 1st Jan 1901 was a Tuesday
+
+  for (let year = 1901; year <= 2000; year++) {
+    for (let month = 1; month <= 12; month++) {
+      if (dayOfWeek === 0) {
+        // If it's a Sunday (0 is Sunday, 1 is Monday, ..., 6 is Saturday)
+        sundaysCount++
+      }
+
+      let daysInMonth = 31
+      if (month === 4 || month === 6 || month === 9 || month === 11) {
+        // April, June, September, November
+        daysInMonth = 30
+      } else if (month === 2) {
+        // February
+        daysInMonth = isLeapYear(year) ? 29 : 28
+      }
+
+      dayOfWeek = (dayOfWeek + daysInMonth) % 7 // Calculate the day of the week
+    }
+  }
+
+  return sundaysCount
+}
+
+export { problem19 }
diff --git a/Project-Euler/Problem035.js b/Project-Euler/Problem035.js
index c877acba5a..0b11cd0357 100644
--- a/Project-Euler/Problem035.js
+++ b/Project-Euler/Problem035.js
@@ -9,7 +9,7 @@
  *
  * @author ddaniel27
  */
-import { sieveOfEratosthenes } from '../Maths/SieveOfEratosthenesIntArray'
+import { sieveOfEratosthenes } from '../Maths/SieveOfEratosthenes'
 
 function problem35(n) {
   if (n < 2) {
diff --git a/Project-Euler/test/Problem005.test.js b/Project-Euler/test/Problem005.test.js
new file mode 100644
index 0000000000..f3ac1b03d8
--- /dev/null
+++ b/Project-Euler/test/Problem005.test.js
@@ -0,0 +1,12 @@
+import { expect } from 'vitest'
+import { findSmallestMultiple } from '../Problem005.js'
+
+describe.concurrent('Find smallest multiple', () => {
+  test.each([
+    [10, 2520],
+    [15, 360360],
+    [20, 232792560]
+  ])('max divisor -> %i, smallest multiple -> %i', (a, expected) => {
+    expect(findSmallestMultiple(a)).toBe(expected)
+  })
+})
diff --git a/Project-Euler/test/Problem014.test.js b/Project-Euler/test/Problem014.test.js
new file mode 100644
index 0000000000..ff464dd42d
--- /dev/null
+++ b/Project-Euler/test/Problem014.test.js
@@ -0,0 +1,15 @@
+import { expect } from 'vitest'
+import { findLongestCollatzSequence } from '../Problem014.js'
+
+describe('Longest Collatz Sequence', () => {
+  test.each([
+    [2, 1],
+    [13, 9],
+    [1000000, 837799]
+  ])(
+    'if limit is %i, then the Longest Collatz Sequence will be %i',
+    (a, expected) => {
+      expect(findLongestCollatzSequence(a)).toBe(expected)
+    }
+  )
+})
diff --git a/Project-Euler/test/Problem019.test.js b/Project-Euler/test/Problem019.test.js
new file mode 100644
index 0000000000..8845e5a0ac
--- /dev/null
+++ b/Project-Euler/test/Problem019.test.js
@@ -0,0 +1,8 @@
+import { problem19 } from '../Problem019.js'
+
+describe('checking sundays during the twentieth century', () => {
+  // Project Euler Challenge Check
+  test('result should be 171', () => {
+    expect(problem19()).toBe(171)
+  })
+})
diff --git a/Recursive/test/FloodFill.test.js b/Recursive/test/FloodFill.test.js
index 618692dd97..eb44e75e09 100644
--- a/Recursive/test/FloodFill.test.js
+++ b/Recursive/test/FloodFill.test.js
@@ -69,7 +69,6 @@ function testDepthFirst(
   replacementColor,
   testLocation
 ) {
-  // eslint-disable-line
   const rgbData = generateTestRgbData()
   depthFirstSearch(rgbData, fillLocation, targetColor, replacementColor)
   return rgbData[testLocation[0]][testLocation[1]]
diff --git a/Search/LinearSearch.js b/Search/LinearSearch.js
index 637ebc1589..96a9d1fa34 100644
--- a/Search/LinearSearch.js
+++ b/Search/LinearSearch.js
@@ -3,6 +3,8 @@
  * value within a list. It sequentially checks each element of the list
  * for the target value until a match is found or until all the elements
  * have been searched.
+ *
+ * @see https://en.wikipedia.org/wiki/Linear_search
  */
 function SearchArray(searchNum, ar, output = (v) => console.log(v)) {
   const position = Search(ar, searchNum)
diff --git a/Search/test/LinearSearch.test.js b/Search/test/LinearSearch.test.js
new file mode 100644
index 0000000000..d593d9aa1c
--- /dev/null
+++ b/Search/test/LinearSearch.test.js
@@ -0,0 +1,35 @@
+import { Search as linearSearch } from '../LinearSearch'
+
+const tests = [
+  {
+    test: {
+      arr: [1, 2, 300, 401, 450, 504, 800, 821, 855, 900, 1002],
+      target: 900
+    },
+    expectedValue: 9
+  },
+  {
+    test: {
+      arr: [1, 104, 110, 4, 44, 55, 56, 78],
+      target: 104
+    },
+    expectedValue: 1
+  },
+  {
+    test: {
+      arr: [-4, 5, 50, 77, 821, 85, 99, 100],
+      target: 192
+    },
+    expectedValue: -1
+  }
+]
+
+describe('Linear Search', () => {
+  it.each(tests)(
+    'linearSearch($test.arr, $test.target) => $expectedValue',
+    ({ test, expectedValue }) => {
+      const { arr, target } = test
+      expect(linearSearch(arr, target)).toBe(expectedValue)
+    }
+  )
+})
diff --git a/package-lock.json b/package-lock.json
index a4efa09c1b..5c38ba06a8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -76,13 +76,270 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/@esbuild/aix-ppc64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
+      "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "aix"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/android-arm": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
+      "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/android-arm64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
+      "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/android-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
+      "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/darwin-arm64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
+      "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/darwin-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
+      "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/freebsd-arm64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
+      "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/freebsd-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
+      "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-arm": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
+      "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-arm64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
+      "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-ia32": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
+      "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-loong64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
+      "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-mips64el": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
+      "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
+      "cpu": [
+        "mips64el"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-ppc64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
+      "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-riscv64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
+      "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-s390x": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
+      "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
     "node_modules/@esbuild/linux-x64": {
-      "version": "0.19.12",
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
+      "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
       "cpu": [
         "x64"
       ],
       "dev": true,
-      "license": "MIT",
       "optional": true,
       "os": [
         "linux"
@@ -91,6 +348,102 @@
         "node": ">=12"
       }
     },
+    "node_modules/@esbuild/netbsd-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
+      "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/openbsd-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
+      "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/sunos-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
+      "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "sunos"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/win32-arm64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
+      "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/win32-ia32": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
+      "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/win32-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
+      "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
     "node_modules/@istanbuljs/schema": {
       "version": "0.1.3",
       "dev": true,
@@ -174,30 +527,214 @@
         "node": ">= 8"
       }
     },
+    "node_modules/@rollup/rollup-android-arm-eabi": {
+      "version": "4.22.4",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz",
+      "integrity": "sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ]
+    },
+    "node_modules/@rollup/rollup-android-arm64": {
+      "version": "4.22.4",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.4.tgz",
+      "integrity": "sha512-VXoK5UMrgECLYaMuGuVTOx5kcuap1Jm8g/M83RnCHBKOqvPPmROFJGQaZhGccnsFtfXQ3XYa4/jMCJvZnbJBdA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ]
+    },
+    "node_modules/@rollup/rollup-darwin-arm64": {
+      "version": "4.22.4",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.4.tgz",
+      "integrity": "sha512-xMM9ORBqu81jyMKCDP+SZDhnX2QEVQzTcC6G18KlTQEzWK8r/oNZtKuZaCcHhnsa6fEeOBionoyl5JsAbE/36Q==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@rollup/rollup-darwin-x64": {
+      "version": "4.22.4",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.4.tgz",
+      "integrity": "sha512-aJJyYKQwbHuhTUrjWjxEvGnNNBCnmpHDvrb8JFDbeSH3m2XdHcxDd3jthAzvmoI8w/kSjd2y0udT+4okADsZIw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+      "version": "4.22.4",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.4.tgz",
+      "integrity": "sha512-j63YtCIRAzbO+gC2L9dWXRh5BFetsv0j0va0Wi9epXDgU/XUi5dJKo4USTttVyK7fGw2nPWK0PbAvyliz50SCQ==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+      "version": "4.22.4",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.4.tgz",
+      "integrity": "sha512-dJnWUgwWBX1YBRsuKKMOlXCzh2Wu1mlHzv20TpqEsfdZLb3WoJW2kIEsGwLkroYf24IrPAvOT/ZQ2OYMV6vlrg==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm64-gnu": {
+      "version": "4.22.4",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.4.tgz",
+      "integrity": "sha512-AdPRoNi3NKVLolCN/Sp4F4N1d98c4SBnHMKoLuiG6RXgoZ4sllseuGioszumnPGmPM2O7qaAX/IJdeDU8f26Aw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm64-musl": {
+      "version": "4.22.4",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.4.tgz",
+      "integrity": "sha512-Gl0AxBtDg8uoAn5CCqQDMqAx22Wx22pjDOjBdmG0VIWX3qUBHzYmOKh8KXHL4UpogfJ14G4wk16EQogF+v8hmA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
+      "version": "4.22.4",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.4.tgz",
+      "integrity": "sha512-3aVCK9xfWW1oGQpTsYJJPF6bfpWfhbRnhdlyhak2ZiyFLDaayz0EP5j9V1RVLAAxlmWKTDfS9wyRyY3hvhPoOg==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+      "version": "4.22.4",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.4.tgz",
+      "integrity": "sha512-ePYIir6VYnhgv2C5Xe9u+ico4t8sZWXschR6fMgoPUK31yQu7hTEJb7bCqivHECwIClJfKgE7zYsh1qTP3WHUA==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-s390x-gnu": {
+      "version": "4.22.4",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.4.tgz",
+      "integrity": "sha512-GqFJ9wLlbB9daxhVlrTe61vJtEY99/xB3C8e4ULVsVfflcpmR6c8UZXjtkMA6FhNONhj2eA5Tk9uAVw5orEs4Q==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
     "node_modules/@rollup/rollup-linux-x64-gnu": {
-      "version": "4.9.6",
+      "version": "4.22.4",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.4.tgz",
+      "integrity": "sha512-87v0ol2sH9GE3cLQLNEy0K/R0pz1nvg76o8M5nhMR0+Q+BBGLnb35P0fVz4CQxHYXaAOhE8HhlkaZfsdUOlHwg==",
       "cpu": [
         "x64"
       ],
       "dev": true,
-      "license": "MIT",
       "optional": true,
       "os": [
         "linux"
       ]
     },
     "node_modules/@rollup/rollup-linux-x64-musl": {
-      "version": "4.9.6",
+      "version": "4.22.4",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.4.tgz",
+      "integrity": "sha512-UV6FZMUgePDZrFjrNGIWzDo/vABebuXBhJEqrHxrGiU6HikPy0Z3LfdtciIttEUQfuDdCn8fqh7wiFJjCNwO+g==",
       "cpu": [
         "x64"
       ],
       "dev": true,
-      "license": "MIT",
       "optional": true,
       "os": [
         "linux"
       ]
     },
+    "node_modules/@rollup/rollup-win32-arm64-msvc": {
+      "version": "4.22.4",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.4.tgz",
+      "integrity": "sha512-BjI+NVVEGAXjGWYHz/vv0pBqfGoUH0IGZ0cICTn7kB9PyjrATSkX+8WkguNjWoj2qSr1im/+tTGRaY+4/PdcQw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-ia32-msvc": {
+      "version": "4.22.4",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.4.tgz",
+      "integrity": "sha512-SiWG/1TuUdPvYmzmYnmd3IEifzR61Tragkbx9D3+R8mzQqDBz8v+BvZNDlkiTtI9T15KYZhP0ehn3Dld4n9J5g==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-x64-msvc": {
+      "version": "4.22.4",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.4.tgz",
+      "integrity": "sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
     "node_modules/@types/estree": {
       "version": "1.0.5",
       "dev": true,
@@ -463,11 +1000,12 @@
       }
     },
     "node_modules/braces": {
-      "version": "3.0.2",
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+      "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
       "dev": true,
-      "license": "MIT",
       "dependencies": {
-        "fill-range": "^7.0.1"
+        "fill-range": "^7.1.1"
       },
       "engines": {
         "node": ">=8"
@@ -566,10 +1104,11 @@
       }
     },
     "node_modules/esbuild": {
-      "version": "0.19.12",
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
+      "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
       "dev": true,
       "hasInstallScript": true,
-      "license": "MIT",
       "bin": {
         "esbuild": "bin/esbuild"
       },
@@ -577,29 +1116,29 @@
         "node": ">=12"
       },
       "optionalDependencies": {
-        "@esbuild/aix-ppc64": "0.19.12",
-        "@esbuild/android-arm": "0.19.12",
-        "@esbuild/android-arm64": "0.19.12",
-        "@esbuild/android-x64": "0.19.12",
-        "@esbuild/darwin-arm64": "0.19.12",
-        "@esbuild/darwin-x64": "0.19.12",
-        "@esbuild/freebsd-arm64": "0.19.12",
-        "@esbuild/freebsd-x64": "0.19.12",
-        "@esbuild/linux-arm": "0.19.12",
-        "@esbuild/linux-arm64": "0.19.12",
-        "@esbuild/linux-ia32": "0.19.12",
-        "@esbuild/linux-loong64": "0.19.12",
-        "@esbuild/linux-mips64el": "0.19.12",
-        "@esbuild/linux-ppc64": "0.19.12",
-        "@esbuild/linux-riscv64": "0.19.12",
-        "@esbuild/linux-s390x": "0.19.12",
-        "@esbuild/linux-x64": "0.19.12",
-        "@esbuild/netbsd-x64": "0.19.12",
-        "@esbuild/openbsd-x64": "0.19.12",
-        "@esbuild/sunos-x64": "0.19.12",
-        "@esbuild/win32-arm64": "0.19.12",
-        "@esbuild/win32-ia32": "0.19.12",
-        "@esbuild/win32-x64": "0.19.12"
+        "@esbuild/aix-ppc64": "0.21.5",
+        "@esbuild/android-arm": "0.21.5",
+        "@esbuild/android-arm64": "0.21.5",
+        "@esbuild/android-x64": "0.21.5",
+        "@esbuild/darwin-arm64": "0.21.5",
+        "@esbuild/darwin-x64": "0.21.5",
+        "@esbuild/freebsd-arm64": "0.21.5",
+        "@esbuild/freebsd-x64": "0.21.5",
+        "@esbuild/linux-arm": "0.21.5",
+        "@esbuild/linux-arm64": "0.21.5",
+        "@esbuild/linux-ia32": "0.21.5",
+        "@esbuild/linux-loong64": "0.21.5",
+        "@esbuild/linux-mips64el": "0.21.5",
+        "@esbuild/linux-ppc64": "0.21.5",
+        "@esbuild/linux-riscv64": "0.21.5",
+        "@esbuild/linux-s390x": "0.21.5",
+        "@esbuild/linux-x64": "0.21.5",
+        "@esbuild/netbsd-x64": "0.21.5",
+        "@esbuild/openbsd-x64": "0.21.5",
+        "@esbuild/sunos-x64": "0.21.5",
+        "@esbuild/win32-arm64": "0.21.5",
+        "@esbuild/win32-ia32": "0.21.5",
+        "@esbuild/win32-x64": "0.21.5"
       }
     },
     "node_modules/estree-walker": {
@@ -634,9 +1173,10 @@
       }
     },
     "node_modules/fill-range": {
-      "version": "7.0.1",
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+      "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
       "dev": true,
-      "license": "MIT",
       "dependencies": {
         "to-regex-range": "^5.0.1"
       },
@@ -649,6 +1189,20 @@
       "dev": true,
       "license": "ISC"
     },
+    "node_modules/fsevents": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+      "dev": true,
+      "hasInstallScript": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
     "node_modules/get-func-name": {
       "version": "2.0.2",
       "dev": true,
@@ -786,8 +1340,9 @@
     },
     "node_modules/is-number": {
       "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
       "dev": true,
-      "license": "MIT",
       "engines": {
         "node": ">=0.12.0"
       }
@@ -990,6 +1545,8 @@
     },
     "node_modules/nanoid": {
       "version": "3.3.7",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
+      "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
       "dev": true,
       "funding": [
         {
@@ -997,7 +1554,6 @@
           "url": "https://github.com/sponsors/ai"
         }
       ],
-      "license": "MIT",
       "bin": {
         "nanoid": "bin/nanoid.cjs"
       },
@@ -1051,9 +1607,10 @@
       }
     },
     "node_modules/picocolors": {
-      "version": "1.0.0",
-      "dev": true,
-      "license": "ISC"
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
+      "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==",
+      "dev": true
     },
     "node_modules/picomatch": {
       "version": "2.3.1",
@@ -1077,7 +1634,9 @@
       }
     },
     "node_modules/postcss": {
-      "version": "8.4.33",
+      "version": "8.4.47",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
+      "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
       "dev": true,
       "funding": [
         {
@@ -1093,11 +1652,10 @@
           "url": "https://github.com/sponsors/ai"
         }
       ],
-      "license": "MIT",
       "dependencies": {
         "nanoid": "^3.3.7",
-        "picocolors": "^1.0.0",
-        "source-map-js": "^1.0.2"
+        "picocolors": "^1.1.0",
+        "source-map-js": "^1.2.1"
       },
       "engines": {
         "node": "^10 || ^12 || >=14"
@@ -1151,9 +1709,10 @@
       }
     },
     "node_modules/rollup": {
-      "version": "4.9.6",
+      "version": "4.22.4",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.4.tgz",
+      "integrity": "sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A==",
       "dev": true,
-      "license": "MIT",
       "dependencies": {
         "@types/estree": "1.0.5"
       },
@@ -1165,19 +1724,22 @@
         "npm": ">=8.0.0"
       },
       "optionalDependencies": {
-        "@rollup/rollup-android-arm-eabi": "4.9.6",
-        "@rollup/rollup-android-arm64": "4.9.6",
-        "@rollup/rollup-darwin-arm64": "4.9.6",
-        "@rollup/rollup-darwin-x64": "4.9.6",
-        "@rollup/rollup-linux-arm-gnueabihf": "4.9.6",
-        "@rollup/rollup-linux-arm64-gnu": "4.9.6",
-        "@rollup/rollup-linux-arm64-musl": "4.9.6",
-        "@rollup/rollup-linux-riscv64-gnu": "4.9.6",
-        "@rollup/rollup-linux-x64-gnu": "4.9.6",
-        "@rollup/rollup-linux-x64-musl": "4.9.6",
-        "@rollup/rollup-win32-arm64-msvc": "4.9.6",
-        "@rollup/rollup-win32-ia32-msvc": "4.9.6",
-        "@rollup/rollup-win32-x64-msvc": "4.9.6",
+        "@rollup/rollup-android-arm-eabi": "4.22.4",
+        "@rollup/rollup-android-arm64": "4.22.4",
+        "@rollup/rollup-darwin-arm64": "4.22.4",
+        "@rollup/rollup-darwin-x64": "4.22.4",
+        "@rollup/rollup-linux-arm-gnueabihf": "4.22.4",
+        "@rollup/rollup-linux-arm-musleabihf": "4.22.4",
+        "@rollup/rollup-linux-arm64-gnu": "4.22.4",
+        "@rollup/rollup-linux-arm64-musl": "4.22.4",
+        "@rollup/rollup-linux-powerpc64le-gnu": "4.22.4",
+        "@rollup/rollup-linux-riscv64-gnu": "4.22.4",
+        "@rollup/rollup-linux-s390x-gnu": "4.22.4",
+        "@rollup/rollup-linux-x64-gnu": "4.22.4",
+        "@rollup/rollup-linux-x64-musl": "4.22.4",
+        "@rollup/rollup-win32-arm64-msvc": "4.22.4",
+        "@rollup/rollup-win32-ia32-msvc": "4.22.4",
+        "@rollup/rollup-win32-x64-msvc": "4.22.4",
         "fsevents": "~2.3.2"
       }
     },
@@ -1236,9 +1798,10 @@
       }
     },
     "node_modules/source-map-js": {
-      "version": "1.0.2",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+      "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
       "dev": true,
-      "license": "BSD-3-Clause",
       "engines": {
         "node": ">=0.10.0"
       }
@@ -1319,8 +1882,9 @@
     },
     "node_modules/to-regex-range": {
       "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
       "dev": true,
-      "license": "MIT",
       "dependencies": {
         "is-number": "^7.0.0"
       },
@@ -1367,13 +1931,14 @@
       "license": "MIT"
     },
     "node_modules/vite": {
-      "version": "5.0.12",
+      "version": "5.4.8",
+      "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz",
+      "integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==",
       "dev": true,
-      "license": "MIT",
       "dependencies": {
-        "esbuild": "^0.19.3",
-        "postcss": "^8.4.32",
-        "rollup": "^4.2.0"
+        "esbuild": "^0.21.3",
+        "postcss": "^8.4.43",
+        "rollup": "^4.20.0"
       },
       "bin": {
         "vite": "bin/vite.js"
@@ -1392,6 +1957,7 @@
         "less": "*",
         "lightningcss": "^1.21.0",
         "sass": "*",
+        "sass-embedded": "*",
         "stylus": "*",
         "sugarss": "*",
         "terser": "^5.4.0"
@@ -1409,6 +1975,9 @@
         "sass": {
           "optional": true
         },
+        "sass-embedded": {
+          "optional": true
+        },
         "stylus": {
           "optional": true
         },
