feat: prepare Radixor 3.0.0 with contracted tries and compiled patch commands

Introduce contracted compiled patch tries for faster lookup, make compiled
patch commands the primary runtime path, refresh stemmer benchmarks and
documentation, and restructure the documentation for 3.0.0 onboarding.

BREAKING CHANGE: Radixor 3.0.0 promotes compiled patch-command APIs and
new compiled trie artifacts as the primary runtime integration model.
This commit is contained in:
2026-07-03 18:44:39 +02:00
parent df4552b113
commit 38620d7e71
101 changed files with 11235 additions and 727 deletions

View File

@@ -0,0 +1,223 @@
import org.gradle.plugins.ide.eclipse.model.SourceFolder
def luceneVersion = '10.5.0'
def luceneRootRelativePath = 'third-party/lucene'
def luceneSourceArtifacts = ['lucene-analysis-common', 'lucene-analyzers-common']
def luceneSourceDirectory = layout.buildDirectory.dir("${luceneRootRelativePath}/source/analyzers-common")
def luceneGeneratedSourceDirectory = layout.buildDirectory.dir('generated/sources/lucene')
def luceneGeneratedPorterFile = luceneGeneratedSourceDirectory.map { it.file('org/egothor/stemmer/benchmark/LucenePorterStemmerCopied.java') }
def luceneSourceDownloadFile = layout.buildDirectory.file("${luceneRootRelativePath}/lucene-${luceneVersion}-sources.jar")
dependencies {
jmhImplementation "org.apache.lucene:lucene-analysis-common:${luceneVersion}"
jmhImplementation "org.apache.lucene:lucene-analysis-stempel:${luceneVersion}"
jmhImplementation "org.apache.lucene:lucene-analysis-morfologik:${luceneVersion}"
}
def buildLuceneSourcesName = { final String artifact ->
"${artifact}-${luceneVersion}-sources.jar"
}
def buildLuceneSourcesUrl = { final String artifact ->
"https://repo1.maven.org/maven2/org/apache/lucene/${artifact}/${luceneVersion}/${buildLuceneSourcesName(artifact)}"
}
def isLuceneSourcesDownloadable = { final String artifact ->
try {
final URL sourceUrl = new URL(buildLuceneSourcesUrl(artifact))
final java.net.HttpURLConnection connection = (java.net.HttpURLConnection) sourceUrl.openConnection()
connection.requestMethod = 'HEAD'
connection.instanceFollowRedirects = true
connection.connectTimeout = 10000
connection.readTimeout = 10000
final int responseCode = connection.responseCode
connection.disconnect()
return responseCode == 200
} catch (Exception ignored) {
return false
}
}
def downloadLuceneSourcesJar = { ->
final File targetFile = luceneSourceDownloadFile.get().asFile
for (String artifact : luceneSourceArtifacts) {
if (!isLuceneSourcesDownloadable(artifact)) {
continue
}
final String sourceUrl = buildLuceneSourcesUrl(artifact)
final File tempFile = new File(targetFile.parentFile, "${artifact}.${luceneVersion}.tmp")
try {
new URL(sourceUrl).withInputStream { inputStream ->
tempFile.parentFile.mkdirs()
tempFile.withOutputStream { outputStream ->
outputStream << inputStream
}
}
if (!tempFile.exists() || tempFile.length() <= 0L) {
throw new GradleException("Downloaded Lucene source artifact for ${artifact} was empty.")
}
targetFile.delete()
if (!tempFile.renameTo(targetFile)) {
throw new GradleException("Failed to persist downloaded Lucene source artifact for ${artifact}.")
}
return
} catch (Exception ignored) {
tempFile.delete()
}
}
throw new GradleException(
"Failed to download Apache Lucene source artifacts ${luceneSourceArtifacts} for version ${luceneVersion}.")
}
def luceneSourceClasspathPath = provider {
project.relativePath(luceneGeneratedSourceDirectory.get().asFile)
}
def luceneEclipseClasspathAttributes = [
gradle_scope : 'jmh',
gradle_used_by_scope: 'jmh',
test : 'true'
]
def isAbsoluteClasspathPath = { String path ->
path.startsWith('/') || path ==~ /^[A-Za-z]:[\\\/].*/
}
def luceneGeneratedPorterNotice = '''
/**
* Generated at benchmark execution time from Apache Lucene source.
*
* This source copy is compiled only for the JMH benchmark source set and is
* not committed as production code.
*/
'''
def transformPorterStemmerSource = { final File sourceFile, final File targetFile ->
if (!sourceFile.exists()) {
throw new GradleException("Apache Lucene PorterStemmer source was not available at ${sourceFile}.")
}
final String sourceText = sourceFile.getText('UTF-8')
String transformedText = sourceText
if (transformedText.contains('package org.apache.lucene.analysis.en;')) {
transformedText = transformedText.replaceFirst(/(?m)^\s*package\s+org\.apache\.lucene\.analysis\.en\s*;/,
'package org.egothor.stemmer.benchmark;')
} else {
throw new GradleException(
'Expected Lucene package-private PorterStemmer in org.apache.lucene.analysis.en package was not found in downloaded source.')
}
transformedText = transformedText.replaceFirst(/(?m)^\s*class\s+PorterStemmer\s*\{/, 'public final class LucenePorterStemmerCopied {')
transformedText = transformedText.replaceFirst(/(?m)^\s*public\s+PorterStemmer\(\)/, 'public LucenePorterStemmerCopied()')
if (!transformedText.contains('class LucenePorterStemmerCopied')) {
throw new GradleException("Failed to rename PorterStemmer class when generating ${targetFile}.")
}
targetFile.parentFile.mkdirs()
targetFile.text = transformedText
}
def resolveLucenePorterStemmerSource = { ->
final File sourceRoot = luceneSourceDirectory.get().asFile
final List<String> candidates = [
'org/apache/lucene/analysis/en/org/apache/lucene/analysis/en/PorterStemmer.java',
'org/apache/lucene/analysis/en/PorterStemmer.java',
'org/apache/lucene/analysis/en/org/tartarus/snowball/ext/PorterStemmer.java'
]
for (String candidate : candidates) {
final File file = new File(sourceRoot, candidate)
if (file.exists()) {
return file
}
}
final FileTree porterCandidates = fileTree(sourceRoot).matching { include '**/PorterStemmer.java' }
for (File file : porterCandidates.files) {
if (file.text.contains('class PorterStemmer') && file.text.contains('package org.apache.lucene.analysis.en;')) {
return file
}
}
throw new GradleException('Unable to resolve Lucene PorterStemmer source file from extracted artifact.')
}
tasks.register('downloadLuceneAnalyzersSources') {
group = 'build setup'
description = 'Downloads Apache Lucene analysis sources for benchmark-only code generation.'
outputs.file(luceneSourceDownloadFile)
doLast {
if (!luceneSourceDownloadFile.get().asFile.exists()) {
downloadLuceneSourcesJar()
}
}
}
tasks.register('extractLuceneAnalyzersSources', Copy) {
group = 'build setup'
description = 'Extracts Apache Lucene analysis source JAR for benchmark-only extraction.'
dependsOn(tasks.named('downloadLuceneAnalyzersSources'))
from(zipTree(luceneSourceDownloadFile))
into(luceneSourceDirectory)
}
tasks.register('generateLucenePorterStemmerCopied') {
group = 'build setup'
description = 'Generates LucenePorterStemmerCopied into the build-only benchmark source directory.'
dependsOn(tasks.named('extractLuceneAnalyzersSources'))
inputs.dir(luceneSourceDirectory)
outputs.file(luceneGeneratedPorterFile)
doLast {
final File sourceFile = resolveLucenePorterStemmerSource()
transformPorterStemmerSource(sourceFile, luceneGeneratedPorterFile.get().asFile)
}
}
sourceSets {
jmh {
java {
srcDir(luceneGeneratedSourceDirectory)
}
}
}
tasks.named('compileJmhJava') {
dependsOn(tasks.named('generateLucenePorterStemmerCopied'))
}
eclipse {
classpath {
file {
whenMerged { classpath ->
String generatedPath = luceneSourceClasspathPath.get()
classpath.entries.removeAll { entry ->
entry.hasProperty('path') && (
entry.path == generatedPath ||
isAbsoluteClasspathPath(entry.path)
)
}
SourceFolder luceneEntry = new SourceFolder(generatedPath, null)
luceneEntry.output = 'bin/jmh'
luceneEclipseClasspathAttributes.each { String name, String value ->
luceneEntry.entryAttributes[name] = value
}
classpath.entries.add(luceneEntry)
}
}
}
}

View File

@@ -0,0 +1,5 @@
def openNlpVersion = '2.5.4'
dependencies {
jmhImplementation "org.apache.opennlp:opennlp-tools:${openNlpVersion}"
}

View File

@@ -0,0 +1,219 @@
import org.gradle.plugins.ide.eclipse.model.SourceFolder
def paicehuskVersion = 'master'
def paicehuskArchiveName = "paice-husk-stemmer-${paicehuskVersion}.zip"
def paicehuskDownloadUrl = "https://github.com/Hopper262/paice-husk-stemmer/archive/refs/heads/${paicehuskVersion}.zip"
def paicehuskDownloadFile = layout.buildDirectory.file("third-party/paicehusk/${paicehuskArchiveName}")
def paicehuskExtractDirectory = layout.buildDirectory.dir('third-party/paicehusk/source')
def paicehuskArchiveDirectory = paicehuskExtractDirectory.map { it.dir('paice-husk-stemmer-master') }
def paicehuskJavaFile = paicehuskArchiveDirectory.map { it.file('paicehusk_java.java') }
def paicehuskRulesFile = paicehuskArchiveDirectory.map { it.file('paicehusk_rules.txt') }
def paicehuskGeneratedSourceDirectory = layout.buildDirectory.dir('generated/sources/paicehusk')
def paicehuskGeneratedStemmerFile = paicehuskGeneratedSourceDirectory.map { it.file('org/egothor/stemmer/benchmark/PaiceHuskLancasterStemmer.java') }
def paicehuskGeneratedSourcePath = provider {
project.relativePath(paicehuskGeneratedSourceDirectory.get().asFile)
}
def paicehuskSourceEclipseClasspathAttributes = [
gradle_scope : 'jmh',
gradle_used_by_scope: 'jmh',
test : 'true'
]
def paicehuskIsAbsolutePath = { String path ->
path.startsWith('/') || path ==~ /^[A-Za-z]:[\\\/].*/
}
def paicehuskGeneratedNotice = '''
/**
* Generated at benchmark execution time from upstream
* https://github.com/Hopper262/paice-husk-stemmer .
*
* This source copy is compiled only for the JMH benchmark source set and is
* not committed as production code.
*/
'''
def escapeForJava = { final String text ->
return text.replace('\\\\', '\\\\\\\\')
.replace('\"', '\\\"')
}
def toRuleLines = { final File rulesFile ->
final List<String> lines = rulesFile.readLines('UTF-8')
final StringBuilder ruleLines = new StringBuilder()
for (int index = 0; index < lines.size(); index++) {
final String line = lines.get(index)
ruleLines.append(' "')
ruleLines.append(escapeForJava(line))
ruleLines.append('"')
if (index < lines.size() - 1) {
ruleLines.append(',')
}
ruleLines.append('\n')
}
return ruleLines.toString()
}
def paicehuskEngineInsertion = { final String ruleLines ->
return """
public static final String[] RULE_LINES = {
${ruleLines}
};
private static final java.util.HashMap RULES = createRulesFromEmbeddedRules();
/**
* Creates benchmark stemmer instance.
*/
public PaiceHuskLancasterStemmer() {
}
/**
* Applies Paice/Husk stemming to one token.
*
* @param token input token
* @return stemmed token
*/
public String stem(final String token) {
if (token == null) {
return null;
}
return stemWord(token, RULES, null);
}
/**
* Loads bundled rule lines directly from the generated benchmark source.
*
* @return initialized rule map
*/
private static java.util.HashMap createRulesFromEmbeddedRules() {
try {
final java.io.File ruleFile = java.io.File.createTempFile("paicehusk-rules", ".txt");
ruleFile.deleteOnExit();
try (java.io.PrintWriter writer = new java.io.PrintWriter(new java.io.FileWriter(ruleFile))) {
for (String line : RULE_LINES) {
writer.println(line);
}
}
return loadRules(ruleFile.getAbsolutePath());
} catch (Exception exception) {
throw new IllegalStateException("Unable to initialize benchmark Paice/Husk rules.", exception);
}
}
"""
}
def transformPaiceHuskSource = { final File sourceFile, final File rulesFile, final File targetFile ->
if (!sourceFile.exists()) {
throw new GradleException("Paice/Husk Java source was not available at ${sourceFile}.")
}
if (!rulesFile.exists()) {
throw new GradleException("Paice/Husk rule file was not available at ${rulesFile}.")
}
final String sourceText = sourceFile.getText('UTF-8')
String transformedText = sourceText
transformedText = 'package org.egothor.stemmer.benchmark;' + '\n\n' + transformedText
transformedText = transformedText.replaceFirst(/(?m)^\s*class\s+PaiceHusk\s*\{/, 'public final class PaiceHuskLancasterStemmer {')
final int packageEnd = transformedText.indexOf('\n', transformedText.indexOf('package org.egothor.stemmer.benchmark;'))
if (packageEnd >= 0) {
transformedText = transformedText.substring(0, packageEnd + 1) + '\n' + paicehuskGeneratedNotice + transformedText.substring(packageEnd + 1)
}
final String marker = '\n} // end class PaiceHusk'
final int markerIndex = transformedText.lastIndexOf(marker)
if (markerIndex < 0) {
throw new GradleException("Unexpected Paice/Husk source structure at ${sourceFile}.")
}
final String replacement = paicehuskEngineInsertion(toRuleLines(rulesFile))
transformedText = transformedText.substring(0, markerIndex) + '\n' + replacement + '\n}'
targetFile.parentFile.mkdirs()
targetFile.text = transformedText
}
tasks.register('downloadPaiceHuskStemmer') {
group = 'build setup'
description = 'Downloads the upstream Paice/Husk benchmark source for dynamic extraction.'
outputs.file(paicehuskDownloadFile)
doLast {
final File targetFile = paicehuskDownloadFile.get().asFile
targetFile.parentFile.mkdirs()
if (!targetFile.exists()) {
new URL(paicehuskDownloadUrl).withInputStream { inputStream ->
targetFile.withOutputStream { outputStream ->
outputStream << inputStream
}
}
}
}
}
tasks.register('extractPaiceHuskStemmer', Copy) {
group = 'build setup'
description = 'Extracts the upstream Paice/Husk benchmark archive.'
dependsOn(tasks.named('downloadPaiceHuskStemmer'))
from(zipTree(paicehuskDownloadFile))
into(paicehuskExtractDirectory)
}
tasks.register('generatePaiceHuskLancasterStemmer') {
group = 'build setup'
description = 'Generates PaiceHuskLancasterStemmer into a benchmark-only generated source directory.'
dependsOn(tasks.named('extractPaiceHuskStemmer'))
inputs.files(paicehuskJavaFile, paicehuskRulesFile)
outputs.file(paicehuskGeneratedStemmerFile)
doLast {
transformPaiceHuskSource(paicehuskJavaFile.get().asFile, paicehuskRulesFile.get().asFile, paicehuskGeneratedStemmerFile.get().asFile)
}
}
sourceSets {
jmh {
java {
srcDir(paicehuskGeneratedSourceDirectory)
}
}
}
tasks.named('compileJmhJava') {
dependsOn(tasks.named('generatePaiceHuskLancasterStemmer'))
}
eclipse {
classpath {
file {
whenMerged { classpath ->
String generatedPath = paicehuskGeneratedSourcePath.get()
classpath.entries.removeAll { entry ->
entry.hasProperty('path') && (
entry.path == generatedPath ||
paicehuskIsAbsolutePath(entry.path)
)
}
SourceFolder paicehuskEntry = new SourceFolder(generatedPath, null)
paicehuskEntry.output = 'bin/jmh'
paicehuskSourceEclipseClasspathAttributes.each { String name, String value ->
paicehuskEntry.entryAttributes[name] = value
}
classpath.entries.add(paicehuskEntry)
}
}
}
}

View File

@@ -7,13 +7,43 @@ def snowballDistributionDirectoryName = "libstemmer_java-${snowballVersion}"
def snowballRootRelativePath = 'third-party/snowball'
def snowballSourceRelativePath = "${snowballRootRelativePath}/source"
def snowballJavaSourceRelativePath = "${snowballSourceRelativePath}/${snowballDistributionDirectoryName}/java"
def snowballGeneratedSourceRelativePath = 'generated/sources/snowball'
def snowballDownloadUrl = "https://snowballstem.org/dist/${snowballArchiveName}"
def snowballDownloadFile = layout.buildDirectory.file("${snowballRootRelativePath}/${snowballArchiveName}")
def snowballExtractDirectory = layout.buildDirectory.dir(snowballSourceRelativePath)
def snowballJavaSourceDirectory = layout.buildDirectory.dir(snowballJavaSourceRelativePath)
def snowballGeneratedSourceDirectory = layout.buildDirectory.dir(snowballGeneratedSourceRelativePath)
def snowballJavaSourceClasspathPath = provider {
project.relativePath(snowballJavaSourceDirectory.get().asFile)
}
def snowballGeneratedSourceClasspathPath = provider {
project.relativePath(snowballGeneratedSourceDirectory.get().asFile)
}
def transformSnowballSourceText = { final String sourceText ->
String transformedText = sourceText
transformedText = transformedText.replaceAll(/(?m)^\s*package\s+org\.tartarus\.snowball\.ext\s*;/,
'package org.egothor.stemmer.benchmark.snowball.ext;')
transformedText = transformedText.replaceAll(/(?m)^\s*package\s+org\.tartarus\.snowball\s*;/,
'package org.egothor.stemmer.benchmark.snowball;')
transformedText = transformedText.replace('org.tartarus.snowball.', 'org.egothor.stemmer.benchmark.snowball.')
return transformedText
}
def copySnowballSourcesWithPackageIsolation = { final File sourceDirectory, final File targetDirectory ->
final FileTree sourceFiles = fileTree(sourceDirectory).matching { include '**/*.java' }
if (targetDirectory.exists()) {
targetDirectory.deleteDir()
}
for (File sourceFile : sourceFiles.files) {
final String relativePath = sourceDirectory.toPath().relativize(sourceFile.toPath()).toString()
final File outputFile = new File(targetDirectory, relativePath)
outputFile.parentFile.mkdirs()
outputFile.text = transformSnowballSourceText(sourceFile.getText('UTF-8'))
}
}
def snowballEclipseClasspathAttributes = [
gradle_scope : 'jmh',
gradle_used_by_scope: 'jmh',
@@ -53,16 +83,33 @@ tasks.register('extractSnowballJava', Copy) {
into(snowballExtractDirectory)
}
tasks.register('generateIsolatedSnowballSources') {
group = 'build setup'
description = 'Copies Snowball source to benchmark-only package-isolated package paths.'
dependsOn(tasks.named('extractSnowballJava'))
inputs.dir(snowballJavaSourceDirectory)
outputs.dir(snowballGeneratedSourceDirectory)
doLast {
copySnowballSourcesWithPackageIsolation(
snowballJavaSourceDirectory.get().asFile,
snowballGeneratedSourceDirectory.get().asFile
)
}
}
sourceSets {
jmh {
java {
srcDir(snowballJavaSourceDirectory)
srcDir(snowballGeneratedSourceDirectory)
}
}
}
tasks.named('compileJmhJava') {
dependsOn(tasks.named('extractSnowballJava'))
dependsOn(tasks.named('generateIsolatedSnowballSources'))
}
eclipse {
@@ -70,17 +117,19 @@ eclipse {
file {
whenMerged { classpath ->
String generatedSnowballPath = snowballJavaSourceClasspathPath.get()
String generatedIsolatedSnowballPath = snowballGeneratedSourceClasspathPath.get()
String modelSnowballPath = snowballJavaSourceRelativePath
classpath.entries.removeAll { entry ->
entry.hasProperty('path') && (
entry.path == generatedSnowballPath ||
entry.path == generatedIsolatedSnowballPath ||
entry.path == modelSnowballPath ||
isAbsoluteClasspathPath(entry.path)
)
}
SourceFolder snowballEntry = new SourceFolder(generatedSnowballPath, null)
SourceFolder snowballEntry = new SourceFolder(generatedIsolatedSnowballPath, null)
snowballEntry.output = 'bin/jmh'
snowballEclipseClasspathAttributes.each { String name, String value ->
snowballEntry.entryAttributes[name] = value

View File

@@ -61,16 +61,6 @@
<sha256 value="fcbbf1c18c9047e6917d384f2064e21b42a58fc85fb0523a9e2e015eff7c619d" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.fasterxml.jackson" name="jackson-base" version="2.20.1">
<artifact name="jackson-base-2.20.1.pom">
<sha256 value="0b748ab0cc7f287db5b6018c614cfe67e7e1f4d80941ce2f41d317ccc3b5b5c5" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.fasterxml.jackson" name="jackson-base" version="2.21.2">
<artifact name="jackson-base-2.21.2.pom">
<sha256 value="38c7898c763b8991fffbd769459972e0176bf0c505c739518c70f7c57d16eed7" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.fasterxml.jackson" name="jackson-bom" version="2.20.1">
<artifact name="jackson-bom-2.20.1.pom">
<sha256 value="0c6467ed4c8c7392524ce703ca6ce3ed88596eec390f13b0c264f2f961308a54" origin="Generated by Gradle"/>
@@ -136,11 +126,6 @@
<sha256 value="35bbfa18de48d36fadf6d380702202889dbb8153841451d3893b3fb598549024" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.fasterxml.jackson.dataformat" name="jackson-dataformats-text" version="2.21.2">
<artifact name="jackson-dataformats-text-2.21.2.pom">
<sha256 value="67a9eb4034f282dbf4f47b798812941be389c6014b09dcf4d8c24ca78d9f3e95" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.fasterxml.jackson.datatype" name="jackson-datatype-jsr310" version="2.21.2">
<artifact name="jackson-datatype-jsr310-2.21.2.jar">
<sha256 value="a083d57cd1c4a28fefcc6bd071740779eb7fc1c22a3c1b40451b5477c443f02f" origin="Generated by Gradle"/>
@@ -157,16 +142,6 @@
<sha256 value="61ae0080285e0d896dd2ed49910b2402d31e85cd18ed59c6732b0b203d5a3280" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.fasterxml.jackson.module" name="jackson-modules-base" version="2.21.2">
<artifact name="jackson-modules-base-2.21.2.pom">
<sha256 value="a952c6f9ea36dfea1d463182d5f06a7452db6751dcb28fc1add3748abffa58de" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.fasterxml.jackson.module" name="jackson-modules-java8" version="2.21.2">
<artifact name="jackson-modules-java8-2.21.2.pom">
<sha256 value="4f428c21279bc34bd44d51c2796741e77afd7f9db7ff4a931a43c7b01a1c4595" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.fasterxml.woodstox" name="woodstox-core" version="7.1.1">
<artifact name="woodstox-core-7.1.1.jar">
<sha256 value="02b9d022e9d47704ff8a7a859a0dbfd3b2882a8311eb7ff1e180f760ccda2712" origin="Generated by Gradle"/>
@@ -284,16 +259,6 @@
<sha256 value="7220ede61026596fbc720ee4b93246fa2d14f328058532b59ef053de397c7d83" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.google.guava" name="guava-parent" version="33.4.8-jre">
<artifact name="guava-parent-33.4.8-jre.pom">
<sha256 value="a03c5199a1be14443df7fd40ba8673b1c6aae04deef6688ce7d573ea489e3a20" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.google.guava" name="guava-parent" version="33.5.0-jre">
<artifact name="guava-parent-33.5.0-jre.pom">
<sha256 value="68719e687c6e4c9ff3e0fecbef7bd20896f0f4f7b314743ed33c72f962568215" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.google.guava" name="listenablefuture" version="9999.0-empty-to-avoid-conflict-with-guava">
<artifact name="listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar">
<sha256 value="b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99" origin="Generated by Gradle"/>
@@ -456,9 +421,6 @@
</artifact>
</component>
<component group="io.opentelemetry" name="opentelemetry-bom" version="1.49.0">
<artifact name="opentelemetry-bom-1.49.0.module">
<sha256 value="ed8b705c0f275f3eb6dd4b25a87eadf966bb70459e0db0ba6d54d4d8e76aaf91" origin="Generated by Gradle"/>
</artifact>
<artifact name="opentelemetry-bom-1.49.0.pom">
<sha256 value="44fcba73912b950d3ec88129e38e03c181b975f5b5ee73d7bab7866a4b376c50" origin="Generated by Gradle"/>
</artifact>
@@ -710,6 +672,11 @@
<sha256 value="d78bd8524c5f8380a190a6525686629a95dfe512df21111383a6d8c0923a4415" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache" name="apache" version="34">
<artifact name="apache-34.pom">
<sha256 value="3671ae9d4d062ae3bb985731c76088bb2f6f7d7254e2d304ee9f690b97651328" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache" name="apache" version="35">
<artifact name="apache-35.pom">
<sha256 value="ea297dcd114136e8b8e8b630230d52a76c2fc69f6c5db25d672b1857000728b8" origin="Generated by Gradle"/>
@@ -846,9 +813,6 @@
</artifact>
</component>
<component group="org.apache.groovy" name="groovy-bom" version="4.0.11">
<artifact name="groovy-bom-4.0.11.module">
<sha256 value="6aeb51768ac49d58bf515a570f966a4cd6cf823a8a919e9e87dfdde4152101e4" origin="Generated by Gradle"/>
</artifact>
<artifact name="groovy-bom-4.0.11.pom">
<sha256 value="27553a483d0f46df6aa86a1ce1f4126dca34aa957b2f88aaeb63136fd847fe18" origin="Generated by Gradle"/>
</artifact>
@@ -905,6 +869,14 @@
<sha256 value="d8ef04000565affac019b7a55de5bb7cc82ab0403295285ef49f6c8c2745afeb" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-analysis-common" version="10.5.0">
<artifact name="lucene-analysis-common-10.5.0.jar">
<sha256 value="922e217fe5cc88305b5a8e057cd80a30b7de96be2ff20dc4327fb524d26e6a25" origin="Generated by Gradle"/>
</artifact>
<artifact name="lucene-analysis-common-10.5.0.pom">
<sha256 value="8ad3288be355a6dca42678ae6abaa4726fe4a320b1657e7a7a455ae684edad27" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-analysis-common" version="9.12.3">
<artifact name="lucene-analysis-common-9.12.3.jar">
<sha256 value="fa571bd7caf0f0b4faf46a72ca004a7836f348c31d92bd522dddcc3d128d287e" origin="Generated by Gradle"/>
@@ -913,6 +885,30 @@
<sha256 value="3242d6696252c6ce33744087bbb821c384373c7819c3a054539b59876e3df39a" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-analysis-morfologik" version="10.5.0">
<artifact name="lucene-analysis-morfologik-10.5.0.jar">
<sha256 value="7438fa8afd11dc9b606e911ef5a922cf642a3d45e32c5bbd456e54d731810dbe" origin="Generated by Gradle"/>
</artifact>
<artifact name="lucene-analysis-morfologik-10.5.0.pom">
<sha256 value="df9863e0db7416ba1d0d1fa657b2728e31a2ac8150bdd87fa272b100aa0838fb" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-analysis-stempel" version="10.5.0">
<artifact name="lucene-analysis-stempel-10.5.0.jar">
<sha256 value="f46699a4457e1cec1035737c37be1f061eaf32d96b6679968bbda19d1b12ed2b" origin="Generated by Gradle"/>
</artifact>
<artifact name="lucene-analysis-stempel-10.5.0.pom">
<sha256 value="da627cd84d6e29eeae63fd1881420b1b9f1b3619c106016a5ba0338351a292ac" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-core" version="10.5.0">
<artifact name="lucene-core-10.5.0.jar">
<sha256 value="ec05ee432860dc6116765fc6bd9ffccf65311cb0430a42a3a90f09fffcd310b1" origin="Generated by Gradle"/>
</artifact>
<artifact name="lucene-core-10.5.0.pom">
<sha256 value="356efef0e44ed7e1979af9d39c4403fea268edc5ede1c6fe4c006e58f218a0dc" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-core" version="9.12.3">
<artifact name="lucene-core-9.12.3.jar">
<sha256 value="b64a3f8098a7572034fb30085cdee01b34ec81fb0e5a31b471536af58dc6c01b" origin="Generated by Gradle"/>
@@ -1106,6 +1102,19 @@
<sha256 value="a941745d7faeb8dc9a75edc2c330c994b7440b9a44d21142716b6053967a41c1" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.opennlp" name="opennlp" version="2.5.4">
<artifact name="opennlp-2.5.4.pom">
<sha256 value="433d0873ec27cfe1b1a20ea643773a2f29a40a1fdea1bb5d1828b2f35350c29b" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.opennlp" name="opennlp-tools" version="2.5.4">
<artifact name="opennlp-tools-2.5.4.jar">
<sha256 value="5efedb26d0e97e53707a8d2f0e2e28f05fcf654fce2a33f8bfe11c2d4c2a4fe9" origin="Generated by Gradle"/>
</artifact>
<artifact name="opennlp-tools-2.5.4.pom">
<sha256 value="fd4557916e65775956c37e8cdda7d9ad2bca778a29c98d6a5c6e31b61f83d560" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.velocity" name="velocity-engine-core" version="2.4.1">
<artifact name="velocity-engine-core-2.4.1.jar">
<sha256 value="1c19157d1171d560088e485be97c93a7a2f7e9f56e517f0a30273c5c39df6231" origin="Generated by Gradle"/>
@@ -1137,6 +1146,35 @@
<sha256 value="22b87dda9aab83fa1d0f3ea409b524e7a44921cf8f5f87999cf59046f0fe0bc3" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.carrot2" name="morfologik-fsa" version="2.1.9">
<artifact name="morfologik-fsa-2.1.9.jar">
<sha256 value="1bfefce937df14cc94d32a98ce59c33f4d5b6c0eddbb436b6bfe27ff2120a23d" origin="Generated by Gradle"/>
</artifact>
<artifact name="morfologik-fsa-2.1.9.pom">
<sha256 value="1097b12e6ede04b5a4e09b77233ac0943d8a6020edced7fd65ec97f2b02e103c" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.carrot2" name="morfologik-parent" version="2.1.9">
<artifact name="morfologik-parent-2.1.9.pom">
<sha256 value="59c72168787ba151785125e34472e7841c5ff18bde176c2db7349c06917a0627" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.carrot2" name="morfologik-polish" version="2.1.9">
<artifact name="morfologik-polish-2.1.9.jar">
<sha256 value="e503682b3f4e8bb7a5d05820b0e2a4a19d4bad43dae20f64741786658a9cf478" origin="Generated by Gradle"/>
</artifact>
<artifact name="morfologik-polish-2.1.9.pom">
<sha256 value="85595c01c592576b91f59600c040bf2ceabaf61afc25ffa8507e4da981a54fb5" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.carrot2" name="morfologik-stemming" version="2.1.9">
<artifact name="morfologik-stemming-2.1.9.jar">
<sha256 value="6170895b2315b697f4da5630caf57c6c441f1cb419d89d1cb5326b0673293e8a" origin="Generated by Gradle"/>
</artifact>
<artifact name="morfologik-stemming-2.1.9.pom">
<sha256 value="0b1495ad4d54b8dd4d309e1b445625ff2c788cc68818b5ded5cfe4f0d2f891a2" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.checkerframework" name="checker-qual" version="3.52.1">
<artifact name="checker-qual-3.52.1.jar">
<sha256 value="934641a18c8461bf66d7e939b2b054bf2a518ed4188fd7d6836a65b038f5364a" origin="Generated by Gradle"/>
@@ -1384,89 +1422,56 @@
</artifact>
</component>
<component group="org.junit" name="junit-bom" version="5.10.1">
<artifact name="junit-bom-5.10.1.module">
<sha256 value="21b0afcfffe2ecb3770f5eb00ae7a19feaee94e771fa3918173850dae78067b7" origin="Generated by Gradle"/>
</artifact>
<artifact name="junit-bom-5.10.1.pom">
<sha256 value="21c4b0286f4b20069577ff4b20978a85c100ac8a46b6f1c8672fbaab337bc3f2" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.junit" name="junit-bom" version="5.10.2">
<artifact name="junit-bom-5.10.2.module">
<sha256 value="de23b114b3e4119a8fe6eb17bed5a3852816698bace67071579d6d927ebb080a" origin="Generated by Gradle"/>
</artifact>
<artifact name="junit-bom-5.10.2.pom">
<sha256 value="169dd904a4b0f6520cffe658cc62292bfe9f3c14a989fa92120724cde43a9968" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.junit" name="junit-bom" version="5.11.0-M2">
<artifact name="junit-bom-5.11.0-M2.module">
<sha256 value="86477abcf490d6ca059aa9973cb108d22a506f49d1a5569bb32cc6cbf43c2cce" origin="Generated by Gradle"/>
</artifact>
<artifact name="junit-bom-5.11.0-M2.pom">
<sha256 value="4a3ffc4a4edcfec2cb5d619922706a9407161798571939f854dfda73e4e17cc8" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.junit" name="junit-bom" version="5.11.1">
<artifact name="junit-bom-5.11.1.module">
<sha256 value="e362fb8167202d6f0d4a5b16707c5324510fd2903d53649888c4496ac81c337e" origin="Generated by Gradle"/>
</artifact>
<artifact name="junit-bom-5.11.1.pom">
<sha256 value="c72124a9c9a79910c1858766b72c350e1a39244cbfb4b076348fbfe078281965" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.junit" name="junit-bom" version="5.11.4">
<artifact name="junit-bom-5.11.4.module">
<sha256 value="a9a4f27be94e99b9d570162d246a80f686d277d5d31aeb5481047cf51daf46e4" origin="Generated by Gradle"/>
</artifact>
<artifact name="junit-bom-5.11.4.pom">
<sha256 value="19d4b747b204805325b6334553296f986562277a4ac1cb5e593a5e4c4f5e4115" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.junit" name="junit-bom" version="5.12.2">
<artifact name="junit-bom-5.12.2.module">
<sha256 value="de70ac5d91a52656d8890a6d23b9e04d99b99b1a0402530decad71bf31b2735e" origin="Generated by Gradle"/>
</artifact>
<artifact name="junit-bom-5.12.2.pom">
<sha256 value="cef80fec86454f6806bfb0df24669b5c6f32e2cb728539ea859f47dfdc9bbc17" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.junit" name="junit-bom" version="5.13.1">
<artifact name="junit-bom-5.13.1.module">
<sha256 value="33c07ab9724790a6e5859ba07d69117ac530439724545a81c4179e3272c75de8" origin="Generated by Gradle"/>
</artifact>
<artifact name="junit-bom-5.13.1.pom">
<sha256 value="fa68451ea830572ed43ffe51d75b6a05f7a5e665a602a51f49d6be02063a65f3" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.junit" name="junit-bom" version="5.13.3">
<artifact name="junit-bom-5.13.3.module">
<sha256 value="5dc84d74ef981d023c639eb0cbc4b1f9ef891034287ce1b101effbbc0f1534b4" origin="Generated by Gradle"/>
</artifact>
<artifact name="junit-bom-5.13.3.pom">
<sha256 value="e3b93e9bb8871969cf11c0e8ff10f507841db1885ca10578e290846f660fd68e" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.junit" name="junit-bom" version="5.13.4">
<artifact name="junit-bom-5.13.4.module">
<sha256 value="e959288fde1b1b050d9bc082fc786789128da5d2853091468fca504104bdf400" origin="Generated by Gradle"/>
</artifact>
<artifact name="junit-bom-5.13.4.pom">
<sha256 value="d7a08a99b2502f0bb68cd4e1f984f0bf69324aaa208bd0f73366c03fc3548a42" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.junit" name="junit-bom" version="5.14.1">
<artifact name="junit-bom-5.14.1.module">
<sha256 value="278acb11ccc9998694224386f96fb4941a22edb42cb446c92e0f1f33014b6b48" origin="Generated by Gradle"/>
</artifact>
<artifact name="junit-bom-5.14.1.pom">
<sha256 value="01b01dfa366550b40ac5760548a7d728b6109d17c451e83864d1e5e0ce862c94" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.junit" name="junit-bom" version="5.14.2">
<artifact name="junit-bom-5.14.2.module">
<sha256 value="5d26f4440392326dd2483cf490143eea1495d5095459a0b9651a7b1b38e24ebf" origin="Generated by Gradle"/>
</artifact>
<artifact name="junit-bom-5.14.2.pom">
<sha256 value="ed2dcc7855bd460bccc93a1bf0c962e63b566ff7d8f1ded0f1f2593ba8183aaf" origin="Generated by Gradle"/>
</artifact>
@@ -1480,17 +1485,11 @@
</artifact>
</component>
<component group="org.junit" name="junit-bom" version="5.9.3">
<artifact name="junit-bom-5.9.3.module">
<sha256 value="b401fd25901e582a524aa5343c4b39e28bc56e24961c1069bf2b4bbfcee46b93" origin="Generated by Gradle"/>
</artifact>
<artifact name="junit-bom-5.9.3.pom">
<sha256 value="4d0329cd9e72f2420e5ca15724cbfe6ffa6e5fd2888361516271190fdc342ed7" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.junit" name="junit-bom" version="6.0.1">
<artifact name="junit-bom-6.0.1.module">
<sha256 value="c48d98f5edcfd9c55e79facbba0101f7c1ba08863489be84a9162b99a186d1c2" origin="Generated by Gradle"/>
</artifact>
<artifact name="junit-bom-6.0.1.pom">
<sha256 value="e315c5ccbb087216dce04ae70c32bf1762be2a0b8a43ef81e3ba78317a4cd5c8" origin="Generated by Gradle"/>
</artifact>
@@ -1630,11 +1629,6 @@
<sha256 value="48bf1d6c8b5dc94f74652bd17900f654deb714350248cf5e8fca27b9090c8e0d" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.ow2" name="ow2" version="1.5">
<artifact name="ow2-1.5.pom">
<sha256 value="0f8a1b116e760b8fe6389c51b84e4b07a70fc11082d4f936e453b583dd50b43b" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.ow2" name="ow2" version="1.5.1">
<artifact name="ow2-1.5.1.pom">
<sha256 value="321ddbb7ee6fe4f53dea6b4cd6db74154d6bfa42391c1f763b361b9f485acf05" origin="Generated by Gradle"/>
@@ -1955,6 +1949,14 @@
<sha256 value="ba01ae7a744cb52fe8ecf3b023cbc32e0ccc8c6beef9f26de77a47808239447d" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="ua.net.nlp" name="morfologik-ukrainian-search" version="4.9.1">
<artifact name="morfologik-ukrainian-search-4.9.1.jar">
<sha256 value="463d9054b8d4cfacb9cd69566395826a6fe32fb6e7da91dbf79d37ddf7d56ba0" origin="Generated by Gradle"/>
</artifact>
<artifact name="morfologik-ukrainian-search-4.9.1.pom">
<sha256 value="6a66d8efe6a5c774932401b04411a8feca7d6628631e4ef80819cfafa133dc38" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="us.springett" name="cpe-parser" version="3.0.1">
<artifact name="cpe-parser-3.0.1.jar">
<sha256 value="f98a50dce0a381e08f0f0ac067801c7f4c51dc7f8f1fe7a3c9960c684a809705" origin="Generated by Gradle"/>