diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
new file mode 100644
index 0000000..622c644
--- /dev/null
+++ b/.github/workflows/codeql.yml
@@ -0,0 +1,91 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+#
+# ******** NOTE ********
+# We have attempted to detect the languages in your repository. Please check
+# the `language` matrix defined below to confirm you have the correct set of
+# supported CodeQL languages.
+#
+name: "CodeQL"
+
+on:
+ # push:
+ # branches: [ "main" ]
+ # pull_request:
+ # branches: [ "main" ]
+ schedule:
+ - cron: '26 2 * * 6'
+
+jobs:
+ analyze:
+ name: Analyze (${{ matrix.language }})
+ # Runner size impacts CodeQL analysis time. To learn more, please see:
+ # - https://gh.io/recommended-hardware-resources-for-running-codeql
+ # - https://gh.io/supported-runners-and-hardware-resources
+ # - https://gh.io/using-larger-runners (GitHub.com only)
+ # Consider using larger runners or machines with greater resources for possible analysis time improvements.
+ runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
+ timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
+ permissions:
+ # required for all workflows
+ security-events: write
+
+ # required to fetch internal or private CodeQL packs
+ packages: read
+
+ # only required for workflows in private repositories
+ actions: read
+ contents: read
+
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
+ # Use `c-cpp` to analyze code written in C, C++ or both
+ # Use 'java-kotlin' to analyze code written in Java, Kotlin or both
+ # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
+ # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
+ # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
+ # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
+ # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v3
+ with:
+ languages: ${{ matrix.language }}
+ build-mode: ${{ matrix.build-mode }}
+ # If you wish to specify custom queries, you can do so here or in a config file.
+ # By default, queries listed here will override any specified in a config file.
+ # Prefix the list here with "+" to use these queries and those in the config file.
+
+ # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
+ # queries: security-extended,security-and-quality
+
+ # If the analyze step fails for one of the languages you are analyzing with
+ # "We were unable to automatically build your code", modify the matrix above
+ # to set the build mode to "manual" for that language. Then modify this step
+ # to build your code.
+ # âšī¸ Command-line programs to run using the OS shell.
+ # đ See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
+ - if: matrix.build-mode == 'manual'
+ shell: bash
+ run: |
+ echo 'If you are using a "manual" build mode for one or more of the' \
+ 'languages you are analyzing, replace this with the commands to build' \
+ 'your code, for example:'
+ echo ' make bootstrap'
+ echo ' make release'
+ exit 1
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v3
+ with:
+ category: "/language:${{matrix.language}}"
diff --git a/.github/workflows/maven-publish.yml b/.github/workflows/maven-publish.yml
new file mode 100644
index 0000000..954e6c8
--- /dev/null
+++ b/.github/workflows/maven-publish.yml
@@ -0,0 +1,34 @@
+# This workflow will build a package using Maven and then publish it to GitHub packages when a release is created
+# For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#apache-maven-with-a-settings-path
+
+name: Maven Package
+
+on:
+ release:
+ types: [created]
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ packages: write
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Set up JDK 11
+ uses: actions/setup-java@v3
+ with:
+ java-version: '11'
+ distribution: 'temurin'
+ server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
+ settings-path: ${{ github.workspace }} # location for the settings.xml file
+
+ - name: Build with Maven
+ run: mvn -B package --file pom.xml
+
+ - name: Publish to GitHub Packages Apache Maven
+ run: mvn deploy -s $GITHUB_WORKSPACE/settings.xml
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
new file mode 100644
index 0000000..857c099
--- /dev/null
+++ b/.github/workflows/maven.yml
@@ -0,0 +1,37 @@
+# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
+# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven
+
+# This workflow uses actions that are not certified by GitHub.
+# They are provided by a third-party and are governed by
+# separate terms of service, privacy policy, and support
+# documentation.
+
+name: Java CI with Maven
+
+on:
+ push:
+ branches: [ "main" ]
+ pull_request:
+ branches: [ "main" ]
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Set up JDK 20
+ uses: actions/setup-java@v3
+ with:
+ java-version: '20'
+ distribution: 'temurin'
+ cache: maven
+ - name: Build with Maven
+ run: |
+ cd primekit-essentials
+ mvn -B clean package -DskipTests
+
+ # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive
+ #- name: Update dependency graph
+ # uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6
diff --git a/README.md b/README.md
index de62dc2..8e1abb0 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,43 @@
# PrimeKit
+
+[![StackShare](http://img.shields.io/badge/tech-stack-0690fa.svg?style=flat)](https://stackshare.io/shortthirdman-org/prime-kit)
+
PrimeKit
+
+## PrimeKit Essentials
+
+A Java common library
+
+![Github Created At](https://img.shields.io/github/created-at/shortthirdman-org/PrimeKit?logo=github&label=shortthirdman-org%2FPrimeKit&link=https%3A%2F%2Fgithub.com%2Fshortthirdman-org%2FPrimeKit)
+![GitHub language count](https://img.shields.io/github/languages/count/shortthirdman-org/PrimeKit)
+![GitHub commits since latest release](https://img.shields.io/github/commits-since/shortthirdman-org/PrimeKit/latest)
+
+![GitHub](https://img.shields.io/github/license/shortthirdman-org/PrimeKit)
+![GitHub issues](https://img.shields.io/github/issues/shortthirdman-org/PrimeKit)
+![GitHub closed issues](https://img.shields.io/github/issues-closed/shortthirdman-org/PrimeKit)
+![GitHub Workflow Status (with event and branch)](https://img.shields.io/github/actions/workflow/status/shortthirdman-org/PrimeKit/release.yml?event=push&branch=main)
+
+## Tech Stack
+
+shortthirdman-org/PrimeKit is built on the following main stack:
+
+
+
+Full tech stack [here](/techstack.md)
+
+
+## Community Resources
+
+* [Release a Java Module with JReleaser to Maven Central with GitHub Actions](https://foojay.io/today/how-to-release-a-java-module-with-jreleaser-to-maven-central-with-github-actions/)
+* [Publish a Java Maven Project to the Maven Central Repository](https://foojay.io/today/how-to-publish-a-java-maven-project-to-the-maven-central-repository/)
+* [Publish Artifacts to Maven Central](https://www.jetbrains.com/help/space/publish-artifacts-to-maven-central.html)
+
+
+## Reference Documentation
+For further reference, please consider the following sections:
+
+* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html)
+* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/3.2.6/maven-plugin/reference/html/)
+* [Create an OCI image](https://docs.spring.io/spring-boot/docs/3.2.6/maven-plugin/reference/html/#build-image)
+* [Spring Shell](https://spring.io/projects/spring-shell)
+
diff --git a/pom-default.xml b/pom-default.xml
new file mode 100644
index 0000000..33ffa10
--- /dev/null
+++ b/pom-default.xml
@@ -0,0 +1,291 @@
+
+
+
{
+
+ Q convert(P input, @Nullable Object... options) throws Exception;
+}
diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToBooleanConverter.java b/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToBooleanConverter.java
new file mode 100644
index 0000000..514161f
--- /dev/null
+++ b/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToBooleanConverter.java
@@ -0,0 +1,25 @@
+package com.shortthirdman.primekit.essentials.common.converter;
+
+import jakarta.annotation.Nullable;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+@Component
+public class StringToBooleanConverter implements Converter> levelOrderTraversal(TreeNode root) {
+ List
> result = new ArrayList<>();
+
+ if (root == null) {
+ return result;
+ }
+
+ LinkedList
> verticalOrderTraversal(TreeNode root) {
+ TreeMap
> result = new ArrayList<>(map.values());
+
+ return result;
+ }
+
+ /**
+ * @see @verticalOrderTraversal
+ * @param root
+ * @return
+ */
+ public static List
> verticalOrder(TreeNode root) {
+ List
> result = new ArrayList<>();
+ if (root == null) {
+ return result;
+ }
+
+ int[] mm = new int[2];
+ getMinMax(root, mm, 0);
+
+ int len = mm[1] - mm[0] + 1;
+
+ for (int i = 0; i < len; i++) {
+ result.add(new ArrayList<>());
+ }
+
+ LinkedList
> findLeaves(TreeNode root) {
+ HashMap
> result = new ArrayList<>();
+ for (int i = min; i <= max; i++) {
+ HashSet
+ * The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.
+ * @param root the root node os bincry tree
+ * @return the maximum depth
+ */
+ public static int maxDepth(TreeNode root) {
+ if (root == null) {
+ return 0;
+ }
+
+ int leftDepth = maxDepth(root.getLeftNode());
+ int rightDepth = maxDepth(root.getRightNode());
+
+ int bigger = Math.max(leftDepth, rightDepth);
+
+ return bigger + 1;
+ }
+
+ /**
+ * Given a binary tree, find its minimum depth.
+ * The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.
+ *
+ * @param root the root node of binary tree
+ * @return minimum depth of binary tree
+ */
+ public static int minDepth(TreeNode root) {
+ if (root == null) {
+ return 0;
+ }
+
+ LinkedList
+ * Recursively traverse down the root. When target is less than root, go left; when target is greater than root, go right.
+ *
+ * @param rootNode the root node of binary tree
+ * @param target the target value to search for
+ * @return the closest value to target
+ */
+ public static int closestValue(TreeNode rootNode, double target) {
+ double min = Double.MAX_VALUE;
+ int result = rootNode.getValue();
+
+ while (rootNode != null) {
+ if (target > rootNode.getValue()) {
+ double diff = Math.abs(rootNode.getValue() - target);
+
+ if (diff < min) {
+ min = Math.min(min, diff);
+ result = rootNode.getValue();
+ }
+
+ rootNode = rootNode.getRightNode();
+ } else if (target < rootNode.getValue()) {
+ double diff = Math.abs(rootNode.getValue() - target);
+
+ if (diff < min) {
+ min = Math.min(min, diff);
+ result = rootNode.getValue();
+ }
+
+ rootNode = rootNode.getLeftNode();
+ } else {
+ return rootNode.getValue();
+ }
+ }
+
+ return result;
+ }
+
+ public static boolean isValidBST(TreeNode root) {
+ return isValidBST(root, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
+ }
+
+ public static boolean isValidBST(TreeNode p, double min, double max){
+ if (p == null) {
+ return true;
+ }
+
+ if (p.getValue() <= min || p.getValue() >= max) {
+ return false;
+ }
+
+ return isValidBST(p.getLeftNode(), min, p.getValue()) && isValidBST(p.getRightNode(), p.getValue(), max);
+ }
+
+ /**
+ * For a undirected graph with tree characteristics, we can choose any node as the root.
+ * The result graph is then a rooted tree. Among all possible rooted trees, those with minimum height are called minimum height trees (MHTs).
+ *
+ * Given such a graph, write a function to find all the MHTs and return a list of their root labels.
+ * The graph contains n nodes which are labeled from 0 to n - 1. You will be given the number n and a list of undirected edges (each edge is a pair of labels).
+ *
+ * @param n the number of the nodes
+ * @param edges the edges of the tree
+ * @return list of their root labels/edges
+ */
+ public static List
+ *
+ *
+ * @param resourceName The name of the resource to load
+ * @param caller The Class object of the calling object
+ */
+ public static URL getResource(String resourceName, Class> caller) {
+ URL url = Thread.currentThread().getContextClassLoader().getResource(resourceName);
+
+ if (url == null) {
+ url = ClassUtils.class.getClassLoader().getResource(resourceName);
+ }
+
+ if (url == null) {
+ url = caller.getClassLoader().getResource(resourceName);
+ }
+
+ return url;
+ }
+
+ /**
+ * This is a convenience method to load a resource as a stream.
+ *
+ * The algorithm used to find the resource is given in getResource()
+ *
+ * @param resourceName The name of the resource to load
+ * @param caller The Class object of the calling object
+ */
+ public static InputStream getResourceAsStream(String resourceName, Class> caller) {
+ URL url = getResource(resourceName, caller);
+ try {
+ return (url != null) ? url.openStream() : null;
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Load a class with a given name.
+ *
+ * It will try to load the class in the following order:
+ *
+ *
+ *
+ * @param className The name of the class to load
+ * @param caller The Class object of the calling object
+ * @throws ClassNotFoundException If the class cannot be found anywhere.
+ */
+ public static Class> loadClass(String className, Class> caller) throws ClassNotFoundException {
+ try {
+ return Thread.currentThread().getContextClassLoader().loadClass(className);
+ } catch (ClassNotFoundException e) {
+ try {
+ return Class.forName(className);
+ } catch (ClassNotFoundException ex) {
+ try {
+ return ClassUtils.class.getClassLoader().loadClass(className);
+ } catch (ClassNotFoundException cnfe) {
+ return caller.getClassLoader().loadClass(className);
+ }
+ }
+ }
+ }
+}
diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/CollectionUtils.java b/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/CollectionUtils.java
new file mode 100644
index 0000000..b4ee147
--- /dev/null
+++ b/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/CollectionUtils.java
@@ -0,0 +1,135 @@
+package com.shortthirdman.primekit.essentials.common.util;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+public final class CollectionUtils {
+
+ private CollectionUtils() {
+ }
+
+ /**
+ * Converts a array of elements into list
+ *
+ * @param array the typed array
+ * @return list of elements
+ */
+ public static , Boolean> seen = new ConcurrentHashMap<>();
+
+ return t ->
+ {
+ final List> keys = Arrays.stream(keyExtractors)
+ .map(ke -> ke.apply(t))
+ .collect(Collectors.toList());
+
+ return seen.putIfAbsent(keys, Boolean.TRUE) == null;
+ };
+ }
+
+ /**
+ * @param map the input map of
+ * Two strings are isomorphic if the characters in source can be replaced to get target.
+ *
+ * @param s the source text
+ * @param t the target text
+ * @return true if two given strings are isomorphic
+ */
+ public boolean isIsomorphic(String s, String t) {
+ if (s.length() != t.length()) {
+ return false;
+ }
+
+ Map