diff --git a/00.config.sh b/00.config.sh
index 946a559..c5c49c7 100644
--- a/00.config.sh
+++ b/00.config.sh
@@ -1,5 +1,75 @@
-## Path to Closure Compiler
-COMPILER="java -jar closure-compiler-v20230103.jar"
+## Closure Compiler Maven Repo URLs
+CC_BASE_URL="https://repo1.maven.org/maven2/com/google/javascript/closure-compiler"
+CC_META_URL="${CC_BASE_URL}/maven-metadata.xml"
+
+## Function to Verify MD5 of a local JAR against Maven Central's published checksum
+## if md5sum does not match, jar is removed to be downloaded again.
+verify_md5() {
+ _jar="$1"
+ _url="$2"
+ if ! command -v md5sum >/dev/null 2>&1; then
+ echo "WARNING: md5sum not found — skipping integrity check."
+ return 0
+ fi
+ _expected=$(curl -fsSL --max-time 15 "${_url}.md5")
+ if [ -z "${_expected}" ]; then
+ echo "WARNING: Could not fetch MD5 from Maven Central — skipping integrity check."
+ return 0
+ fi
+ _actual=$(md5sum "${_jar}" | cut -d' ' -f1)
+ if [ "${_actual}" != "${_expected}" ]; then
+ echo "ERROR: MD5 mismatch for ${_jar}"
+ echo " Expected: ${_expected}"
+ echo " Got: ${_actual}"
+ rm -f "${_jar}"
+ return 1
+ fi
+ echo "===> MD5 OK (${_actual})"
+ return 0
+}
+
+## Check if a closure-compiler JAR already exists locally
+CC_JAR=$(ls closure-compiler-*.jar 2>/dev/null | head -n 1)
+
+if [ -n "${CC_JAR}" ]; then
+ # JAR found — extract version from filename and verify against Maven Central
+ CC_VERSION="${CC_JAR#closure-compiler-}"
+ CC_VERSION="${CC_VERSION%.jar}"
+ CC_URL="${CC_BASE_URL}/${CC_VERSION}/${CC_JAR}"
+ echo "===> Found local ${CC_JAR} — verifying integrity..."
+ if ! verify_md5 "${CC_JAR}" "${CC_URL}"; then
+ echo "===> Local JAR failed integrity check. Re-downloading..."
+ CC_JAR=""
+ fi
+fi
+
+if [ -z "${CC_JAR}" ]; then
+ # JAR not found — resolve latest version and download
+ echo "===> Resolving latest Closure Compiler version..."
+ CC_VERSION=$(curl -fsSL --max-time 15 "${CC_META_URL}" | sed -n 's|.*\(.*\).*|\1|p')
+ if [ -z "${CC_VERSION}" ]; then
+ echo "ERROR: Could not resolve Closure Compiler version from Maven Central."
+ echo " Check your internet connection or manually place the JAR in this directory."
+ exit 1
+ fi
+ CC_JAR="closure-compiler-${CC_VERSION}.jar"
+ CC_URL="${CC_BASE_URL}/${CC_VERSION}/${CC_JAR}"
+ echo "===> Downloading Closure Compiler ${CC_VERSION}..."
+ if ! curl -fSL --max-time 120 -o "${CC_JAR}" "${CC_URL}"; then
+ rm -f "${CC_JAR}"
+ echo "ERROR: Failed to download Closure Compiler ${CC_VERSION} from:"
+ echo " ${CC_URL}"
+ echo " Check your internet connection and try again."
+ exit 1
+ fi
+ echo "===> Downloaded ${CC_JAR}"
+ if ! verify_md5 "${CC_JAR}" "${CC_URL}"; then
+ echo "ERROR: Downloaded JAR failed integrity check."
+ exit 1
+ fi
+fi
+
+COMPILER="java -jar ${CC_JAR}"
EXT_NAME=WV
EXT_FILE_NAME="WME_Validator.user.js"
diff --git a/99.build.sh b/99.build.sh
index 224f041..fd48070 100644
--- a/99.build.sh
+++ b/99.build.sh
@@ -32,6 +32,7 @@ cat "${SRC_DIR}/meta/i18n-end.js" >> "${LOC_FILE}"
${COMPILER} \
--language_in ECMASCRIPT_2020 \
+ --language_out ECMASCRIPT_2020 \
--js "${SRC_DIR}/src/release.js" \
--js "${LOC_FILE}" \
--js "${SRC_DIR}/src/helpers.js" \
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 0000000..9387adf
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,117 @@
+# CLAUDE.md
+
+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
+
+## What This Is
+
+WME Validator is a Tampermonkey/GreasyFork userscript for the [Waze Map Editor](https://waze.com). It validates map data (segments, nodes, venues) against 150+ rules across 26+ countries, highlights issues in the editor, and generates detailed reports with wiki references and solutions.
+
+## Build Commands
+
+The project uses shell scripts wrapping the Google Closure Compiler (Java). No `npm` or `package.json`.
+
+```bash
+./10.release.sh # Release build → build/WME_Validator.user.js (ADVANCED_OPTIMIZATIONS)
+./20.debug.sh # Debug build → build/WME_Validator.debug.js (BUNDLE, DEF_DEBUG=true)
+./30.gf.sh # GreasyFork build → build/WME_Validator.gf.js (WHITESPACE_ONLY)
+./98.format.sh # Format the compiled output with clang-format (Google style, tab width 4)
+./99.build.sh # Orchestrator — runs all three build variants
+```
+
+> **Windows / Git Bash note:** If scripts produce `: not found` errors, strip CRLF line endings with:
+> ```bash
+> sed -i 's/\r//' *.sh
+> ```
+
+Configuration (compiler path, output dirs) is in `./00.config.sh`. The Closure Compiler JAR is **auto-downloaded** from Maven Central on first run — no manual installation needed. The script detects any existing `closure-compiler-*.jar` in the repo root, verifies its MD5 against Maven Central, and re-downloads if missing or corrupt. Always fetches the latest published release.
+
+There are **no automated tests**. Validation is done manually per `doc/RELENG.md`.
+
+## Architecture
+
+### Build Pipeline
+
+Source files are concatenated in a specific order and fed to Closure Compiler:
+
+1. `meta/meta-begin.js` — UserScript `@userscript` header
+2. `meta/i18n-begin.js` — opens the translations object
+3. `i18n/default.js` + `i18n/.js` (26 countries) — localization rules, auto-concatenated
+4. `meta/i18n-end.js` — closes the translations object
+5. `src/*.js` — core application code
+6. `meta/meta-end.js` — closing wrapper
+7. `meta/wme-externs.js` + `meta/jquery-1.9.js` — Closure Compiler extern definitions (not bundled, only used for type-checking)
+
+The post-build steps prepend the UserScript metadata header and run `clang-format`.
+
+### Global Namespaces
+
+All runtime state lives in four top-level objects defined in `src/data.js`:
+
+| Namespace | Purpose |
+|-----------|---------|
+| `_WV` | Private validator state and configuration |
+| `_UI` | User interface state |
+| `_RT` | Runtime data (current scan results, active segment info) |
+| `_REP` | Report accumulator |
+
+The `_THUI` namespace (from `src/lib/thui.js`) is a small embedded HTML UI toolkit.
+
+### Core Execution Flow
+
+```
+WME login event
+ └─ F_LOGIN (src/login.js) — access control, UI initialization
+
+User triggers scan
+ └─ F_VALIDATE (src/validate.js) — runs all rules against segments/nodes/venues
+
+Map change events (segments/nodes/venues)
+ └─ F_ONSEGMENTSCHANGED / F_ONNODESCHANGED / F_ONVENUESCHANGED (src/other.js)
+ └─ re-validates affected objects
+
+User requests report
+ └─ F_SHOWREPORT (src/report.js) — generates HTML/text/CSV output
+```
+
+### Source File Roles
+
+- `src/release.js` — version string, release/expiry dates, CDN URLs, global access lists
+- `src/data.js` — namespace definitions, constants, `DEF_DEBUG` flag
+- `src/helpers.js` — pure utilities: `classOf`, `deepCopy`, `deepCompare`, `getDirection`
+- `src/basic.js` — logging, HTML escaping, Trusted Types policy, error handling
+- `src/validate.js` — validation engine; each rule is a function called per object
+- `src/report.js` — report rendering (HTML table, plain text, CSV)
+- `src/login.js` — login handler, access list parsing, country/user/level gates
+- `src/other.js` — WME event listeners and layer change handler
+- `src/lib/i18n.js` — i18n lookup helpers
+- `src/lib/audio.js` — audio notification system
+- `src/lib/thui.js` — tiny UI library for building form controls
+
+### Localization and Country Rules
+
+`i18n/` is a **git submodule** (`https://github.com/WMEValidator/i18n.git`). Each country file (`i18n/AR.js`, `i18n/DE.js`, etc.) overrides or extends the default English rules in `i18n/default.js`. When editing country-specific rules, changes go in the submodule, not in the main repo.
+
+### Access Control
+
+Rules can be gated by user level, username, country, or city using constants from `src/release.js`:
+- `GA_FORLEVEL` — minimum WME user level
+- `GA_FORUSER` / `GA_FORCOUNTRY` / `GA_FORCITY` — allowlists with negation (`"!Dekis,*"`)
+
+These are evaluated in `F_LOGIN` against `WLM.user` attributes.
+
+### Conventions
+
+- Main handler functions are named `F_ACTION()` (e.g., `F_VALIDATE`, `F_LOGIN`, `F_SHOWREPORT`)
+- Constants are `ALL_CAPS`
+- JSDoc annotations (`@const`, `@type`, `@suppress`, `@struct`, `@define`) are used throughout — they matter for Closure Compiler's type checker and dead code elimination
+- Debug-only code is guarded by `DEF_DEBUG` (a `@define` constant, stripped in release builds)
+- All HTML written to the DOM must go through the Trusted Types policy defined in `src/basic.js`
+
+## Release Checklist
+
+See `doc/RELENG.md` for the full checklist. Key steps before releasing:
+- Ensure all `window.console` calls are commented out
+- Resolve all `TEST:`, `TODO:`, `BETA:` markers
+- Verify header fields: country locks, user levels, release date, expiration date
+- Run release build and test both in Tampermonkey and Firefox
+- Check Unicode characters in the output file
diff --git a/doc/ChangeLog.txt b/doc/ChangeLog.txt
index 9324ed6..daeefbb 100644
--- a/doc/ChangeLog.txt
+++ b/doc/ChangeLog.txt
@@ -1,5 +1,11 @@
Current changes:
+v2026.06.13:
+- Updated PFX_PEDIA link for a waze discuss search link (temp fix)
+- Added CLAUDE.md
+- Improved closure compiler retrieval process
+- Added --language_out ECMASCRIPT_2020 in build params
+
v2026.06.12:
- DaveAcincy: migrating validator to use the WME SDK.
- update US and Chile localizations.
@@ -870,4 +876,4 @@ Bugs & Issues:
- Run once mode permalinks were fixed
Other changes
-- report of a very long street names has moved to a Polish country pack
\ No newline at end of file
+- report of a very long street names has moved to a Polish country pack
diff --git a/meta/meta-begin.js b/meta/meta-begin.js
index 6cad108..0bcb4d8 100644
--- a/meta/meta-begin.js
+++ b/meta/meta-begin.js
@@ -1,6 +1,6 @@
// ==UserScript==
// @name WME Validator
-// @version 2026.06.12
+// @version 2026.06.13
// @description This script validates a map area in Waze Map Editor, highlights issues and generates a very detailed report with wiki references and solutions
// @match https://beta.waze.com/*editor*
// @match https://www.waze.com/*editor*
@@ -12,7 +12,6 @@
// @icon https://raw.githubusercontent.com/WMEValidator/release/master/img/WV-icon96.png
// @namespace a
// @homepage https://www.waze.com/discuss/t/script-wme-validator-v2025-02-26-places-beta/44877
-// @homepage https://www.waze.com/discuss/t/script-wme-validator-v2025-02-26-places-beta/44877
// @author Andriy Berestovskyy
// @copyright 2013-2018 Andriy Berestovskyy
// @license GPLv3
@@ -21,6 +20,7 @@
// @contributor jangliss
// @contributor Glodenox
// @contributor DaveAcincy
+// @contributor miguelovergara
// ==/UserScript==
/* global turf */
/* global turf */
@@ -36,10 +36,9 @@
*
* For questions please use official forum:
* https://www.waze.com/discuss/t/script-wme-validator-v2025-02-26-places-beta/44877
- * https://www.waze.com/discuss/t/script-wme-validator-v2025-02-26-places-beta/44877
*
* Report bugs on GitHub Issues Tracker:
* https://github.com/WMEValidator/validator/issues
*/
-(function () {
\ No newline at end of file
+(function () {
diff --git a/src/login.js b/src/login.js
index f101382..2a3b958 100644
--- a/src/login.js
+++ b/src/login.js
@@ -557,12 +557,12 @@ async function F_LOGIN() {
if (labelPL in translation) {
let l = translation[labelPL]
.replace('W:', PFX_WIKI)
- .replace('P:', PFX_PEDIA)
+ .replace('P:', PFX_SEARCH)
.replace('F:', PFX_FORUM)
.replace('D:', PFX_DISCUSS)
;
check.PROBLEMLINK[ccode] = encodeURI(l);
- if (-1 !== l.indexOf(PFX_WIKI) || -1 !== l.indexOf(PFX_PEDIA))
+ if (-1 !== l.indexOf(PFX_WIKI) || -1 !== l.indexOf(PFX_SEARCH))
check.PROBLEMLINKTEXT[ccode] = trS('report.link.wiki');
else
if (-1 !== l.indexOf(PFX_FORUM))
@@ -573,12 +573,12 @@ async function F_LOGIN() {
if (labelSL in translation) {
let l = translation[labelSL]
.replace('W:', PFX_WIKI)
- .replace('P:', PFX_PEDIA)
+ .replace('P:', PFX_SEARCH)
.replace('F:', PFX_FORUM)
.replace('D:', PFX_DISCUSS)
;
check.SOLUTIONLINK[ccode] = encodeURI(l);
- if (-1 !== l.indexOf(PFX_WIKI || -1 !== l.indexOf(PFX_PEDIA)))
+ if (-1 !== l.indexOf(PFX_WIKI || -1 !== l.indexOf(PFX_SEARCH)))
check.SOLUTIONLINKTEXT[ccode] = trS('report.link.wiki');
else
if (-1 !== l.indexOf(PFX_FORUM))
diff --git a/src/release.js b/src/release.js
index c548bf3..6d95274 100644
--- a/src/release.js
+++ b/src/release.js
@@ -135,7 +135,7 @@ let wmeSDK;
/** @const */
var PFX_WIKI = 'https://www.waze.com/wiki/';
/** @const */
-var PFX_PEDIA = 'https://wazeopedia.waze.com/wiki/';
+var PFX_SEARCH = 'https://www.waze.com/discuss/search?q=';
/** @const */
var PFX_FORUM = 'https://www.waze.com/forum/viewtopic.php?';
/** @const */
diff --git a/src/report.js b/src/report.js
index 99ebdc3..f6ffef3 100644
--- a/src/report.js
+++ b/src/report.js
@@ -371,7 +371,7 @@ function F_SHOWREPORT(reportFormat) {
function addTextLabels(pack, label, defSet, oldPack) {
var defData = (defSet[label] || '')
.replace(new RegExp('^W:'), PFX_WIKI)
- .replace(new RegExp('^P:'), PFX_PEDIA)
+ .replace(new RegExp('^P:'), PFX_SEARCH)
.replace(new RegExp('^F:'), PFX_FORUM)
.replace(new RegExp('^D:'), PFX_DISCUSS)
;
@@ -380,14 +380,14 @@ function F_SHOWREPORT(reportFormat) {
var oldData = origData
.replace(new RegExp('^' + GL_TODOMARKER), '')
.replace(new RegExp('^W:'), PFX_WIKI)
- .replace(new RegExp('^P:'), PFX_PEDIA)
+ .replace(new RegExp('^P:'), PFX_SEARCH)
.replace(new RegExp('^F:'), PFX_FORUM)
.replace(new RegExp('^D:'), PFX_DISCUSS)
;
// preserve old data
var oldDataEN = (oldPack[label + '.en'] || '')
.replace(new RegExp('^W:'), PFX_WIKI)
- .replace(new RegExp('^P:'), PFX_PEDIA)
+ .replace(new RegExp('^P:'), PFX_SEARCH)
.replace(new RegExp('^F:'), PFX_FORUM)
.replace(new RegExp('^D:'), PFX_DISCUSS)
;
diff --git a/src/validate.js b/src/validate.js
index 8e5f573..985c4b1 100644
--- a/src/validate.js
+++ b/src/validate.js
@@ -2309,7 +2309,7 @@ function F_VALIDATE(disabledHL) {
let foundPublicConnection = checkPublicConnection(segment, null);
if (!foundPublicConnection) {
// We might have a isolated segment. Could be a Restricted Gate
- // See https://wazeopedia.waze.com/wiki/USA/Private_Installations#Specialty_Gate:_Restricted_Gate
+ // See: https://www.waze.com/discuss/t/private-installations/378216#p-2277317-specialty-gate-restricted-gate-30
if (nodeA.$otherSegmentsLen == 1 && nodeB.$otherSegmentsLen == 1) {
// both sides are connected to just one private segment
let nodeASegment = nodeA.$otherSegments[0];