Skip to content

Commit 77113a5

Browse files
committed
Add a couple of mini changes to improve adding custom plugins + Lots of fixes to RegExps to accurately reflect incoming data + others - see ChangeLog.md for details
1 parent 4a2ff78 commit 77113a5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+285
-123
lines changed

ChangeLog.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,26 @@
11

22
## Changes ##
33

4+
### 17.1.2
5+
- ENH: Add support for \\p{Digit} as a synonym for \d in RegExp plugins (Issue #142)
6+
- ENH: Validate the input file associated with a user-defined list plugin to check for lower case characters (Issue #143)
7+
- BUG: RegExp for FREE_TEXT incorrect if newlines present
8+
- BUG: RegExp for SPATIAL.WKT incorrect - missing '.'
9+
- BUG: RegExp for STREET_ADDRESS_EN, FULL_ADDRESS_EN incorrect if newlines present
10+
- BUG: RegExp incorrect if backing out from PhoneNumber misdetection and newlines present
11+
- BUG: RegExp incorrect if Unicode alphabetic character present and outputting a set of values
12+
- BUG: RegExp incorrect if returning a alphabetic character class with lower case e.g expected '(?i)[A-D]' for a, b, c, d not '[A-D]'
13+
- BUG: RegExp incorrect if merging a simple numeric with a qualified numeric e.g. '\d' & '\d{2}\p{IsAlphabetic}{4}'
14+
- BUG: RegExp for NAME.MIDDLE should allow periods
15+
- BUG: RegExp for POSTAL_CODE.ZIP5_PLUS4_US incorrect if any Zips with fewer than 5 digits present
16+
- BUG: VIN's outside the US do not have a check digit hence format is to easy to misinterpret so insist on a valid header
17+
- BUG: Were not recognizing '?' as a special character for Regular Expression - hence they were not being sloshed
18+
- BUG: RegExp for URLs not allowing parens
19+
- BUG: If we change out mind and make it a Regular Expression semantic type then any outliers are actually invalids
20+
- INT: Fix a couple of warnings
21+
- INT: Add missing Indian Semantic Types to documentation
22+
- INT: Bump google phonenumber to 9.0.10, gradle to 8.14.3, commons-validator to 1.10 (fixes dependency on vulnerable commons-beanutils), spotbugs to 6.2.2
23+
424
### 17.1.1
525
- ENH: Improve Indian District and State detection
626
- INT: Migrate to the Central Publishing Portal (OSSRH Service is EOL)
@@ -32,7 +52,7 @@
3252

3353
### 16.2.10
3454
- INT: Fix SpotBugs issues
35-
- INT: Bump google phonenumber to 9.0.7m gradle to 8.14.2
55+
- INT: Bump google phonenumber to 9.0.7, gradle to 8.14.2
3656

3757
### 16.2.9
3858
- BUG: Fix issues with sampleCount being incorrect - typically when doing a subsequent pass (Issue #134)

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Design objectives:
1717
* Sufficiently fast to be used inline. See Speed notes below.
1818
* Minimal false positives for Semantic type detection. See Performance notes below.
1919
* Usable in either Streaming, Bulk or Record mode.
20-
* Broad country/language support - including US, Canada, Mexico, Brazil, UK, Australia, much of Europe, Japan and China.
20+
* Broad country/language support - including US, Canada, Mexico, Brazil, UK, Australia, India, much of Europe, Japan and China.
2121
* Support for sharded analysis (i.e. Analysis results can be merged)
2222
* Once stream is profiled then subsequent samples can be validated and/or new samples can be generated
2323

@@ -124,7 +124,7 @@ Semantic Type: ***NAME.MIDDLE*** (String)
124124

125125
### Additional Examples
126126

127-
Are in the [example](examples) directory.
127+
Are in the [examples](examples) directory.
128128

129129
## Date Format determination ##
130130

SemanticTypes.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@
109109
|POSTAL_CODE.POSTAL_CODE_DE|Postal Code (DE)|https://www.wikidata.org/wiki/Property:P281, https://en.wikipedia.org/wiki/Postal_codes_in_Germany, https://schema.org/postalCode|de-DE|
110110
|POSTAL_CODE.POSTAL_CODE_ES|Postal Code (ES)|https://www.wikidata.org/wiki/Property:P281, https://en.wikipedia.org/wiki/Postal_codes_in_Spain, https://schema.org/postalCode|es-ES|
111111
|POSTAL_CODE.POSTAL_CODE_FR|Postal Code (FR)|https://www.wikidata.org/wiki/Property:P281, https://en.wikipedia.org/wiki/Postal_codes_in_France, https://schema.org/postalCode|fr-FR|
112+
|POSTAL_CODE.POSTAL_CODE_IN|Postal Code (IN)|https://www.wikidata.org/wiki/Property:P281, https://en.wikipedia.org/wiki/Postal_Index_Number, https://schema.org/postalCode|en-IN,hi-IN|
112113
|POSTAL_CODE.POSTAL_CODE_JA|Postal Code (JA)|https://www.wikidata.org/wiki/Property:P281, https://en.wikipedia.org/wiki/Postal_codes_in_Japan, https://schema.org/postalCode|ja|
113114
|POSTAL_CODE.POSTAL_CODE_MX|Postal Code (MX)|https://www.wikidata.org/wiki/Property:P281, https://en.wikipedia.org/wiki/Postal_codes_in_Mexico, https://schema.org/postalCode|es-MX|
114115
|POSTAL_CODE.POSTAL_CODE_NL|Postal Code (NL)|https://www.wikidata.org/wiki/Property:P281, https://en.wikipedia.org/wiki/Postal_codes_in_the_Netherlands, https://schema.org/postalCode|en-NL,nl-NL|
@@ -131,6 +132,7 @@
131132
|STATE_PROVINCE.COUNTY_US|US County Name|https://en.wikipedia.org/wiki/County_(United_States)|en-US|
132133
|STATE_PROVINCE.DEPARTMENT_CO|Colombian Department|https://en.wikipedia.org/wiki/Departments_of_Colombia|es-CO|
133134
|STATE_PROVINCE.DEPARTMENT_NAME_FR|French Department||fr-FR|
135+
|STATE_PROVINCE.DISTRICT_NAME_IN|Indian District name|https://en.wikipedia.org/wiki/List_of_districts_in_India|en-IN, hi-IN|
134136
|STATE_PROVINCE.DISTRICT_NAME_PT|Portuguese District Name|https://en.wikipedia.org/wiki/List_of_municipalities_of_Portugal|pt-PT|
135137
|STATE_PROVINCE.INSEE_CODE_FR|French Insee Code (5 digit)|https://en.wikipedia.org/wiki/INSEE_code|fr-FR|
136138
|STATE_PROVINCE.MUNICIPALITY_BR|Brazilian Municipality|https://en.wikipedia.org/wiki/Municipalities_of_Brazil|pt-BR|
@@ -166,6 +168,8 @@
166168
|STATE_PROVINCE.STATE_NAME_US|US State Name|https://en.wikipedia.org/wiki/List_of_states_and_territories_of_the_United_States, https://schema.org/State|en-US,es-US,en-CA,fr-CA,en-MX|
167169
|STATE_PROVINCE.STATE_PROVINCE_NA|US State Code/Canadian Province Code/Mexican State Code|https://schema.org/State|en-US,en-CA,fr-CA,en-MX|
168170
|STATE_PROVINCE.STATE_PROVINCE_NAME_NA|US State Name/Canadian Province Name/Mexican State Name|https://schema.org/State|en-US,es-US,en-CA,fr-CA,en-MX|
171+
|STATE_PROVINCE.STATE_UNION_IN|Indian State/Union Code|https://en.wikipedia.org/wiki/States_and_union_territories_of_India, https://en.wikipedia.org/wiki/ISO_3166-2:IN|en-IN|
172+
|STATE_PROVINCE.STATE_UNION_NAME_IN|Indian State/Union name|https://en.wikipedia.org/wiki/States_and_union_territories_of_India, https://en.wikipedia.org/wiki/ISO_3166-2:IN|en-IN|
169173
|STATE_PROVINCE.STATE_US|US State Code|https://en.wikipedia.org/wiki/List_of_states_and_territories_of_the_United_States, https://schema.org/State|en-US,en-Latn-US,en-CA,fr-CA,en-MX|
170174
|STATE_PROVINCE.SUBURB_AU|Australian Suburb|https://en.wikipedia.org/wiki/Suburbs_and_localities_(Australia)|en-AU|
171175
|STREET_ADDRESS2_EN|Street Address - Line 2 (English Language)||en|

build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
plugins {
22
id "com.github.ben-manes.versions"
3-
id "com.github.spotbugs" version "6.2.1" apply false
3+
id "com.github.spotbugs" version "6.2.2" apply false
44
}
55

66
wrapper {
7-
gradleVersion = '8.14.2'
7+
gradleVersion = '8.14.3'
88
}
99

1010
tasks.register('examples.clean') {

cli/src/main/java/com/cobber/fta/driver/FileProcessor.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,8 @@ private void processAllFields(final ParserSettings settings) throws IOException,
336336
final int[] blanks = new int[numFields];
337337
final Set<String> failures = new HashSet<>();
338338

339+
final TextAnalysisResult[] results = processor.getResult();
340+
339341
// Check the RegExp at level 2 validation
340342
if (options.validate == 2) {
341343
try (BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(new File(filename)), options.charset))) {
@@ -348,13 +350,15 @@ private void processAllFields(final ParserSettings settings) throws IOException,
348350
Pattern[] patterns = null;
349351
rawRecordIndex = 0;
350352

353+
TextAnalyzer[] analyzers = null;
351354
for (final CloseableIterator<NamedCsvRecord> iter = csv.iterator(); iter.hasNext();) {
352355
final NamedCsvRecord rowRaw = iter.next();
353356
final String[] row = rowRaw.getFields().toArray(new String[0]);
357+
354358
// Are we looking at the header row?
355359
if (rawRecordIndex == 0) {
356360
numFields = rowRaw.getFieldCount();
357-
final TextAnalysisResult[] results = processor.getResult();
361+
analyzers = processor.getAnalyzers();
358362
patterns = new Pattern[numFields];
359363

360364
for (int i = 0; i < numFields; i++)
@@ -369,11 +373,11 @@ private void processAllFields(final ParserSettings settings) throws IOException,
369373
for (int i = 0; i < numFields; i++) {
370374
if (options.col == -1 || options.col == i) {
371375
final String value = row[i];
372-
if (value == null)
376+
if (analyzers[i].isNullEquivalent(value))
373377
nulls[i]++;
374378
else if (value.trim().isEmpty())
375379
blanks[i]++;
376-
else if (patterns[i].matcher(value).matches())
380+
else if (patterns[i].matcher(value.trim()).matches())
377381
matched[i]++;
378382
else if (options.verbose != 0)
379383
failures.add(value);
@@ -396,7 +400,6 @@ else if (options.verbose != 0)
396400
if (outputJSON)
397401
output.printf("[%n");
398402

399-
final TextAnalysisResult[] results = processor.getResult();
400403
final ArrayNode fieldsArray = mapper.createArrayNode();
401404

402405
for (int i = 0; i < numFields; i++) {
@@ -510,13 +513,17 @@ else if (result.getCardinality() > 20) {
510513
}
511514

512515
if (options.validate == 2 && matched[i] != result.getMatchCount()) {
513-
if (result.isSemanticType())
514-
if (matched[i] > result.getMatchCount())
515-
error.printf("\t*** Warning: Match Count via RegExp (%d) > LogicalType match analysis (%d) ***%n", matched[i], result.getMatchCount());
516-
else
517-
error.printf("\t*** Error: Match Count via RegExp (%d) < LogicalType match analysis (%d) ***%n", matched[i], result.getMatchCount());
516+
String logicalType = result.isSemanticType() ? "Logical Type " : "";
517+
518+
if (matched[i] > result.getMatchCount())
519+
error.printf("\t*** NOTE: Composite: %s, field: %s (%d), match Count via RegExp (%d) > %smatch analysis (%d) ***%n",
520+
analyzer.getContext().getCompositeName(), analyzer.getContext().getStreamName(),
521+
analyzer.getContext().getStreamIndex(), matched[i], logicalType, result.getMatchCount());
518522
else
519-
error.printf("\t*** Error: Match Count via RegExp (%d) does not match analysis (%d) ***%n", matched[i], result.getMatchCount());
523+
error.printf("\t*** ERROR: Composite: %s, field: %s (%d), match Count via RegExp (%d) < %smatch analysis (%d) ***%n",
524+
analyzer.getContext().getCompositeName(), analyzer.getContext().getStreamName(),
525+
analyzer.getContext().getStreamIndex(), matched[i], logicalType, result.getMatchCount());
526+
520527
if (options.verbose != 0) {
521528
error.println("Failed to match:");
522529
for (final String failure : failures)

core/src/main/java/com/cobber/fta/KnownTypes.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.cobber.fta.core.FTAType;
2727
import com.cobber.fta.core.RegExpGenerator;
2828
import com.cobber.fta.core.RegExpSplitter;
29+
import com.cobber.fta.core.Utils;
2930

3031
/**
3132
* A set of predefined types, for simple numerics, strings and boolean values.
@@ -69,6 +70,8 @@ public enum ID {
6970

7071
public static final String PATTERN_ANY = ".";
7172
public static final String PATTERN_ANY_VARIABLE = ".+";
73+
public static final String PATTERN_ANY_STRING = ".*";
74+
public static final String PATTERN_ANY_STRING_DOTALL = "(?s).*";
7275
public static final String PATTERN_ALPHA = "\\p{IsAlphabetic}";
7376
public static final String PATTERN_NUMERIC = "\\d";
7477
public static final String PATTERN_NUMERIC_VARIABLE = PATTERN_NUMERIC + "+";
@@ -203,7 +206,8 @@ else if (negSuffix.charAt(0) == minusSign && minusSign == '\u2212') // Unicode
203206
final String localizedNo = keywords.get("NO");
204207
if (localizedYes != null && localizedNo != null) {
205208
if (!"yes".equals(localizedYes) || !"no".equals(localizedNo)) {
206-
PATTERN_BOOLEAN_YES_NO_LOCALIZED = "(?i)(" + localizedNo + "|" + localizedYes + ")";
209+
PATTERN_BOOLEAN_YES_NO_LOCALIZED = !Utils.isSimpleAlphas(localizedYes) || !Utils.isSimpleAlphas(localizedNo) ? "(?u)" : "";
210+
PATTERN_BOOLEAN_YES_NO_LOCALIZED += "(?i)(" + localizedNo.toUpperCase(locale) + "|" + localizedYes.toUpperCase(locale) + ")";
207211
knownTypes.put(PATTERN_BOOLEAN_YES_NO_LOCALIZED,
208212
new TypeInfo(ID.ID_BOOLEAN_YES_NO_LOCALIZED, PATTERN_BOOLEAN_YES_NO_LOCALIZED, FTAType.BOOLEAN, "YES_NO", false, ""));
209213
}

core/src/main/java/com/cobber/fta/core/RegExpGenerator.java

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ public class RegExpGenerator {
5353
private boolean isUnderscore;
5454
private boolean isMinus;
5555
private boolean isOther;
56+
private boolean isUnicode;
5657
private int maxClasses;
5758
private int maxSetSize = -1;
5859
private Locale locale;
@@ -76,7 +77,7 @@ public RegExpGenerator(final int maxSetSize, final Locale locale) {
7677
* @return True if the character is reserved.
7778
*/
7879
public static boolean isSpecial(final char ch) {
79-
return ch == '.' || ch == '+' || ch == '*' || ch == '^' || ch == '$' ||
80+
return ch == '.' || ch == '+' || ch == '*' || ch == '^' || ch == '$' || ch == '?' ||
8081
ch == '[' || ch == ']' || ch == '(' || ch == ')' || ch == '{' || ch == '}' || ch == '|';
8182

8283
}
@@ -94,8 +95,13 @@ public static String slosh(final char ch) {
9495
* @return The merged expression.
9596
*/
9697
public static String merge(String firstRE, String secondRE) {
98+
if (firstRE.equals(secondRE))
99+
return firstRE;
100+
101+
String simpleAnswer = firstRE.compareTo(secondRE) < 0 ? firstRE + '|' + secondRE : secondRE + '|' + firstRE;
102+
97103
if (!firstRE.contains(secondRE) && !secondRE.contains(firstRE))
98-
return firstRE.compareTo(secondRE) < 0 ? firstRE + '|' + secondRE : secondRE + '|' + firstRE;
104+
return simpleAnswer;
99105

100106
// Switch it so that the firstRE contains the second
101107
if (secondRE.contains(firstRE)) {
@@ -104,9 +110,14 @@ public static String merge(String firstRE, String secondRE) {
104110
secondRE = save;
105111
}
106112

107-
// Case 1: first starts with second
108-
if (firstRE.startsWith(secondRE))
113+
// Case 1: first starts with second (e.g. "\d{2}" and "\d{2}-\d{2}") should return "\d{2}(-\d{2})?")
114+
if (firstRE.startsWith(secondRE)) {
115+
String optionalTail = firstRE.substring(secondRE.length());
116+
// We need to not merge if we have something like "\d{2}" and "\d-\d{2}" as we would NOT want to return "\d({2}-\d{2})?"
117+
if (optionalTail.charAt(0) == '{')
118+
return simpleAnswer;
109119
return secondRE + '(' + firstRE.substring(secondRE.length()) + ")?";
120+
}
110121

111122
// Case 2: first ends with second
112123
if (firstRE.endsWith(secondRE))
@@ -173,10 +184,16 @@ public void train(final String input) {
173184

174185
for (int i = 0; i < len; i++) {
175186
final char ch = input.charAt(i);
176-
if (Character.isLetter(ch))
187+
if (Character.isLetter(ch)) {
177188
isLetter = true;
178-
else if (Character.isDigit(ch))
189+
if (!isUnicode && !Utils.isSimpleAlpha(ch))
190+
isUnicode = true;
191+
}
192+
else if (Character.isDigit(ch)) {
193+
if (!isUnicode && !Utils.isSimpleDigit(ch))
194+
isUnicode = true;
179195
isDigit = true;
196+
}
180197
else if (ch == '.')
181198
isPeriod = true;
182199
else if (ch == ' ')
@@ -221,7 +238,7 @@ public String getResult() {
221238
final boolean constantLength = shortest == longest;
222239

223240
// Generate a Character class if possible - we would rather see [A-G] than A|B|C|D|E|F|G
224-
if (memory.size() >= 3 && shortest == 1 && constantLength) {
241+
if (memory.size() >= 3 && shortest == 1 && constantLength && !isUnicode) {
225242
char first = 0;
226243
char last = 0;
227244
char current;
@@ -238,6 +255,8 @@ public String getResult() {
238255
last = current;
239256
}
240257
if (collapsible) {
258+
if (isLetter)
259+
result.append("(?i)");
241260
result.append('[').append(first).append('-').append(last).append(']');
242261
return result.toString();
243262
}
@@ -247,6 +266,8 @@ public String getResult() {
247266
if (memory.size() <= maxSetSize && !(constantLength && !isSpace && !isOther && !isUnderscore && shortest >= 12)) {
248267
if (isLetter)
249268
result.append("(?i)");
269+
if (isUnicode)
270+
result.append("(?u)");
250271
if (memory.size() != 1)
251272
result.append('(');
252273
for (final String element : memory) {
@@ -302,14 +323,20 @@ public Set<String> getValues() {
302323
toSimplifyFull.put("[\\p{IsAlphabetic}\\d]", "(<L>|<Nd>)");
303324
toSimplifyFull.put("\\p{XDigit}", "[0-9A-Fa-f]");
304325
toSimplifyFull.put("\\p{IsAlphabetic}", "<L>");
326+
toSimplifyFull.put("\\p{Alpha}", "<L>");
327+
toSimplifyFull.put("\\p{Alnum}", "(<L>|<Nd>)");
305328
toSimplifyFull.put("\\d", "<Nd>");
329+
toSimplifyFull.put("\\p{Digit}", "<Nd>");
306330
toSimplifyFull.put("#", "\\#");
307331
toSimplifyFull.put("(?i)", "");
308332

309333
toSimplifyASCII.put("[\\p{IsAlphabetic}\\d]", "[A-Za-z0-9]");
310334
toSimplifyASCII.put("\\p{XDigit}", "[0-9A-Fa-f]");
311335
toSimplifyASCII.put("\\p{IsAlphabetic}", "[A-Za-z]");
336+
toSimplifyASCII.put("\\p{Alpha}", "[A-Za-z]");
337+
toSimplifyASCII.put("\\p{Alnum}", "[A-Za-z0-9]");
312338
toSimplifyASCII.put("\\d", "[0-9]");
339+
toSimplifyASCII.put("\\p{Digit}", "[0-9]");
313340
toSimplifyASCII.put("#", "\\#");
314341
toSimplifyASCII.put("(?i)", "");
315342
}

core/src/main/java/com/cobber/fta/core/Utils.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,12 +161,24 @@ public static boolean isAlphas(final String input) {
161161
return input.chars().allMatch(Character::isLetter);
162162
}
163163

164+
/**
165+
* Test if the supplied input is all simple alphas.
166+
* @param input String to test.
167+
* @return True if the string is all simple alphas.
168+
*/
169+
public static boolean isSimpleAlphas(final String input) {
170+
if (input == null || input.isEmpty())
171+
return false;
172+
173+
return input.chars().allMatch(c -> isSimpleAlpha((char) c));
174+
}
175+
164176
/**
165177
* Test if the supplied character is numeric [0-9].
166178
* @param ch Character to test.
167179
* @return True if the character is in the range [0-9].
168180
*/
169-
public static boolean isSimpleNumeric(final char ch) {
181+
public static boolean isSimpleDigit(final char ch) {
170182
return ch >= '0' && ch <= '9';
171183
}
172184

core/src/test/java/com/cobber/fta/TestUtilsCore.java

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -502,13 +502,13 @@ public void testIsSimpleAlpha() {
502502

503503
@Test(groups = { TestGroups.ALL })
504504
public void testIsSimpleNumeric() {
505-
assertTrue(Utils.isSimpleNumeric('0'));
506-
assertTrue(Utils.isSimpleNumeric('9'));
507-
assertFalse(Utils.isSimpleNumeric('0'));
508-
assertFalse(Utils.isSimpleNumeric('a'));
509-
assertFalse(Utils.isSimpleNumeric('z'));
510-
assertFalse(Utils.isSimpleNumeric('A'));
511-
assertFalse(Utils.isSimpleNumeric('Z'));
505+
assertTrue(Utils.isSimpleDigit('0'));
506+
assertTrue(Utils.isSimpleDigit('9'));
507+
assertFalse(Utils.isSimpleDigit('0'));
508+
assertFalse(Utils.isSimpleDigit('a'));
509+
assertFalse(Utils.isSimpleDigit('z'));
510+
assertFalse(Utils.isSimpleDigit('A'));
511+
assertFalse(Utils.isSimpleDigit('Z'));
512512
}
513513

514514
@Test(groups = { TestGroups.ALL })
@@ -602,7 +602,17 @@ public void testRegExpGenerator() {
602602
generator.train("D");
603603
generator.train("E");
604604
}
605-
assertEquals(generator.getResult(), "[A-E]");
605+
assertEquals(generator.getResult(), "(?i)[A-E]");
606+
607+
generator = new RegExpGenerator(20, Locale.getDefault());
608+
for (int i = 0; i < 100; i++) {
609+
generator.train("a");
610+
generator.train("b");
611+
generator.train("c");
612+
generator.train("d");
613+
generator.train("e");
614+
}
615+
assertEquals(generator.getResult(), "(?i)[A-E]");
606616

607617
generator = new RegExpGenerator();
608618
for (int i = 0; i < 100; i++) {

examples/contextual/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ plugins {
33
}
44

55
wrapper {
6-
gradleVersion = '8.14.2'
6+
gradleVersion = '8.14.3'
77
}
88

99
repositories {

0 commit comments

Comments
 (0)