From 684849a6670a8fd67855c43c99d064ad055daeb6 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 12:22:49 +0300 Subject: [PATCH 01/51] Gates for the guide defects Asciidoctor cannot see Four checks, split out of the structural repairs they were written alongside so each can be reviewed on its own terms. Every one was verified to fail when the defect it describes is reintroduced, and to pass again when it is reverted. check-guide-structure.py -- every document is in the book or declared out of it; no chapter silently becomes a part, a subsection, or a duplicate; and, by rendering the book and reading its headings back, every included chapter's title survives into the output. That last check is what would have caught a whole chapter rendering as subsections of the one before it. check-guide-xrefs.py -- every internal link resolves, and none renders as a bare "[some-id]". Asciidoctor reports neither: a reference carrying link text renders as an ordinary link to nowhere. check-missing-code-blocks.py -- prose that promises a listing where a hole follows. 406 exist, from the snippet extraction in bbdc6058f0, recoverable from bbdc6058f0~1. check-guide-links.py -- links checked against the paths the site actually serves, derived from _redirects and the Hugo content tree and followed through every redirect rule to what it produces, rather than accepted for matching one. The two ratchets may only shrink; growing one needs --allow-new, so recording debt is deliberate rather than a side effect of regenerating. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/developer-guide-docs.yml | 19 + .github/workflows/website-docs.yml | 11 + scripts/developer-guide/check-guide-links.py | 408 +++++++++++++++++ .../developer-guide/check-guide-structure.py | 324 ++++++++++++++ scripts/developer-guide/check-guide-xrefs.py | 112 +++++ .../check-missing-code-blocks.py | 195 +++++++++ .../developer-guide/guide-links-baseline.txt | 43 ++ .../missing-code-blocks-baseline.txt | 409 ++++++++++++++++++ 8 files changed, 1521 insertions(+) create mode 100755 scripts/developer-guide/check-guide-links.py create mode 100755 scripts/developer-guide/check-guide-structure.py create mode 100755 scripts/developer-guide/check-guide-xrefs.py create mode 100755 scripts/developer-guide/check-missing-code-blocks.py create mode 100644 scripts/developer-guide/guide-links-baseline.txt create mode 100644 scripts/developer-guide/missing-code-blocks-baseline.txt diff --git a/.github/workflows/developer-guide-docs.yml b/.github/workflows/developer-guide-docs.yml index 2d0df8a5a1b..7393eaee936 100644 --- a/.github/workflows/developer-guide-docs.yml +++ b/.github/workflows/developer-guide-docs.yml @@ -271,6 +271,25 @@ jobs: echo "Asciidoctor exited with status $STATUS — the final quality-gate step will fail the build." >&2 fi + # These four cover defects the gates above are structurally blind to: a + # chapter swallowed by the one before it, a cross-reference that resolves + # to nothing, prose that promises a code block which is not there, and a + # link the website does not serve. Asciidoctor reports none of them, and + # every one of them shipped. The structure and cross-reference checks + # render the book, so they must run after the Asciidoctor install. + - name: Check developer guide structure, cross-references, code blocks and links + run: | + set -euo pipefail + python3 scripts/developer-guide/check-guide-structure.py + python3 scripts/developer-guide/check-guide-xrefs.py + python3 scripts/developer-guide/check-missing-code-blocks.py + # Note this only catches a link the GUIDE breaks. When the website + # moves the route instead -- a page renamed, deleted or re-slugged -- + # the same script runs from website-docs.yml, which triggers on + # docs/website/**. Putting those paths here would run this whole job + # (maven install, demo build, screenshots) for every blog post. + python3 scripts/developer-guide/check-guide-links.py + - name: Build Developer Guide HTML and PDF if: github.event_name != 'pull_request' || steps.changes.outputs.docs == 'true' || steps.changes.outputs.demos == 'true' || steps.changes.outputs.workflow == 'true' run: | diff --git a/.github/workflows/website-docs.yml b/.github/workflows/website-docs.yml index 8fc0a7b1a02..fae57010a9f 100644 --- a/.github/workflows/website-docs.yml +++ b/.github/workflows/website-docs.yml @@ -277,6 +277,17 @@ jobs: --root-dir public public/**/*.html + # The developer guide links into this site, so a page renamed, deleted or + # re-slugged here breaks the guide. The check lives in THIS workflow rather + # than in developer-guide-docs.yml because it is the route data that + # changed: widening that workflow's paths to docs/website/** would run the + # full guide build -- maven install, demo build, screenshot generation -- + # on every blog post the daily publisher pushes, to run one Python script. + # This job already triggers on docs/website/**, and the check needs nothing + # but a checkout. + - name: Check developer guide links against the routes this site serves + run: python3 scripts/developer-guide/check-guide-links.py + - name: Reject absolute codenameone.com links run: | set -euo pipefail diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py new file mode 100755 index 00000000000..55f111a0747 --- /dev/null +++ b/scripts/developer-guide/check-guide-links.py @@ -0,0 +1,408 @@ +#!/usr/bin/env python3 +"""Check the developer guide's links against the site that has to serve them. + +Three failures the guide shipped, none of which any existing gate could see: + +* Fifteen ``codenameone.com/manual/.html`` deep links. ``_redirects`` + covers ``/manual`` and ``/manual/`` exactly and has no splat, so every one of + them 404s -- and every one points at a section inside this same book, which an + internal cross-reference would have reached. +* ``https://stackoverflow/tags/codenameone/`` -- a host with no dot in it, which + resolves nowhere. +* Plain ``http://`` links to hosts that have not answered on port 80 for years. + +Rather than curate a list of good links, this derives the set of paths the site +actually serves -- the redirect table plus the Hugo content tree -- and reports +any codenameone.com link that lands outside it. The baseline is a ratchet: it may +shrink, never grow. +""" +from __future__ import annotations + +import argparse +import collections +import datetime +import re +import sys +from pathlib import Path +from urllib.parse import urlsplit + +ASCIIDOC_EXTENSIONS = {".adoc", ".asciidoc"} +URL_RE = re.compile(r"\bhttps?://[^\s\[\]<>\"'`)]+") +# The one tree that genuinely cannot be enumerated from this repository: the +# Javadoc is produced from the framework sources at build time. Everything else, +# /developer-guide/ included, is derived below -- whitelisting a prefix silently +# exempts every path under it from the check. +GENERATED_PREFIXES = ("/javadoc/",) +# http:// is correct for these: RFC 3161 timestamping servers reject TLS, and +# example.com URLs are illustrative rather than fetched. +TLS_EXEMPT_HOSTS = {"timestamp.digicert.com", "example.com", "www.example.com"} +# Hosts with no dot that are still real destinations. +LOCAL_HOSTS = {"localhost", "127.0.0.1", "0.0.0.0"} +# Only the marketing site is served from the redirect table and the Hugo content +# tree. cloud.codenameone.com and friends are separate services. +SITE_HOSTS = {"codenameone.com", "www.codenameone.com"} + + +def front_matter(page: Path) -> dict[str, object]: + """Pull the few front-matter keys that decide a page's published route. + + Deliberately not a YAML parse: the tree mixes YAML and TOML front matter and + only three keys matter here. + """ + text = page.read_text(encoding="utf-8", errors="ignore") + lines = text.split("\n") + if not lines or lines[0].strip() not in {"---", "+++"}: + return {} + fence = lines[0].strip() + out: dict[str, object] = {} + aliases: list[str] = [] + in_aliases = False + for line in lines[1:]: + if line.strip() == fence: + break + if in_aliases: + stripped = line.strip() + if stripped in {"]", "],"}: + in_aliases = False + continue + # YAML block sequence ("- /x") and TOML/flow array ("\"/x\",") both + # appear in this tree, so accept either continuation shape. + if stripped.startswith("-") or stripped.startswith(("\"", "'")): + aliases.append(stripped.lstrip("- ").strip().rstrip(",").strip("\"'")) + continue + in_aliases = False + match = re.match(r'^(url|slug|aliases|draft|date)\s*[:=]\s*(.*)$', line) + if not match: + continue + key, raw = match.group(1), match.group(2).strip() + if key == "aliases": + if raw in {"", "[", "[]"}: + in_aliases = raw != "[]" + else: + aliases.extend(v.strip().strip("\"'") for v in raw.strip("[]").split(",") if v.strip()) + continue + out[key] = raw.strip("\"'") + if aliases: + out["aliases"] = aliases + return out + + +def is_published(meta: dict[str, object], today: str) -> bool: + """Hugo defaults buildDrafts and buildFuture to false, so neither reaches the site. + + The date test makes the result depend on the day it runs, which is not ideal in + a gate. It is kept because it mirrors what the site actually serves: a link to a + post that has not been published yet is genuinely broken until it is. + """ + if str(meta.get("draft", "")).strip().strip("\"'").lower() in {"true", "yes"}: + return False + date = str(meta.get("date", "")).strip().strip("\"'") + return not (re.match(r"^\d{4}-\d{2}-\d{2}", date) and date[:10] > today) + + +def normalize_path(value: str) -> str: + value = value.strip() + if not value: + return "" + if not value.startswith("/"): + value = "/" + value + return value.rstrip("/") or "/" + + +def redirect_pattern(source: str) -> tuple[re.Pattern[str], list[str]] | None: + """Compile a _redirects source that is not a literal path. + + Netlify sources may end in a `*` splat or contain `:placeholder` segments, and + 21 of the rules in this file do. Recording `/files/cn1libs/*` as a literal + string means a real link to `/files/cn1libs/foo.cn1lib` matches nothing and is + reported as broken. Returns the pattern and the capture names in order, so the + destination can be reconstructed from a match. + """ + if "*" not in source and ":" not in source: + return None + names: list[str] = [] + pattern = "" + for part in re.split(r"(\*|:[A-Za-z_][A-Za-z0-9_]*)", source): + if not part: + continue + if part == "*": + names.append("splat") + pattern += "(.*)" + elif part.startswith(":"): + names.append(part[1:]) + pattern += "([^/]+)" + else: + pattern += re.escape(part) + return re.compile("^" + pattern + "/?$"), names + + +def resolves(target: str, known: set[str], rules: list, depth: int = 0) -> bool: + """Whether a path is served, following wildcard redirects to their destination. + + Accepting every path that merely *matches* a wildcard source is the same + mistake as whitelisting a prefix. `/*.html -> /:splat/ 301` matches any + root-level .html path at all, so `/does-not-exist.html` would pass while + redirecting to a page that is not there. Substitute the captures into the + destination and check that instead. + """ + if target in known: + return True + if target.startswith(GENERATED_PREFIXES) or target + "/" in GENERATED_PREFIXES: + # Reachable both directly and by following a redirect into it, so the + # test belongs here rather than only at the call site. + return True + if depth > 4: # a redirect loop in the table should not hang the check + return False + for compiled, names, destination in rules: + match = compiled.match(target) + if not match: + continue + if not destination or not destination.startswith("/"): + return True # redirects off-site; nothing here can verify it + resolved = destination + for name, value in zip(names, match.groups()): + resolved = resolved.replace(":" + name, value or "") + resolved = normalize_path(resolved) + if resolved == target: + return False + if resolves(resolved, known, rules, depth + 1): + return True + return False + + +def site_paths(repo_root: Path) -> tuple[set[str], list]: + """Every path the website is known to answer on, derived rather than listed. + + Returns the literal paths and every redirect rule, each as a matcher, its + capture names and its destination, so a link can be followed rather than + accepted for merely matching. + """ + paths: set[str] = set() + patterns: list = [] + + redirects = repo_root / "docs/website/static/_redirects" + if redirects.exists(): + for line in redirects.read_text(encoding="utf-8").split("\n"): + parts = line.split() + if not parts or parts[0].startswith("#"): + continue + destination = parts[1] if len(parts) > 1 else "" + compiled = redirect_pattern(parts[0]) + if compiled is not None: + patterns.append((compiled[0], compiled[1], destination)) + else: + # A literal source is not a served route either -- it is a rule, + # and a rule pointing at a page that was deleted redirects the + # reader to a 404. Follow it like any other, rather than treating + # the fact that a rule exists as proof the link works. + patterns.append( + (re.compile("^" + re.escape(normalize_path(parts[0])) + "/?$"), [], destination) + ) + # Only the SOURCE counts. A rule whose destination was deleted still + # sits in this file, so trusting destinations would accept a guide + # link to a page that no longer exists. + + # Hugo's published route is the section path plus the page's slug, which + # 1055 of the content pages override; deriving it from the filename instead + # both invents routes that are never generated and rejects real ones. + # + # Known gap: taxonomy term pages (/tags//) are generated by Hugo from + # front-matter tags rather than from a file, so they are not derived here. No + # guide link targets one today. If one is ever added it will be reported as + # broken, which is the safe direction for a gate to be wrong in. + paths.add("/") # Hugo always renders the home page, _index.md or not + + # scripts/website/build.sh renders the guide to /developer-guide/ and rsyncs + # this directory alongside it so relative image links resolve, excluding the + # Sketch sources and the AsciiDoc itself. That makes every served path under + # the guide enumerable, so it does not need a blanket exemption. + guide = repo_root / "docs/developer-guide" + if guide.exists(): + paths.add("/developer-guide") + for asset in guide.rglob("*"): + if not asset.is_file(): + continue + relative = asset.relative_to(guide) + if relative.parts[0] == "sketch" or relative.suffix in {".asciidoc", ".adoc"}: + continue + paths.add(normalize_path("developer-guide/" + relative.as_posix())) + + today = datetime.date.today().isoformat() + content = repo_root / "docs/website/content" + if content.exists(): + for page in content.rglob("*.md"): + relative = page.relative_to(content).with_suffix("") + meta = front_matter(page) + if not is_published(meta, today): + continue + for alias in meta.get("aliases", []) or []: + if isinstance(alias, str): + paths.add(normalize_path(alias)) + if meta.get("url"): + paths.add(normalize_path(str(meta["url"]))) + continue + parts = list(relative.parts) + if parts and parts[-1] in {"_index", "index"}: + parts.pop() + if meta.get("slug"): + parts = parts[:-1] + [str(meta["slug"])] if parts else [str(meta["slug"])] + paths.add(normalize_path("/".join(parts)) if parts else "/") + + # Some redirects are written into _redirects at deploy time rather than + # committed, so the file in the tree does not list them. Read the paths out + # of the script that emits them instead of assuming a prefix is safe. + for emitter in sorted((repo_root / "scripts/website").glob("*redirect*.sh")): + for match in re.finditer( + r"printf\s+'(/[^\s']+)\s+%s[^']*'", emitter.read_text(encoding="utf-8") + ): + paths.add(normalize_path(match.group(1))) + + # Anything committed under static/ is served at its own path. + static = repo_root / "docs/website/static" + if static.exists(): + for asset in static.rglob("*"): + if not asset.is_file(): + # A directory is not a route. static/uploads holds assets and no + # index page, so recording the directory itself would accept a + # link to /uploads that resolves to nothing. + continue + paths.add(normalize_path(asset.relative_to(static).as_posix())) + if asset.name == "index.html": + paths.add(normalize_path(asset.parent.relative_to(static).as_posix())) + + return paths, patterns + + +def findings_for(path: Path, known: set[str], patterns: list) -> list[tuple[str, str]]: + out: list[tuple[str, str]] = [] + for number, line in enumerate(path.read_text(encoding="utf-8").split("\n"), 1): + for url in URL_RE.findall(line): + url = url.rstrip(".,;:") + split = urlsplit(url) + host = split.hostname or "" + if "." not in host and host not in LOCAL_HOSTS: + out.append((url, f"host '{host}' has no dot in it and resolves nowhere")) + continue + if split.scheme == "http" and host not in TLS_EXEMPT_HOSTS | LOCAL_HOSTS: + out.append((url, "plain http, not https")) + if host in SITE_HOSTS: + target = split.path.rstrip("/") or "/" + if not resolves(target, known, patterns): + out.append((url, "the website serves no such path (checked _redirects and the content tree)")) + return out + + +def load_baseline(path: Path) -> collections.Counter: + """Read the baseline as a multiset: one line per occurrence. + + A file that mentions the same broken URL twice has two problems, not one. + Collapsing them into a set understated the real count -- 35 recorded against + 38 occurrences -- and left a second occurrence of an already-baselined link + free to appear without the check noticing. + """ + if not path.exists(): + return collections.Counter() + return collections.Counter( + line.rstrip("\n") + for line in path.read_text(encoding="utf-8").split("\n") + if line.strip() and not line.startswith("#") + ) + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--guide-dir", default="docs/developer-guide", type=Path) + parser.add_argument("--repo-root", default=".", type=Path) + parser.add_argument( + "--baseline", default="scripts/developer-guide/guide-links-baseline.txt", type=Path + ) + parser.add_argument("--write-baseline", action="store_true") + parser.add_argument( + "--allow-new", + action="store_true", + help="permit --write-baseline to ADD entries; without it the baseline may only shrink", + ) + args = parser.parse_args() + + guide_dir = args.guide_dir.resolve() + known, patterns = site_paths(args.repo_root.resolve()) + if not known: + raise SystemExit("could not derive any site paths; is --repo-root correct?") + + current: collections.Counter = collections.Counter() + reasons: dict[str, str] = {} + for path in sorted(guide_dir.rglob("*")): + if path.suffix not in ASCIIDOC_EXTENSIONS or not path.is_file(): + continue + name = path.relative_to(guide_dir).as_posix() + for url, reason in findings_for(path, known, patterns): + entry = f"{name}\t{url}" + current[entry] += 1 + reasons[entry] = reason + + if args.write_baseline: + # The command that banks a fix is the same command that could bury a new + # failure. Shrinking is free; growing needs --allow-new, so recording new + # debt is a deliberate act that shows up in the command as well as in the + # baseline diff a reviewer reads. + added = sorted((current - load_baseline(args.baseline)).elements()) + if added and not args.allow_new: + for entry in added: + name, _, url = entry.partition("\t") + print(f"{name}: {url}", file=sys.stderr) + print( + f"\nRefusing to add {len(added)} entr(ies) to the baseline. Fix the " + f"link, or pass --allow-new if this is debt you mean to record.", + file=sys.stderr, + ) + return 1 + args.baseline.write_text( + "\n".join( + [ + "# Developer guide links that do not resolve, or are not TLS.", + "# One line per occurrence: a file naming the same bad URL twice gets", + "# two lines, because that is two things to fix.", + "# A ratchet: entries may be removed as links are fixed, never added.", + "# Regenerate with check-guide-links.py --write-baseline.", + ] + + sorted(current.elements()) + ) + + "\n", + encoding="utf-8", + ) + print(f"Wrote baseline with {sum(current.values())} entr(ies).") + return 0 + + baseline = load_baseline(args.baseline) + new = sorted((current - baseline).elements()) + # A baselined entry that no longer reproduces has to leave the file. Leaving it + # keeps a slot open: a later change can restore that exact file+URL and + # `current - baseline` stays empty, so the regression sails through. The + # ratchet only ratchets if fixes are banked. + stale = sorted((baseline - current).elements()) + if new or stale: + for entry in new: + name, _, url = entry.partition("\t") + print(f"{name}: {url} -- {reasons[entry]}", file=sys.stderr) + for entry in stale: + name, _, url = entry.partition("\t") + print( + f"{name}: {url} -- no longer broken, but still in the baseline. Run " + f"check-guide-links.py --write-baseline to bank the fix.", + file=sys.stderr, + ) + print( + f"\n{len(new)} new broken or insecure link(s), {len(stale)} stale baseline entr(ies).", + file=sys.stderr, + ) + return 1 + + print( + f"Links: {sum(current.values())} known bad link(s) against {len(known)} known site paths " + f"and {len(patterns)} redirect rule(s); none new, none stale." + ) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/developer-guide/check-guide-structure.py b/scripts/developer-guide/check-guide-structure.py new file mode 100755 index 00000000000..94eabec1adc --- /dev/null +++ b/scripts/developer-guide/check-guide-structure.py @@ -0,0 +1,324 @@ +#!/usr/bin/env python3 +"""Verify that the developer guide's book structure is what the manifest says. + +Three defects motivated this check, all of which shipped in a green build: + +* ``Working-With-Linux.asciidoc`` was included on the line directly after + ``Working-With-Windows.asciidoc``, whose last line is a paragraph. After + include expansion the Linux chapter's ``== `` title became a continuation of + that paragraph, so the whole chapter rendered as subsections of the Windows + chapter and its title vanished. Asciidoctor reports nothing. +* Three chapters opened with a level-0 ``= `` heading. Under ``doctype: book`` + that turns each into a *part*, promotes its own sections to chapters and drops + its title from the numbered sequence. Also silent. +* Six complete chapters sat in the tree while being included by nothing, so they + never reached a reader at all. + +The first two are caught by rendering the book and checking that every included +chapter's title survives into the output; the third by walking the include graph. +""" +from __future__ import annotations + +import argparse +import collections +import html +import re +import subprocess +import sys +import tempfile +from pathlib import Path + +ASCIIDOC_EXTENSIONS = {".adoc", ".asciidoc"} +INCLUDE_RE = re.compile(r"^include::([^\[]+)\[([^\]]*)\]\s*$") +HEADING_RE = re.compile(r"^(=+) +(\S.*)$") +# Literal-content blocks only. The container delimiters -- ==== example, +# **** sidebar, ____ quote -- hold ordinary AsciiDoc, so an include or a heading +# inside one is real and must not be skipped. +FENCE_RE = re.compile(r"^(----|\.\.\.\.|````|\+\+\+\+)\s*$") +# Inline AsciiDoc markup that never survives into the rendered heading text. +INLINE_MARKUP_RE = re.compile(r"[`*_#]|\[\[[^\]]*\]\]|\[[^\]]*\]") + + +def parse_lines(path: Path) -> list[str]: + return path.read_text(encoding="utf-8").split("\n") + + +def first_heading(path: Path) -> tuple[int, str] | None: + """Return (level, title) of the file's first heading outside a fenced block.""" + in_fence = False + for line in parse_lines(path): + if FENCE_RE.match(line): + in_fence = not in_fence + continue + if in_fence: + continue + match = HEADING_RE.match(line) + if match: + return len(match.group(1)), match.group(2).strip() + return None + + +def normalize(title: str) -> str: + """Reduce a heading to something comparable across AsciiDoc and HTML.""" + text = html.unescape(title) + text = INLINE_MARKUP_RE.sub("", text) + return re.sub(r"\s+", " ", text).strip().lower() + + +class Walker: + """Expands the include graph, recording every edge for the adjacency check.""" + + def __init__(self, root: Path, guide_dir: Path) -> None: + self.root = root + self.guide_dir = guide_dir + self.reachable: dict[Path, str] = {} + self.direct: set[Path] = set() + # Direct entries that sit inside an ifdef/ifndef region. Only one branch + # renders, so the outcome check cannot demand every branch's title. + self.conditional: set[Path] = set() + # Counted at the EDGE, not per visited file: _visit returns early on a + # revisit, so a document included twice would otherwise leave no trace. + # Only direct manifest entries are counted. A nested fragment may be + # reused from two parents on purpose, and a file included under + # mutually exclusive ifdef/ifndef branches appears twice in the source + # while rendering once -- neither is a duplicated chapter. + self.direct_include_count: collections.Counter = collections.Counter() + self.errors: list[str] = [] + self._visit(root, "") + + def _visit(self, path: Path, attrs_from_parent: str) -> None: + if path in self.reachable: + return + self.reachable[path] = attrs_from_parent + lines = parse_lines(path) + in_fence = False + for index, line in enumerate(lines): + if FENCE_RE.match(line): + in_fence = not in_fence + continue + if in_fence: + continue + match = INCLUDE_RE.match(line) + if not match: + continue + target_raw, attrs = match.group(1), match.group(2) + target = (path.parent / target_raw).resolve() + if target.suffix not in ASCIIDOC_EXTENSIONS: + continue # a snippet include, validated by validate-guide-snippets.py + if not target.exists(): + self.errors.append( + f"{path.name}:{index + 1}: include target does not exist: {target_raw}" + ) + continue + if path == self.root: + # A conditional entry is still a chapter: it must open at chapter + # level and be spaced correctly. Only the DUPLICATE count skips + # it, because the same chapter under two exclusive branches + # appears twice in the source and once in the output. + self.direct.add(target) + self._check_manifest_spacing(index, lines, target_raw) + if self._inside_conditional(lines, index): + self.conditional.add(target) + else: + self.direct_include_count[target] += 1 + self._visit(target, attrs) + + @staticmethod + def _inside_conditional(lines: list[str], index: int) -> bool: + """Whether this line sits inside an ifdef/ifndef/ifeval region. + + A chapter included once per branch of a conditional appears twice in the + source and once in the output, so counting it as a duplicate would reject + valid markup. + """ + depth = 0 + for line in lines[:index]: + if re.match(r"^(ifdef|ifndef|ifeval)::.*\[\s*\]\s*$", line): + depth += 1 + elif re.match(r"^endif::", line): + depth = max(0, depth - 1) + return depth > 0 + + def _check_manifest_spacing(self, index: int, lines: list[str], target_raw: str) -> None: + """Require a blank line after every include in the top-level manifest. + + Two adjacent include lines put the first target's last line next to the + second target's first line. When the first ends on a paragraph, the second + chapter's title becomes a continuation of it and the chapter disappears + without a single warning -- which is exactly how the native Linux chapter + spent its life rendered as subsections of the Windows one. + """ + following = lines[index + 1] if index + 1 < len(lines) else "" + # A preprocessor directive is not content and cannot absorb a paragraph, + # so an include closed by endif:: on the next line is correctly spaced. + if re.match(r"^(ifdef|ifndef|ifeval|endif)::", following.strip()): + return + if following.strip(): + self.errors.append( + f"developer-guide.asciidoc:{index + 1}: include of {target_raw} is not " + f"followed by a blank line. Two adjacent includes let the first " + f"chapter's trailing paragraph swallow the second chapter's title." + ) + + +def render(root: Path) -> str: + with tempfile.TemporaryDirectory() as tmp: + out = Path(tmp) / "guide.html" + result = subprocess.run( + ["asciidoctor", "--require", "rouge", "-o", str(out), str(root)], + capture_output=True, + text=True, + ) + if result.returncode != 0: + print(result.stderr, file=sys.stderr) + raise SystemExit("asciidoctor failed to render the guide") + return out.read_text(encoding="utf-8") + + +def rendered_titles(markup: str) -> dict[str, int]: + """Count every rendered heading, normalized and stripped of its number.""" + body = markup.split('id="content"', 1)[-1] + counts: dict[str, int] = {} + for match in re.finditer(r"]*>(.*?)", body, re.S): + text = re.sub(r"<[^>]+>", "", match.group(2)) + text = re.sub(r"^(Appendix [A-Z]:|(\d+|[A-Z])(\.\d+)*\.)\s*", "", html.unescape(text).strip()) + key = normalize(text) + counts[key] = counts.get(key, 0) + 1 + return counts + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--guide-dir", default="docs/developer-guide", type=Path) + args = parser.parse_args() + + guide_dir = args.guide_dir.resolve() + root = guide_dir / "developer-guide.asciidoc" + if not root.exists(): + raise SystemExit(f"guide root not found: {root}") + + walker = Walker(root, guide_dir) + errors = list(walker.errors) + + # A chapter included twice by the manifest is rendered twice. The title check + # below cannot see it, because it only asks whether a title appears AT LEAST + # as often as it is declared. + for path, count in sorted(walker.direct_include_count.items()): + if count > 1: + errors.append( + f"{path.name}: is included {count} times, so the book renders it " + f"{count} times. Remove the duplicate include." + ) + + # 1. Every chapter in the tree is either in the book or declared out of it. + declared_path = guide_dir / "not-in-book.txt" + declared = set() + if declared_path.exists(): + for line in declared_path.read_text(encoding="utf-8").split("\n"): + line = line.split("#", 1)[0].strip() + if line: + declared.add(line) + + on_disk = { + path.resolve() + for path in guide_dir.rglob("*") + if path.suffix in ASCIIDOC_EXTENSIONS and path.is_file() + } + unreachable = sorted(on_disk - set(walker.reachable)) + for path in unreachable: + name = path.relative_to(guide_dir).as_posix() + if name not in declared: + errors.append( + f"{name}: present in the guide directory but included by nothing, so it " + f"never reaches a reader. Include it, delete it, or list it in " + f"not-in-book.txt with a reason." + ) + reachable_names = {p.relative_to(guide_dir).as_posix() for p in walker.reachable} + for name in sorted(declared & reachable_names): + errors.append(f"not-in-book.txt lists {name}, but it is included. Remove the entry.") + + # 2. A chapter's own heading level decides whether it is a chapter at all. + # A level-0 heading turns it into a book PART; a level-3 heading (or none) + # makes it a subsection of whatever chapter precedes it. Both nest silently, + # and the rendered-title check below cannot see either, because it accepts a + # title at any depth. Only entries the manifest includes DIRECTLY are held + # to this: nested fragments such as the appendix_goal_* files legitimately + # start at level 3 under their parent. + for path, attrs in sorted(walker.reachable.items()): + if path == root: + continue + heading = first_heading(path) + if heading and heading[0] == 1 and "leveloffset" not in attrs: + errors.append( + f"{path.name}: opens with a level-0 '= {heading[1]}' heading. Under " + f"doctype:book that renders as a PART and promotes its own sections to " + f"chapters. Use '== ' or include it with leveloffset=+1." + ) + if path not in walker.direct: + continue + if heading is None: + errors.append( + f"{path.name}: is included directly by developer-guide.asciidoc but has " + f"no heading, so its content is absorbed into the chapter before it." + ) + continue + # A leveloffset shifts every heading in the included file, so what decides + # whether this renders as a chapter is the declared level PLUS the offset. + # Exempting offset includes entirely would leave the same nesting bug one + # step further along: '== Chapter' at leveloffset=+1 renders as a + # subsection, and the outcome check cannot see it because it accepts a + # title at any depth. + offset = 0 + match = re.search(r"leveloffset=([+-]?\d+)", attrs) + if match: + offset = int(match.group(1)) + effective = heading[0] + offset + if effective != 2: + detail = ( + f"level {heading[0]} with leveloffset={offset:+d}" + if offset + else f"level {heading[0]}" + ) + errors.append( + f"{path.name}: is included directly by developer-guide.asciidoc at " + f"{detail}, so it renders at level {effective} rather than as a chapter. " + f"A direct manifest entry must come out at level 2." + ) + + # 3. Outcome check: every included chapter's title survives into the book. + rendered = rendered_titles(render(root)) + expected: dict[str, list[str]] = {} + for path in sorted(walker.reachable): + if path == root or path in walker.conditional: + # A conditional entry renders in one branch only, so requiring its + # title in this render would report a chapter that is deliberately + # absent. Its level and spacing are still checked above. + continue + heading = first_heading(path) + if heading: + expected.setdefault(normalize(heading[1]), []).append(path.name) + for title, sources in sorted(expected.items()): + # Compare counts, not membership: a chapter sharing its title with another + # heading would otherwise hide the fact that it was swallowed. + if rendered.get(title, 0) < len(sources): + errors.append( + f"{', '.join(sources)}: the title '{title}' appears " + f"{rendered.get(title, 0)} time(s) in the rendered book but " + f"{len(sources)} document(s) declare it. A chapter was swallowed by " + f"whatever precedes it." + ) + + if errors: + for error in errors: + print(f"::error::{error}" if sys.stdout.isatty() is False else error, file=sys.stderr) + print(f"\n{len(errors)} guide structure problem(s).", file=sys.stderr) + return 1 + print( + f"Guide structure OK: {len(walker.reachable) - 1} included documents, " + f"{len(declared)} declared out of book." + ) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/developer-guide/check-guide-xrefs.py b/scripts/developer-guide/check-guide-xrefs.py new file mode 100755 index 00000000000..e1fe0a5049d --- /dev/null +++ b/scripts/developer-guide/check-guide-xrefs.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python3 +"""Report developer guide cross-references that point at nothing. + +Asciidoctor does not fail, or even warn, on a dangling internal reference. A +bare ``<>`` at least renders as the literal text ``[missing]``, which a +reader might notice; but ``<>`` renders as an ordinary link +with the right words and a href to an id that does not exist, so it looks +perfectly fine and silently goes nowhere. The introduction shipped two of those +pointing at an "Application Lifecycle" sidebar nobody ever wrote. + +Working from the rendered HTML rather than the AsciiDoc source means both forms +are caught, along with anchors declared in any of AsciiDoc's several syntaxes. +""" +from __future__ import annotations + +import argparse +import re +import subprocess +import sys +import tempfile +from collections import defaultdict +from pathlib import Path + +ID_RE = re.compile(r'\bid="([^"]+)"') +HREF_RE = re.compile(r'href="#([^"]+)"') +# Asciidoctor falls back to printing the raw id in brackets when a reference +# resolves to an anchor that carries no title -- an anchor on an image or a +# paragraph rather than on a section. The link works; the sentence reads +# "see [watch-complications]". +RAW_ID_LINK_RE = re.compile(r'\[\1\]') +# Anchor syntaxes, used only to point the reader at the offending source file. +ANCHOR_SOURCE_RE = re.compile(r"<<([^>,]+)") + + +def render(root: Path) -> str: + with tempfile.TemporaryDirectory() as tmp: + out = Path(tmp) / "guide.html" + result = subprocess.run( + ["asciidoctor", "--require", "rouge", "-o", str(out), str(root)], + capture_output=True, + text=True, + ) + if result.returncode != 0: + print(result.stderr, file=sys.stderr) + raise SystemExit("asciidoctor failed to render the guide") + return out.read_text(encoding="utf-8") + + +def source_locations(guide_dir: Path, target: str) -> list[str]: + """Find where a dangling target is referenced, so the error is actionable.""" + hits = [] + for path in sorted(guide_dir.rglob("*")): + if path.suffix not in {".adoc", ".asciidoc"} or not path.is_file(): + continue + for number, line in enumerate(path.read_text(encoding="utf-8").split("\n"), 1): + for match in ANCHOR_SOURCE_RE.finditer(line): + if match.group(1).strip() == target: + hits.append(f"{path.name}:{number}") + return hits + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--guide-dir", default="docs/developer-guide", type=Path) + args = parser.parse_args() + + guide_dir = args.guide_dir.resolve() + root = guide_dir / "developer-guide.asciidoc" + markup = render(root) + + ids = set(ID_RE.findall(markup)) + dangling: dict[str, int] = defaultdict(int) + for target in HREF_RE.findall(markup): + if target not in ids: + dangling[target] += 1 + + raw_id_links: dict[str, int] = defaultdict(int) + for target in RAW_ID_LINK_RE.findall(markup): + raw_id_links[target] += 1 + + if not dangling and not raw_id_links: + print(f"Cross-references OK: {len(ids)} anchors, every internal link resolves.") + return 0 + + for target in sorted(dangling): + where = source_locations(guide_dir, target) + location = ", ".join(where) if where else "not found in source (generated content?)" + print( + f"{location}: <<{target}>> points at an id that does not exist in the " + f"rendered book ({dangling[target]} reference(s)).", + file=sys.stderr, + ) + for target in sorted(raw_id_links): + where = source_locations(guide_dir, target) + location = ", ".join(where) if where else "unknown" + print( + f"{location}: <<{target}>> resolves to an anchor with no title, so the " + f"sentence renders the raw id as \"[{target}]\" " + f"({raw_id_links[target]} reference(s)). Give the reference link text " + f"(<<{target},some words>>) or move the anchor onto the section.", + file=sys.stderr, + ) + print( + f"\n{len(dangling)} dangling and {len(raw_id_links)} untitled " + f"cross-reference target(s).", + file=sys.stderr, + ) + return 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/developer-guide/check-missing-code-blocks.py b/scripts/developer-guide/check-missing-code-blocks.py new file mode 100755 index 00000000000..c486f434842 --- /dev/null +++ b/scripts/developer-guide/check-missing-code-blocks.py @@ -0,0 +1,195 @@ +#!/usr/bin/env python3 +"""Find prose that promises a code block where no block follows. + +Commit bbdc6058f0 ("Extract developer guide snippets into demos") converted +inline listings into ``include::`` directives and dropped roughly 415 of them on +the floor, leaving the introducing sentence, its colon, and two blank lines where +the code used to be. The Commerce chapter documents a paid service and, after +that pass, contained no code at all. + +``validate-guide-snippets.py`` cannot see this: it validates the blocks that are +present, not the ones that should be. The signature here is the hole itself -- +a sentence ending in a colon followed by two blank lines, which is what a removed +block leaves behind (a real block is separated from its introduction by exactly +one blank line). + +The baseline is a ratchet: it may shrink, never grow. Entries are keyed by the +text of the promising sentence rather than by line number, so ordinary editing +elsewhere in a chapter does not churn the file. +""" +from __future__ import annotations + +import argparse +import collections +import re +import sys +from pathlib import Path + +ASCIIDOC_EXTENSIONS = {".adoc", ".asciidoc"} +# Only blocks whose CONTENT is literal: listing, literal, fenced code and +# passthrough. The container delimiters -- ==== example, **** sidebar, ____ quote +# -- hold ordinary prose, and skipping them hid six real holes in basics.asciidoc +# alone, among them the setSameWidth example this check was written to find. +FENCE_RE = re.compile(r"^(----|\.\.\.\.|````|\+\+\+\+)\s*$") +# Lines that end in a colon without promising a listing: headings, attributes, +# comments, block titles, list markers, table cells and block delimiters. +NON_PROSE_PREFIX = ("//", "|", "=", ".", ":", "*", "-", "+", "[", "<") +# A list marker is followed by whitespace; a block title (.Title) and bold text +# (*text*) are not. Stripping the marker lets the prose test see the sentence, +# so an introduction written as a list item is not mistaken for markup. +LIST_MARKER_RE = re.compile(r"^([*\-]+|\.{1,5}|[0-9]+\.)\s+") +# What a real block looks like when it starts. An introduction separated from its +# listing by more than one blank line is untidy, not a hole, and reporting it +# would make the gate reject valid AsciiDoc spacing. Deliberately conservative: +# only unambiguous starts, so a genuine hole is never explained away. +BLOCK_START_RE = re.compile( + r'^(\[[a-zA-Z%.#"]|image::|include::|\|===|(----|\.\.\.\.|````|\+\+\+\+|====|\*\*\*\*|____)\s*$)' +) + + +def normalize(line: str) -> str: + return re.sub(r"\s+", " ", line.strip()) + + +def scan(path: Path) -> list[tuple[int, str]]: + lines = path.read_text(encoding="utf-8").split("\n") + in_fence = False + findings = [] + for index, line in enumerate(lines): + if FENCE_RE.match(line): + in_fence = not in_fence + continue + if in_fence: + continue + stripped = line.rstrip() + if not stripped.endswith(":"): + continue + body = stripped.lstrip() + marker = LIST_MARKER_RE.match(body) + if marker: + body = body[marker.end():] + if not body or body.startswith(NON_PROSE_PREFIX): + continue + if index + 2 >= len(lines): + continue + if lines[index + 1].strip() or lines[index + 2].strip(): + continue + following = index + 1 + while following < len(lines) and not lines[following].strip(): + following += 1 + if following < len(lines) and BLOCK_START_RE.match(lines[following].strip()): + continue + findings.append((index + 1, normalize(stripped))) + return findings + + +def load_baseline(path: Path) -> collections.Counter: + """Read the baseline as a multiset: one line per occurrence. + + Two identical introducing sentences in one chapter are two holes to fill, and + keying by text alone would let the second appear for free. + """ + baseline: collections.Counter = collections.Counter() + if not path.exists(): + return baseline + for raw in path.read_text(encoding="utf-8").split("\n"): + if raw.startswith("#") or not raw.strip(): + continue + name, _, text = raw.rstrip("\n").partition("\t") + if text: + baseline[f"{name}\t{text}"] += 1 + return baseline + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--guide-dir", default="docs/developer-guide", type=Path) + parser.add_argument( + "--baseline", + default="scripts/developer-guide/missing-code-blocks-baseline.txt", + type=Path, + ) + parser.add_argument( + "--write-baseline", + action="store_true", + help="rewrite the baseline from the current tree", + ) + parser.add_argument( + "--allow-new", + action="store_true", + help="permit --write-baseline to ADD entries; without it the baseline may only shrink", + ) + args = parser.parse_args() + + guide_dir = args.guide_dir.resolve() + current: collections.Counter = collections.Counter() + located: dict[str, list[int]] = {} + for path in sorted(guide_dir.rglob("*")): + if path.suffix not in ASCIIDOC_EXTENSIONS or not path.is_file(): + continue + name = path.relative_to(guide_dir).as_posix() + for number, text in scan(path): + entry = f"{name}\t{text}" + current[entry] += 1 + located.setdefault(entry, []).append(number) + + if args.write_baseline: + # Same reasoning as check-guide-links.py: the command that banks a fix + # must not silently bury a new hole. + added = sorted((current - load_baseline(args.baseline)).elements()) + if added and not args.allow_new: + for entry in added: + print(entry.replace("\t", ": "), file=sys.stderr) + print( + f"\nRefusing to add {len(added)} entr(ies) to the baseline. Restore the " + f"block, or pass --allow-new if this is debt you mean to record.", + file=sys.stderr, + ) + return 1 + lines = [ + "# Prose that promises a code block where none follows.", + "# A ratchet: entries may be removed as holes are filled, never added.", + "# Regenerate with check-missing-code-blocks.py --write-baseline.", + ] + lines.extend(sorted(current.elements())) + args.baseline.write_text("\n".join(lines) + "\n", encoding="utf-8") + total = sum(current.values()) + print(f"Wrote baseline with {total} entr(ies).") + return 0 + + baseline = load_baseline(args.baseline) + new: list[str] = [] + for entry in sorted((current - baseline).elements()): + name, _, text = entry.partition("\t") + where = ", ".join(str(n) for n in located.get(entry, [])) + new.append(f"{name}:{where}: promises a code block that is not there: {text[:100]}") + + # A filled hole has to leave the baseline. Leaving it keeps a slot open: a + # later change can empty that exact block again and `current - baseline` stays + # empty, so the regression passes. The ratchet only ratchets if fixes are banked. + stale: list[str] = [] + for entry in sorted((baseline - current).elements()): + name, _, text = entry.partition("\t") + stale.append( + f"{name}: filled, but still in the baseline: {text[:80]}. Run " + f"check-missing-code-blocks.py --write-baseline to bank the fix." + ) + + total = sum(current.values()) + if new or stale: + for entry in new + stale: + print(entry, file=sys.stderr) + print( + f"\n{len(new)} new hole(s) and {len(stale)} stale baseline entr(ies). Restore " + f"the block (the originals are recoverable from bbdc6058f0~1) or rewrite the " + f"sentence so it stops promising one.", + file=sys.stderr, + ) + return 1 + + print(f"Missing code blocks: {total} known hole(s), none new, none stale.") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/developer-guide/guide-links-baseline.txt b/scripts/developer-guide/guide-links-baseline.txt new file mode 100644 index 00000000000..c2d739300eb --- /dev/null +++ b/scripts/developer-guide/guide-links-baseline.txt @@ -0,0 +1,43 @@ +# Developer guide links that do not resolve, or are not TLS. +# One line per occurrence: a file naming the same bad URL twice gets +# two lines, because that is two things to fix. +# A ratchet: entries may be removed as links are fixed, never added. +# Regenerate with check-guide-links.py --write-baseline. +About-This-Guide.asciidoc http://github.com/chen-fishbein/ +About-This-Guide.asciidoc http://github.com/shannah/ +Advanced-Theming.asciidoc http://freebiesbug.com/psd-freebies/iphone-6-ui-kit/ +Advanced-Theming.asciidoc https://www.codenameone.com/files/iOS_UI-Kit.psd +Advanced-Topics-Under-The-Hood.asciidoc http://developer.android.com/reference/android/content/Context.html +Advanced-Topics-Under-The-Hood.asciidoc http://developer.freshdesk.com/mobihelp/android/api/reference/com/freshdesk/mobihelp/Mobihelp.html +Advanced-Topics-Under-The-Hood.asciidoc http://developer.freshdesk.com/mobihelp/android/api/reference/com/freshdesk/mobihelp/Mobihelp.html +Advanced-Topics-Under-The-Hood.asciidoc http://developer.freshdesk.com/mobihelp/android/api/reference/com/freshdesk/mobihelp/package-summary.html +Advanced-Topics-Under-The-Hood.asciidoc http://developer.freshdesk.com/mobihelp/android/api/reference/com/freshdesk/mobihelp/package-summary.html +Advanced-Topics-Under-The-Hood.asciidoc http://developer.freshdesk.com/mobihelp/android/integration_guide/ +Advanced-Topics-Under-The-Hood.asciidoc http://developer.freshdesk.com/mobihelp/ios/api/ +Advanced-Topics-Under-The-Hood.asciidoc http://developer.freshdesk.com/mobihelp/ios/api/ +Advanced-Topics-Under-The-Hood.asciidoc http://developer.freshdesk.com/mobihelp/ios/integration_guide/ +Advanced-Topics-Under-The-Hood.asciidoc http://developer.freshdesk.com/mobihelp/ios/integration_guide/#getting-started +Advanced-Topics-Under-The-Hood.asciidoc http://groovy-lang.org/ +Advanced-Topics-Under-The-Hood.asciidoc http://jruby.org/ +Advanced-Topics-Under-The-Hood.asciidoc http://shannah.github.io/cn1-freshdesk/ +Advanced-Topics-Under-The-Hood.asciidoc http://stackoverflow.com/questions/11421048/android-ios-custom-uri-protocol-handling +Advanced-Topics-Under-The-Hood.asciidoc http://www.mirah.org/ +Introduction.asciidoc http://teavm.org +Introduction.asciidoc http://www.xmlvm.org/ +Miscellaneous-Features.asciidoc http://wiki.akosma.com/IPhone_URL_Schemes +The-Components-Of-Codename-One.asciidoc http://awoiaf.westeros.org/index.php/A_Game_of_Thrones +The-Components-Of-Codename-One.asciidoc http://awoiaf.westeros.org/index.php/Portal:Books +The-Components-Of-Codename-One.asciidoc http://www.georgerrmartin.com/ +The-EDT---Event-Dispatch-Thread.asciidoc http://foxtrot.sourceforge.net/ +basics.asciidoc http://docs.oracle.com/Java +basics.asciidoc http://www.miglayout.com/QuickStart.pdf +graphics.asciidoc http://fontello.com/ +io.asciidoc http://twillo.com/ +io.asciidoc http://www.anapioficeandfire.com/api/characters?page=5&pageSize=3 +io.asciidoc http://www.codenameone.com/javadoc/com/codename1/io/ConnectionRequest.html +io.asciidoc http://www.codenameone.com/javadoc/com/codename1/io/NetworkManager.html +performance.asciidoc http://optipng.sourceforge.net/ +signing.asciidoc http://developer.android.com/guide/publishing/app-signing.html +signing.asciidoc http://developer.apple.com/ +signing.asciidoc http://get.udid.io/ +signing.asciidoc http://stackoverflow.com/questions/6320255/if-i-revoke-an-existing-distribution-certificate-will-it-mess-up-anything-with diff --git a/scripts/developer-guide/missing-code-blocks-baseline.txt b/scripts/developer-guide/missing-code-blocks-baseline.txt new file mode 100644 index 00000000000..d5a5f1f6104 --- /dev/null +++ b/scripts/developer-guide/missing-code-blocks-baseline.txt @@ -0,0 +1,409 @@ +# Prose that promises a code block where none follows. +# A ratchet: entries may be removed as holes are filled, never added. +# Regenerate with check-missing-code-blocks.py --write-baseline. +3D-Graphics.asciidoc ARGB pixels: +3D-Graphics.asciidoc Querying capabilities at runtime: +3D-Graphics.asciidoc own material, so a textured model renders with no extra setup: +Advanced-Topics-Under-The-Hood.asciidoc For the release build, you will also need to inject some proguard configuration so that important classes don't get stripped out at build time. The FreshDesk SDK instructions state: +Advanced-Topics-Under-The-Hood.asciidoc You can override these methods in the draggable components: +Advertising.asciidoc (for example "Sponsored"): +Advertising.asciidoc anchored at the top or bottom) and call `load()`: +Advertising.asciidoc identifier. The recommended order is to initialize, gather consent, then load: +Advertising.asciidoc manager and provider handle the foreground hook and freshness window for you: +Advertising.asciidoc method that registers its provider with `AdManager`: +Advertising.asciidoc next one when the current ad is dismissed: +Advertising.asciidoc rewards, verify server side rather than trusting the client: +Advertising.asciidoc transitions, no more often than a given interval: +Ai-And-Speech.asciidoc `ChatMessage` values to JSON under a named key: +Ai-And-Speech.asciidoc `SecureStorage` overloads: +Ai-And-Speech.asciidoc `chatStream(...)` can mutate the view directly: +Ai-And-Speech.asciidoc `cn1-ai-stablediffusion` cn1lib (when present in the consumer project): +Ai-And-Speech.asciidoc accepts either inline bytes plus a MIME type or a remote HTTPS URL: +Ai-And-Speech.asciidoc and streams the same text into a `ChatView`: +Ai-And-Speech.asciidoc calling `cancel()` on the resource closes the underlying socket: +Ai-And-Speech.asciidoc clustering: +Ai-And-Speech.asciidoc conversation: +Ai-And-Speech.asciidoc one user message: +Ai-And-Speech.asciidoc returns a string the runtime can hand to `JSONParser`: +Ai-And-Speech.asciidoc safe to log: +Ai-And-Speech.asciidoc you need a custom send pipeline: +Analytics.asciidoc Consent is broken down by category, so you can honor granular choices -- for example allowing crash reporting while declining behavioral analytics: +Analytics.asciidoc Each device is identified by a pseudonymous client id. It's generated on first use and stored locally -- it isn't derived from any hardware identifier. To honor an erasure request ("right to be forgotten"), reset it: +Analytics.asciidoc If you would rather not gate at all, switch the default so collection is active unless the user withdraws it. This places the compliance responsibility on you as the integrator: +Analytics.asciidoc If your application has already obtained consent through its own mechanism -- a custom prompt, a third-party consent-management platform, an enterprise device-management policy, or a jurisdiction where you have determined consent isn't required -- record it once at startup so reporting flows without a second prompt: +Analytics.asciidoc Once at least one provider is registered, report usage from anywhere in your app: +Analytics.asciidoc You can also seed every category and then revoke just one with the builder, for example to allow analytics but not ad storage: +Analytics.asciidoc `FirebaseAnalyticsProvider` forwards to the native Firebase Analytics SDK on Android and iOS. Register it like any other provider: +Analytics.asciidoc `GoogleAnalyticsProvider` uses the GA4 Measurement Protocol. Create it with a measurement id (`G-XXXXXXXX`) and a Measurement Protocol API secret from the GA4 admin console: +Analytics.asciidoc `MatomoAnalyticsProvider` targets Matomo (formerly Piwik) through its HTTP tracking API. Matomo can be self-hosted and supports IP anonymization, which makes it a good fit for privacy-sensitive deployments: +Animations.asciidoc That one command will enable swiping back from `currentForm`. https://www.codenameone.com/javadoc/com/codename1/util/LazyValue.html[LazyValue] allows you to pass a value lazily: +Animations.asciidoc builder: +Annotation-Component-Binding.asciidoc ASM and inserts the equivalent of: +Annotation-Component-Binding.asciidoc After binding, drive validation through the returned handle: +Annotation-JSON-XML-Mapping.asciidoc Hand-write a `Mapper` and register it at startup: +Annotation-JSON-XML-Mapping.asciidoc mutation: +Annotation-SQLite-ORM.asciidoc dao surface isn't enough. Transactions: +App-Review.asciidoc By default the low-rating feedback is collected through an e-mail to the address passed to `setSupportEmail(String)`. To deliver feedback through your own backend, register a `FeedbackListener`: +App-Review.asciidoc Rather than picking the moment yourself, you can let `AppReview` decide based on simple engagement heuristics: how many times the app was launched, how long ago it was installed, and how long since it last asked. Configure it once (for example in your app's `init` or `start` method) and call `registerSession()` on every launch: +App-Review.asciidoc The simplest usage is a single call at a moment that makes sense in your app -- typically right after the user completed something rewarding (finished a level, saved a document, completed an order): +Apple-Wallet-Extension.asciidoc In Java, publish the user's cards whenever they change (typically after login) and keep a fresh token published so Wallet can skip the login screen: +Authentication-And-Identity.asciidoc Firebase Auth isn't an OIDC provider -- it issues Google-Identity-Toolkit-style tokens via REST endpoints. `com.codename1.social.FirebaseAuth` wraps those endpoints: +Authentication-And-Identity.asciidoc For federated sign-in (Google / Apple / Microsoft as Firebase providers), first obtain an ID token via the matching `*Connect` class, then swap it for a Firebase session: +Authentication-And-Identity.asciidoc Or, if the provider exposes a discovery document: +Authentication-And-Identity.asciidoc Pseudo-code (the actual HTTP calls depend on your server library): +Authentication-And-Identity.asciidoc Refresh the Firebase session at app launch: +Authentication-And-Identity.asciidoc `OidcClient` saves the response under a per-issuer + per-client-ID key using `com.codename1.io.oidc.TokenStore.DefaultStorageTokenStore` (which serializes to `com.codename1.io.Storage`). To restore on next launch: +Authentication-And-Identity.asciidoc `com.codename1.social.FacebookConnect` exposes both the old SDK-based `doLogin()` and a new SDK-free `signIn(...)` that uses the system browser via `OidcClient`. Use the new method for the simulator, the web port, and for apps that don't want to bundle the Facebook SDK at all: +Authentication-And-Identity.asciidoc `com.codename1.social.GoogleConnect` now offers a modern `signIn(...)` method that runs entirely through `OidcClient`: +Authentication-And-Identity.asciidoc becomes: +Commerce.asciidoc After a purchase, or on app start, validate the device's receipts with the cloud and refresh the entitlement cache. `refresh()` makes a blocking network call, so run it off the EDT: +Commerce.asciidoc Drive purchases through the manager (these delegate to the `Purchase` API): +Commerce.asciidoc In your `Lifecycle.init` (or wherever you set up purchases): +Commerce.asciidoc The core idea is the *entitlement*: an abstract access right such as `pro` or `remove_ads`. You map one or more store products to an entitlement, and your code only ever checks the entitlement: +Crash-Protection.asciidoc In your `Lifecycle.init`: +Deep-Links-Routing.asciidoc Or annotate a static factory method: +Deep-Links-Routing.asciidoc `AssetLinksBuilder` produces the payload: +Deep-Links-Routing.asciidoc attempts so they can confirm before discarding unsaved work: +Deep-Links-Routing.asciidoc without redirects. The plugin's `AasaBuilder` produces the payload: +Desktop-Integration.asciidoc same scheduling and handling code is shared across phone and desktop: +Device-Input-And-Form-Factors.asciidoc (or `Display`), mirroring the existing `CN.isShiftKeyDown()` family: +Device-Input-And-Form-Factors.asciidoc Any pointer listener receives an `ActionEvent`; call `getPointerEvent()` on it: +Device-Input-And-Form-Factors.asciidoc React to fold changes with a posture listener: +Device-Input-And-Form-Factors.asciidoc handles desktop and touch: +Device-Input-And-Form-Factors.asciidoc https://www.codenameone.com/javadoc/com/codename1/ui/DevicePosture.html[`DevicePosture`]: +Device-Input-And-Form-Factors.asciidoc pointer is a stylus or eraser: +Events.asciidoc The pointer events (touch events) can be intercepted by overriding one or more of these methods in `Component` or `Form`. Notice that unless you want to block functionality you should probably invoke `super` when overriding: +Events.asciidoc Then when you need to broadcast the event use: +Events.asciidoc https://www.codenameone.com/javadoc/com/codename1/ui/events/StyleListener.html[StyleListener] allows components to track changes to the style objects. For example, if the developer does something like: +Game-Assets.asciidoc is registered as solid. Applications add their own without changing the level format: +Game-Builder.asciidoc Loading and playing a level at runtime is three lines: +Game-Builder.asciidoc `start()` it: +Game-Builder.asciidoc the editor: +Game-Development.asciidoc as 2:1 diamonds -- columns step right-and-down, rows step left-and-down: +Game-Development.asciidoc build the frames yourself, which is what `ScrollerGameSample`'s runner does: +Game-Development.asciidoc come from one piece of geometry: +Game-Development.asciidoc each card's bounding box: +Game-Development.asciidoc engine can report completion, so guard with `isVoiceCompletionSupported()`: +Game-Development.asciidoc handle: +Game-Development.asciidoc layers the sprites within a cell: +Game-Development.asciidoc never recompute coordinates: +Game-Development.asciidoc objects, and step it once per frame from your `update`: +Game-Development.asciidoc rendered positions between physics states: +Game-Development.asciidoc required: +Game-Development.asciidoc rotation automatically (in pixels, screen space) -- and the scene draws it there: +Game-Development.asciidoc runs once before the first frame: +Game-Development.asciidoc that always faces the camera, so your existing 2D art keeps working in 3D: +Game-Development.asciidoc the thin point reads exactly the same to the eye: +Game-Development.asciidoc uploading it with `com.codename1.gpu.GraphicsDevice#createTexture(com.codename1.ui.Image)`: +In-Car-Experiences.asciidoc Head units enforce a hard cap on the number of rows/items they display (driver-distraction rules). Query it and trim accordingly: +In-Car-Experiences.asciidoc Register a single `CarApplication` from your app's `init()` -- before a head unit connects -- and return a root `CarScreen` that builds a template: +In-Car-Experiences.asciidoc `CarContext` manages a back stack, mirroring `androidx.car.app`'s `ScreenManager` and CarPlay's `CPInterfaceController`: +In-Car-Experiences.asciidoc `CarScreen` exposes optional lifecycle hooks -- `onCreate()`, `onResume()`, `onPause()`, `onDestroy()` -- and `CarApplication` is notified of connection changes via `onCarConnected(CarContext)` / `onCarDisconnected()`. You can also observe connection globally: +Introduction.asciidoc In a cold start `init(Object)` is invoked followed by the `start()` method. For example, `start()` can be invoked more than once if an app is minimized and restored, see the sidebar <>: +Introduction.asciidoc Next consider the first lifecycle method `init(Object)`. The <> discusses the lifecycle in depth: +Introduction.asciidoc Now that you have a general sense of the lifecycle lets look at the last two lifecycle methods: +Introduction.asciidoc The hello world Java source file looks like this (removed some comments and whitespace): +Maps.asciidoc A native provider only renders on the platforms that ship its SDK. To show a provider's map *everywhere* -- including platforms with no native SDK for it -- register a `WebMapProvider`, which hosts the provider's JavaScript SDK inside a `BrowserComponent`: +Maps.asciidoc Every map -- vector or native -- exposes the same operations through `MapSurface`: +Maps.asciidoc For a real app you point `MapView` at a hosted tile service. The simplest keyless option is OpenFreeMap (OpenStreetMap-based vector tiles); for branded styles or higher quotas use a keyed provider such as MapTiler or your own self-hosted Protomaps/TileServer GL endpoint: +Maps.asciidoc When a provider is selected the build server injects that provider's implementation into your app and wires it in; with no provider selected (or when the provider is unavailable at runtime, for example when Google Play Services is missing) `NativeMap` simply renders the vector `MapView` fallback. You can configure the fallback basemap explicitly: +Maven-Creating-CN1Libs.adoc Now try it out. Try adding the following code to your application project's main class (or anywhere in the application project, for that matter): +Maven-Creating-CN1Libs.adoc The simulator dispatches every action on the Codename One EDT through `Display.callSerially`, so your method can call `Display.getInstance()`, `Form.show()`, `Dialog.show()`, `ToastBar.showInfoMessage()` and any other CN1 API. Reflection uses the same classloader that loaded `Display`, so cn1lib internals (including package-private classes) resolve normally: +Media-And-Audio.asciidoc `AudioEffects` provides small platform-neutral PCM transforms that compose with the mixer: +Miscellaneous-Features.asciidoc A typical use of this API would be something like this: +Miscellaneous-Features.asciidoc Easy thread can be created like this: +Miscellaneous-Features.asciidoc For Android 11+ (API 30+), Codename One detects if background location is needed and presents a dialog explaining the need before redirecting the user to the app settings. You can customize the permission prompt message using the localization key `android.permission.ACCESS_BACKGROUND_LOCATION`: +Miscellaneous-Features.asciidoc For example: you can copy the `Image` to `Storage` using: +Miscellaneous-Features.asciidoc However, it gets better, say you want to return a value: +Miscellaneous-Features.asciidoc If you need to apply the scale manually for custom fonts or layout calculations, read the values directly: +Miscellaneous-Features.asciidoc It allows formatting numbers/dates & time based on platform locale. It also provides a great deal of the information you need such as the language/locale information you need to pick the proper resource bundle: +Miscellaneous-Features.asciidoc The `Capture` API also includes a callback based API that uses the `ActionListener` interface to implement capture. For example: you can adapt the previous sample to use this API as such: +Miscellaneous-Features.asciidoc The following code demonstrates usage of the GeoFence API: +Miscellaneous-Features.asciidoc The list of available languages in the resource bundle could be retrieved like this. Notice that this a list that was set by you and doesn't need to confirm to the ISO language code standards: +Miscellaneous-Features.asciidoc These asynchronous calls make things a bit painful to wade through, so the API wraps them in a simplified synchronous version: +Miscellaneous-Features.asciidoc To solve this sort of used case you have two APIs in `Display`: +Miscellaneous-Features.asciidoc You can add more than one attachment by putting them directly into the attachment map for example: +Miscellaneous-Features.asciidoc You can install the bundle using code like this: +Miscellaneous-Features.asciidoc You can send a task to the thread using: +Monetization.asciidoc And you also provide a button to allow the user to manually synchronize the receipts: +Monetization.asciidoc And your `itemPurchased()` callback will need to add a world: +Monetization.asciidoc At the end of the `start()` method: +Monetization.asciidoc At this point, the app can track the sale of the world. To make it more useful, add `ToastBar` feedback for purchase completion: +Monetization.asciidoc In the hello world app you'll use this information in a few different places. On your main form you'll include a label to show the current expiry date, and you allow the user to press a button to synchronize receipts manually if they think the value is out of date: +Monetization.asciidoc In the main form, you want two buttons to subscribe to the `World`, for one month and one year respectively. They look like: +Monetization.asciidoc Now in the `start()` method, add a button that lets the user buy the world: +Monetization.asciidoc Now you'll change your buy code as follows: +Monetization.asciidoc On the server-side, your REST controller is a standard JAX-RS REST interface. The Netbeans web service wizard generated it and then it was modified to suit the purposes here. The methods of the `ReceiptsFacadeREST` class for the REST API are shown here: +Monetization.asciidoc Once implemented, your `fetchReceipts()` method will look like: +Monetization.asciidoc The `createRESTClient()` method shown there creates a `RESTfulWebServiceClient` and configuring it to use basic authentication with a username and password. The idea is that your user would have logged into your app at some point, and you would have a username and password on hand to pass back to the web service with the receipt data so that you can connect the subscription to a user account. The source of that method is listed here: +Monetization.asciidoc The `submitReceipt()` method is a little more complex, as it needs to calculate the new expiry date for your subscription: +Monetization.asciidoc The buy callbacks are like the ones implemented in the regular in-app purchase examples: +Monetization.asciidoc The general usage is as follows: +Monetization.asciidoc The source for your ReceiptStore is as follows: +Monetization.asciidoc To build the signed discount payload required by Apple you can use the `ApplePromotionalOffer` helper: +Monetization.asciidoc You are now ready to see the full magic of the `validateAndSaveReceipt()` method in all its glory: +Monetization.asciidoc You'll register it in your app's init() method so that it's always available: +Monetization.asciidoc You'll set these in your constants: +Motion-Sensors.asciidoc Callbacks arrive on the EDT, so the listener can update the UI directly. Sampling is reference counted: the hardware sensor draws power only while at least one listener is registered. Remove the listener once the screen is no longer visible, typically from the form's `removeNotify`, so the sensor powers down: +Motion-Sensors.asciidoc Register a `GestureListener` for one of the `GestureEvent.TYPE_*` gestures. The accelerometer powers on for the duration that a gesture listener stays registered: +Motion-Sensors.asciidoc The detection thresholds suit most apps as shipped, and you can tune them when a gesture needs to be more or less sensitive: +Motion-Sensors.asciidoc `MotionSensorManager.getInstance()` always returns a manager. On a device without motion hardware every sensor reports as unsupported, so application code can call the API without a null check on the manager itself. `getSensor(int)` returns `null` when the requested sensor isn't available on the current device: +Native-Themes.asciidoc `UIManager.addThemeProps` after the theme has been installed: +Near-Field-Communication.asciidoc Beyond NDEF, the discovered `Tag` exposes accessors for the underlying technologies: +Near-Field-Communication.asciidoc For FeliCa on iOS, set the system codes in `NfcReadOptions`: +Near-Field-Communication.asciidoc Host Card Emulation (HCE) lets the device pretend to be a contactless smart card. A nearby reader (Android phone, payment terminal, access control gate) sends ISO 7816 APDUs and your app responds. Subclass `HostCardEmulationService` and register the instance: +Network-Connectivity.asciidoc To advertise an HTTP server you wrote on port 8080: +Network-Connectivity.asciidoc To associate the device with a specific SSID: +Notifications-And-Background-Execution.asciidoc before; the bean has been extended with fluent, backward-compatible setters: +Notifications-And-Background-Execution.asciidoc then reference it from a notification with `setChannelId(...)`: +Printing.asciidoc `Printer.printImage(image, listener)` prints a `com.codename1.ui.Image` directly. The image is encoded to a temporary PNG file behind the scenes and the file is deleted once the print flow finishes: +SVG-Transcoder.asciidoc the generated class directly: +The-Components-Of-Codename-One.asciidoc A common source of confusion in the `MultiButton` is the difference between the icon and the emblem, since both may have an icon image associated with them. The icon is an image representing the entry while the emblem is an optional visual representation of the action that will be undertaken when the element is pressed. Both may be used simultaneously or individually of one another: +The-Components-Of-Codename-One.asciidoc A form is a container with a title, a content area, and an optional menu or menu-bar area. When you call methods such as `add` or `remove` on a form, you're invoking something that maps to this: +The-Components-Of-Codename-One.asciidoc A more practical "real world" example would be working with XML data. You can use something like this to show an XML `Tree`: +The-Components-Of-Codename-One.asciidoc A picker can work with your existing sample using code like this: +The-Components-Of-Codename-One.asciidoc A popup dialog is a common mobile paradigm showing a `Dialog` that points at a specific component. It's a standard `Dialog` that's shown in a unique way: +The-Components-Of-Codename-One.asciidoc And call its methods: +The-Components-Of-Codename-One.asciidoc Call the builder from a Maven plugin, an Ant task or a one-shot `main`: +The-Components-Of-Codename-One.asciidoc For example, if you wish to query a database or a web service you will need to derive the class and perform more advanced filtering by overriding the `filter` method: +The-Components-Of-Codename-One.asciidoc For example, suppose you want to pass a string with text to set in a textarea within the webpage. You can do something like: +The-Components-Of-Codename-One.asciidoc For example, this behavior might not be desired so to block that you can do: +The-Components-Of-Codename-One.asciidoc For example, to enclose the `CheckBox` components in a vertical `ComponentGroup` and the `RadioButton's` in a horizontal group, change the last line of the code above as such: +The-Components-Of-Codename-One.asciidoc For example, you can change the focus `Component` to have an icon: +The-Components-Of-Codename-One.asciidoc For example: +The-Components-Of-Codename-One.asciidoc For example: You might want to create a proxy for the https://developer.mozilla.org/en-You/docs/Web/API/Window/location[window.location] object so that you can access its properties more from Java: +The-Components-Of-Codename-One.asciidoc For example: the demo below uses the GRRM demo data from above to build a `ComboBox`: +The-Components-Of-Codename-One.asciidoc Here is a simple example of a `MultiList` containing a highly popular subject matter: +The-Components-Of-Codename-One.asciidoc Here is a simple example that also shows the difference between the `scale to fill` and `scale to fit` modes: +The-Components-Of-Codename-One.asciidoc If you add to the sample above a `Validator`: +The-Components-Of-Codename-One.asciidoc If you call `Display` directly instead of using `ShareButton`, pass the listener as the final argument to the new overload: +The-Components-Of-Codename-One.asciidoc In the sample below you fetch all the contacts from the device and enable search through them, notice it expects and image called `duke.png` which is the default Codename One icon renamed and placed in the src folder: +The-Components-Of-Codename-One.asciidoc It's also recommended to place the list in the `CENTER` location of a https://www.codenameone.com/javadoc/com/codename1/ui/layouts/BorderLayout.html[BorderLayout] to produce the most effective results. For example: +The-Components-Of-Codename-One.asciidoc Let start by exploring how you can achieve this UI that fetches data from a webservice: +The-Components-Of-Codename-One.asciidoc Masking allows you to accept partial input in one field and implicitly move to the next, this can be used to all types of complex input thanks to the text component API. E.g with the code above you can mask the credit card input so the cursor jumps to the next field implicitly using this code: +The-Components-Of-Codename-One.asciidoc NOTE: In all the sample code below, you can assume that variables named `bc` represent an instance of https://www.codenameone.com/javadoc/com/codename1/ui/BrowserComponent.html[BrowserComponent]: +The-Components-Of-Codename-One.asciidoc Normally, to build the model for a renderer of this type, you use something like: +The-Components-Of-Codename-One.asciidoc Notice in the sample below that you associate all the radio buttons with a group but don't do anything with the group as the radio buttons keep the reference internally. You also show the opposite side functionality and icon behavior: +The-Components-Of-Codename-One.asciidoc Notice that this feature works with the on-top and permanent versions of the side menu and not with the legacy versions: +The-Components-Of-Codename-One.asciidoc Notice that when you work with numeric values or anything related to the types mentioned above your code must be aware of the typing. For example: in this case the type is `Double` and not `String`: +The-Components-Of-Codename-One.asciidoc Now look at a more advanced Renderer: +The-Components-Of-Codename-One.asciidoc Now make it a bit more useful: +The-Components-Of-Codename-One.asciidoc Now that you have a webservice lets proceed to create the UI. Check out the code annotations below: +The-Components-Of-Codename-One.asciidoc One of the features of label that moved into `SpanLabel` to some extent is the ability to position the icon. For example, unlike a `Label` the icon position is determined by the layout manager of the composite so `setIconPosition` accepts a `BorderLayout` constraint: +The-Components-Of-Codename-One.asciidoc Or synchronously: +The-Components-Of-Codename-One.asciidoc Simple usage of the `Calendar` class looks something like this: +The-Components-Of-Codename-One.asciidoc Simple usage of the `ToastBar` class looks something like this: +The-Components-Of-Codename-One.asciidoc The Renderer is a simple interface with 2 methods: +The-Components-Of-Codename-One.asciidoc The callbacks you pass to `execute()` and `executeAndWait()` are single-use callbacks. You can’t, for example, store the `callback` variable on the JavaScript side for later use (for example: to respond to a button click event). If you need a "multi-use" callback, you should use the `addJSCallback()` method instead. Its usage looks identical to `execute()`, the difference is that the callback will live on after its first use. For example: Consider the following code: +The-Components-Of-Codename-One.asciidoc The code below provides a brief overview of these options: +The-Components-Of-Codename-One.asciidoc The data of the `Tree` arrives from a model for example: this: +The-Components-Of-Codename-One.asciidoc The first step is creating the webservice call, you won't go into too much detail here as webservices & IO are discussed later in the guide: +The-Components-Of-Codename-One.asciidoc The https://www.codenameone.com/javadoc/com/codename1/ui/list/ListModel.html[ListModel] interface can be implemented by anyone in this case you did a stupid simple implementation: +The-Components-Of-Codename-One.asciidoc The model for the XML hierarchy is implemented as such: +The-Components-Of-Codename-One.asciidoc The most simple/naive implementation may choose to implement the renderer as follows: +The-Components-Of-Codename-One.asciidoc The old API provided a synchronous wrapper around an inherently asynchronous process, and made extensive use of `invokeAndBlock()` underneath the covers. This resulted in a nice API with high-level abstractions that played with a synchronous programming model, but it came with a price-tag in performance, complexity, and predictability. Let’s take a simple example, getting a reference to the "window" object: +The-Components-Of-Codename-One.asciidoc The screenshot above was produced using the following code: +The-Components-Of-Codename-One.asciidoc The split pane component is a bit desktop specific but works reasonably well on devices. To get the image below you changed `SalesDemo.java` in the kitchen sink by changing this: +The-Components-Of-Codename-One.asciidoc Then implement the method `automoveToNext` as: +The-Components-Of-Codename-One.asciidoc Then you can retrieve its properties using the `get()` method: +The-Components-Of-Codename-One.asciidoc This code should output "The result was 7" to the console. It's fully asynchronous, so you can include this code anywhere without worrying about it "bogging down" your code. The full signature of this form of the https://www.codenameone.com/javadoc/com/codename1/ui/BrowserComponent.html#execute-java.lang.String-com.codename1.util.SuccessCallback-[execute()] method is: +The-Components-Of-Codename-One.asciidoc This sample below continues from the place where the <> stopped by adding validation to that code: +The-Components-Of-Codename-One.asciidoc This swipe gesture is commonly used in touch interfaces to expose features such as delete, edit etc. It's trivial to use this component by determining the components placed on top and bottom (the revealed component): +The-Components-Of-Codename-One.asciidoc To make the code tighter, keep a reference to the `Component` or extend it as https://www.codenameone.com/javadoc/com/codename1/ui/list/DefaultListCellRenderer.html[DefaultListCellRenderer] does: +The-Components-Of-Codename-One.asciidoc Unlike the `InfiniteScrollAdapter` you can't use the `ContentPane` directly so you've to use a `BorderLayout` and place the `InfiniteContainer` there: +The-Components-Of-Codename-One.asciidoc Unlike the `MultiButton` it uses the `TextArea` internally to break lines seamlessly. The `SpanButton` is far simpler than the `MultiButton` and as a result isn't as configurable: +The-Components-Of-Codename-One.asciidoc What if you want componentName to be red? Just use: +The-Components-Of-Codename-One.asciidoc When using lightweight picker mode (`setUseLightweightPopup(true)`), you can add custom quick-action buttons to the popup. This is useful for actions like setting the date to "Today" or "+7 Days" without scrolling the wheels manually: +The-Components-Of-Codename-One.asciidoc With this: +The-Components-Of-Codename-One.asciidoc You can access JavaScript variables from the context by using code like this: +The-Components-Of-Codename-One.asciidoc You can also delay the showing of the status message using `showDelayed` as such: +The-Components-Of-Codename-One.asciidoc You can also query the context for objects and change their value for example: +The-Components-Of-Codename-One.asciidoc You can also set its properties: +The-Components-Of-Codename-One.asciidoc You can automatically clear a status message/progress after a timeout using the `setExpires` method as such: +The-Components-Of-Codename-One.asciidoc You can combine some demos above including the <> to rank GRRM's books in an interactive way: +The-Components-Of-Codename-One.asciidoc You can convert the sample above to use toggle buttons as such: +The-Components-Of-Codename-One.asciidoc You can dynamically download images directly into the `ImageViewer` with a custom list model like this: +The-Components-Of-Codename-One.asciidoc You can now replace the existing model by removing all the model related logic and changing the constructor call as such: +The-Components-Of-Codename-One.asciidoc You can show a progress indicator in the ToastBar like this: +The-Components-Of-Codename-One.asciidoc You can use the `ImageViewer` as a tool to view a single image which allows you to zoom in/out to that image as such: +The-Components-Of-Codename-One.asciidoc You can wrap a `TextField` with a clearable wrapper to get this effect on all platforms. For example: replace this: +The-Components-Of-Codename-One.asciidoc You need to change this code to use the `addJSCallback()` method as follows: +The-Components-Of-Codename-One.asciidoc You will need to define the following theme constants for the arrow to work: +The-Components-Of-Codename-One.asciidoc `ImageViewer` also supports optional side arrows (material font icons) and an optional thumbnail strip for direct image navigation: +The-Components-Of-Codename-One.asciidoc `InfiniteProgress` can be used in one of two ways either by embedding the component into the UI through something like this: +The-Components-Of-Codename-One.asciidoc `Label` text can be positioned in one of 4 locations as such: +The-Components-Of-Codename-One.asciidoc `Slider` is highly customizable for example: a slider can be used to replicate a 5-star rating widget as such. Notice that this slider will work when its given its preferred size otherwise more stars will appear. That's why you place it within a `FlowLayout`: +The-Components-Of-Codename-One.asciidoc `setRenderingPrototype` accepts a "fake" value that represents a reasonably large amount of data and it will be used to calculate the preferred size. For example: for a multiList that should render 2 lines of text with 20 characters and a 5mm square icon you can do something like this: +The-Components-Of-Codename-One.asciidoc app for specific examples, but here is a high-level view of some code that creates a Pie Chart: +The-Components-Of-Codename-One.asciidoc doing this, you need to define this entry for all entries, for example: +The-Components-Of-Codename-One.asciidoc or a go icon using a hint such as this: +The-EDT---Event-Dispatch-Thread.asciidoc A simplistic approach is to do something like this: +The-EDT---Event-Dispatch-Thread.asciidoc For example, instead of using operation names lets use a more "real world" example: +The-EDT---Event-Dispatch-Thread.asciidoc However, `updateUIWithContentOfFile` should be executed on the EDT and not on a random thread. The right way to do this would therefore be something like this: +The-EDT---Event-Dispatch-Thread.asciidoc IMPORTANT: The Runnable passed to the `callSerially` and `callSeriallyAndWait` methods isn't a `Thread`. Use the `Runnable` interface as a convenient callback interface: +The-EDT---Event-Dispatch-Thread.asciidoc Invoke and block solves this in a unique way you can get almost the exact same behavior by using this: +The-EDT---Event-Dispatch-Thread.asciidoc Or this with Java 8 syntax: +The-EDT---Event-Dispatch-Thread.asciidoc TIP: You can write this code more concisely using Java 8 lambda code as such: +The-EDT---Event-Dispatch-Thread.asciidoc The `callSeriallyAndWait(Runnable)` method blocks the current thread until the method completes, this is useful for cases such as user notification e.g.: +The-EDT---Event-Dispatch-Thread.asciidoc This is best explained by an example. Typical Java code reads as a single sequence as such: +The-EDT---Event-Dispatch-Thread.asciidoc To explain how invokeAndBlock works you can return to the sample above of how the EDT works: +The-EDT---Event-Dispatch-Thread.asciidoc You can visualize the EDT as a loop such as this: +The-EDT---Event-Dispatch-Thread.asciidoc `invokeAndBlock()` works in a similar way to this pseudo-code: +Video-Capture-Constraints.asciidoc Find out if this constraint will be obeyed: +Video-Capture-Constraints.asciidoc For example: +Video-Capture-Constraints.asciidoc Suppose you want to allow the user to capture a short (5 second) clip, in a low resolution, appropriate for sharing on a social media platform. You create your `VideoCaptureConstraints` object as follows: +Video-Capture-Constraints.asciidoc This constraint can then be passed to `Capture.captureVideo()` to get the captured file: +Working-With-iOS.asciidoc Repeating notifications will continue until they're canceled by the app. You can cancel a single notification by calling: +appendix_goal_generate_graphql.adoc The `@GraphQLClient` interface looks like: +appendix_goal_generate_graphql.adoc an `OnComplete>`: +appendix_goal_generate_graphql.adoc ends the stream: +appendix_goal_generate_grpc.adoc Call sites use the static factory: +appendix_goal_generate_grpc.adoc The `@GrpcClient` interface looks like: +appendix_goal_generate_openapi.adoc Call sites use the static factory: +basics.asciidoc For example: see this code where: +basics.asciidoc From that point on you can write code that looks like this: +basics.asciidoc In the race to make code "`tighter`" you can make this even shorter. Most layout managers have their own custom terse syntax style for example: +basics.asciidoc Instead of: +basics.asciidoc Instead of: +basics.asciidoc Some things were changed so you won't have too many conflicts for example, `Log.p` or `Log.e` would have been problematic so you now have: +basics.asciidoc The UIID's translate the theme elements into a set of `Style` objects. These `Style` objects get their initial values from the theme but can be further manipulated after the fact. To make the text field's foreground color red you could use this code: +basics.asciidoc The same applies for most network manager calls e.g.: +basics.asciidoc This works great for regular layouts but might not for constraint based layouts. A constraint based layout accepts another argument. For example: `BorderLayout` needs a location for the `Component`: +basics.asciidoc and `setSameHeight` methods, for example: +graphics.asciidoc (that's: where the numbers appear), and the remaining marks (corresponding with seconds) will be short: +graphics.asciidoc 3. Invert the translation performed in step 1: +graphics.asciidoc A `URLImage` can be created with a mask adapter to apply an effect to an image. This allows you to round downloaded images or apply any sort of masking for example: you can adapt the round mask code above as such: +graphics.asciidoc And you will translate it down slightly so that it overlaps the center. This translation will be performed on the `GeneralPath` object directly rather than through the `Graphics` context: +graphics.asciidoc Center: +graphics.asciidoc For example: a `pointerPressed()` callback method can look like this: +graphics.asciidoc The `animate()` method in the `AnalogClock` class: +graphics.asciidoc The code to instantiate the clock, and start the animation would be something like: +graphics.asciidoc The remaining drawing code is as follows: +graphics.asciidoc The simple use case is pretty trivial: +graphics.asciidoc To do this you can override: +graphics.asciidoc Top Left Corner: +graphics.asciidoc `ConicGradient` - following the same pattern as the `Shape` hierarchy: +graphics.asciidoc can override or augment whatever the default set: +graphics.asciidoc class is the most common option and accepts a list of color stops along a line: +graphics.asciidoc coordinates of the component. You therefore need to get the absolute clock center position to perform the rotation: +graphics.asciidoc for the images. The default is a scale adapter although you might change that to scale fill in the future: +graphics.asciidoc hook. Two ways to install one: +graphics.asciidoc https://www.codenameone.com/javadoc/com/codename1/ui/Graphics.html#isShapeSupported()[`Graphics.isShapeSupported()`] method. For example: +graphics.asciidoc it can be added to a form: +graphics.asciidoc mark at the 12 o'clock position: +graphics.asciidoc method to append curves to the drawing as follows: +graphics.asciidoc methods in the component as follows: +graphics.asciidoc name of icon to `icon_URLImage` then using this in the data: +graphics.asciidoc show this, try to place five of these components on a form inside a https://www.codenameone.com/javadoc/com/codename1/ui/layouts/BorderLayout.html[BorderLayout] and see how it looks: +graphics.asciidoc straight lines rather than curves might look like this: +graphics.asciidoc to draw each individual tick: +io.asciidoc A more advanced usage of the `FileSystemStorage` API can be a `FileSystemStorage` `Tree`: +io.asciidoc A simpler implementation could do something like this: +io.asciidoc Above, if you want to select the IDs of all players that are ranked in the top 2, you can use an expression like: +io.asciidoc Above, you globally find a lastname element with a value of ‘Hewitt’, then grab the parent node of lastname which happens to be the player node, then grab the ID attribute from the player node. Or, you could get the same result from the following simpler statement: +io.asciidoc Above, you selected the IDs of all ranked players. Conversely, you can select the non-ranked players like this: +io.asciidoc After you do that once you can write/read contacts from storage if you so want: +io.asciidoc An `Externalizable` object *must* have a *default public constructor* and must implement the following 4 methods: +io.asciidoc And delete an entry using: +io.asciidoc And vice versa: +io.asciidoc Another approach is to use the `setFailSilently(true)` method on the `ConnectionRequest`. This will prevent the `ConnectionRequest` from displaying any errors to the user. It's a powerful strategy if you use the synchronous version of the APIs for example: +io.asciidoc As part of the premium cloud features it's possible to invoke Log.sendLog() to email a log directly to the developer account. Codename One can do that seamlessly based on changes printed into the log or based on exceptions that are uncaught or logged for example: +io.asciidoc Assuming you added a new date field to the object you can do the following. Notice that a `Date` is a `long` value in Java that can be null. For completeness the full class is presented below: +io.asciidoc Binding makes this all seamless. For example: the code above can be written as: +io.asciidoc By default `GZConnectionRequest` doesn't request gzipped data ( unzips it when its received) but its pretty easy to do so add the HTTP header `Accept-Encoding: gzip` for example: +io.asciidoc Codename One provides many tools to simplify the path between networking/IO & GUI. A common task of showing a wait dialog or progress sign while fetching network data can be simplified by using the https://www.codenameone.com/javadoc/com/codename1/components/InfiniteProgress.html[InfiniteProgress] class for example: +io.asciidoc Developers need to write the data of the object in the externalize method using the methods in the data output stream and read the data of the object in the internalize method for example: +io.asciidoc For a lot of REST requests this will fail because you need to add an HTTP header indicating that you accept JSON results. You have a special case support for that: +io.asciidoc For endpoints that return a list of DTOs, use `fetchAsMappedList`: +io.asciidoc For example, if you wish to have finer grained control over the submission process for example: for making a `HEAD` request you can do this with code like: +io.asciidoc For example: to block all network errors from showing anything to the user you could do something like this: +io.asciidoc For example: you can do something like this in your `init(Object)` method: +io.asciidoc For starters all the common methods of `Object` can be implemented with almost no code: +io.asciidoc If a document is ordered, you might want to select nodes by their position, for example: +io.asciidoc If you continue the example from above to show persistence to the SQL database you can do something like this: +io.asciidoc If you continue your example from above you can do something like this: +io.asciidoc Implementing the `Externalizable` interface is important when you want to store a proprietary object. In this case you must register the object with the `com.codename1.io.Util` class so the externalization algorithm will be able to recognize it by name by invoking: +io.asciidoc In the above code you do the following: +io.asciidoc It's also possible to nest expressions, for example: +io.asciidoc It's also possible to select parent nodes, by using the `..` expression. For example: +io.asciidoc Listing the entries is more interesting: +io.asciidoc Moving on, to select a node based on the existence of an attribute: +io.asciidoc Notice that you can also implement the same thing and much more by avoiding the response listener code and instead overriding the methods of the `ConnectionRequest` class which offers many points to override for example: +io.asciidoc One of the bigger features of properties are their ability to bind UI to a property. For example: if you continue the sample above with the `Contact` class, say you have a text field on the form and you want the property (which you mapped to the database) to have the value of the text field. You could do something like this: +io.asciidoc POST requests use the same builder pattern: +io.asciidoc Server returned headers are a bit trickier to read. You need to subclass the connection request and override the `readHeaders` method for example: +io.asciidoc Since strings might be null sometimes you also included convenience methods to implement such externalization. This effectively writes a boolean before writing the UTF to show whether the string is null: +io.asciidoc Since you assume most developers reading this will be familiar with Java here is the way to implement the multipart upload in the servlet API: +io.asciidoc Some headers are built-in as direct APIs for example: content type is directly exposed within the API since it's a pretty common use case. You can set the content kind of post request using: +io.asciidoc Some objects make sense as global objects, you can use the `Preferences` API to store that data directly but then you don't have the type safety that property objects bring to the table. That's where the binding of property objects to preferences makes sense. For example: say you have a global `Settings` property object you can bind it to preferences using: +io.asciidoc That's what the new method of `URLImage` does: +io.asciidoc The JSON ("JavaScript Object Notation") format is popular on the web for passing values to/from webservices since it works so well with JavaScript. Parsing JSON is as easy but has two different variations. You can use the https://www.codenameone.com/javadoc/com/codename1/io/JSONParser.html[JSONParser] class to build a tree of the JSON data as such: +io.asciidoc The XML processor handles global selections by using a double slash anywhere within the expression, for example: +io.asciidoc The `CachedDataService` will fetch data if it isn't cached locally and cache it. When you "refresh" it will send a special HTTP request that will send back the data if it has been updated since the last refresh: +io.asciidoc The `Rest` API makes it easy to invoke a RESTful webservice without many of the nuances of `ConnectionRequest`. You can use it to define the HTTP method and start building based on that. To get a parsed JSON result from a URL you could do: +io.asciidoc The cool thing is that this works with many component types and property types almost magically. Binding works by using an adapter class to convert the data to/from the component. The adapter itself works with a generic converter for example: this code: +io.asciidoc The sample code below demonstrates listing storage content, adding and viewing entries, and deleting entries: +io.asciidoc The simplest usage of `XMLParser` looks a bit like this: +io.asciidoc There are many methods of interest to keep an eye for: +io.asciidoc This can be tedious to do if you want all requests from your app to use this header. For this use case you can use: +io.asciidoc This means that this code won't compile: +io.asciidoc This should display an error message to the user if there was a problem sending the SMS: +io.asciidoc This simple example allows you to create a server and a client assuming the device supports both: +io.asciidoc This still carries most of the flexibilities of the regular binding for example: you can still get a binding object using: +io.asciidoc To parse a CSV use the https://www.codenameone.com/javadoc/com/codename1/io/CSVParser.html[CSVParser] class as such: +io.asciidoc Up until now this was pretty cool but if you looked at the UI construction code above you would see that it's pretty full of boilerplate code. The thing about boilerplate is that it shows where automation can be applied, that's the exact idea behind the magical "InstantUI" class. This means that the UI above can be generated using this code: +io.asciidoc When you used a POJO you did this: +io.asciidoc With properties you do this: +io.asciidoc Without this feature the code would look like this: +io.asciidoc Working with a database is pretty trivial, the application logic below can send arbitrary queries to the database and present the results in a `Table`. You can probably integrate this code into your app as a debugging tool: +io.asciidoc You added a new syntax: +io.asciidoc You can also add any arbitrary header type you want, for example: a common use case is basic authorization where the authorization header includes the Base64 encoded user/password combination as such: +io.asciidoc You can also override the error callbacks of the various types in the request for example: for a server error code you can do: +io.asciidoc You can always submit data in the `buildRequestBody` but this is flaky and has some limitations in devices/size allowed. HTTP standardized file upload capabilities through the multipart request protocol, this is implemented by countless servers and is well documented. Codename One supports this out of the box: +io.asciidoc You can build a UI that would allow you to edit the `Contact` property in memory: +io.asciidoc You can do some more elaborate bindings such as: +io.asciidoc You can now send hello world as an SMS to the end user. Once this is in place sending an SMS through REST is a matter of using the `Rest` API: +io.asciidoc You can pick either one of these approaches based on your personal preferences. Here you show both uses with the server API: +io.asciidoc You can send a get request to a URL using something like: +io.asciidoc You can then add entries to the contact table using: +io.asciidoc You can update an entry using: +io.asciidoc You might not have noticed this but in the previous verbose code you had lines like: +io.asciidoc You want to extract some data above into simpler string results. You can do this using: +io.asciidoc You've some special case defaults for some common property names, so if your property is named email it will use an email constraint by default. If it's named url or password etc. It will do the "right thing" unless you explicitly state otherwise. You can customize the constraint for a specific property using something like: +io.asciidoc `NetworkManager` also supports synchronous requests which work in a similar way to `Dialog` through the `invokeAndBlock` call and thus don't block the EDT footnote:[Event Dispatch Thread] illegally. For example: you can do something like this: +io.asciidoc `Storage` also offers a simple API in the form of the https://www.codenameone.com/javadoc/com/codename1/io/Preferences.html[Preferences] class. The `Preferences` class lets developers store simple variables, strings, numbers, booleans, and similar values without writing storage code. This is a common use case in applications. For example, you might need to store a server token: +io.asciidoc `com.codename1.io.JSONWriter` class is the complement of `JSONParser`: +io.asciidoc database by name: +io.asciidoc directly: +io.asciidoc download a `ConnectionRequest` to `Storage` using code like this: +io.asciidoc out any change made to the property: +io.asciidoc than a `Map` literal: +io.asciidoc that prevents setting the property to null and defaults it to an empty string: +io.asciidoc the array directly: +io.asciidoc values from parsed JSON: +io.asciidoc you will notice the `final` keyword: +performance.asciidoc All you need to do now is update the `lastScroll` variable whenever user interaction is in place. This works for user touches: +performance.asciidoc For example, Codename One annotates: +performance.asciidoc In the new Contacts demo you have a share button for each contact, the code for constructing a `ShareButton` looks like this: +performance.asciidoc Then you did this within the background loading thread: +performance.asciidoc These icons are in a shared resource file that you load and don't cache. The initial workaround was to cache this resource but a better solution was to convert this code: +performance.asciidoc This works for general scrolling: +performance.asciidoc `Simd` is accessed as a singleton: +performance.asciidoc method returns. This is what the `alloca*` family exposes: +performance.asciidoc the allocation helpers on `Simd`: +security.asciidoc Baking an API key (for example a Google Maps key) into your app is unsafe: anyone can extract it from the binary, and rotating it means shipping a new build. `com.codename1.security.Secrets` solves this. You define the secret once in the Codename One Cloud vault, and the app fetches it at runtime and caches it in `SecureStorage`: +security.asciidoc For HOTP, supply the counter explicitly and increment it after every successful authentication: +security.asciidoc For RSA-signed tokens (RS256/384/512) and ECDSA-signed tokens (ES256/384/512), pass the key to the dynamic overloads: +security.asciidoc Shared secrets are commonly distributed as Base32 strings (the format embedded in QR codes by authenticator apps). `com.codename1.security.Base32` handles the encoding: +security.asciidoc The runtime API is identical on both platforms -- request a token bound to a fresh server nonce, then POST it to your backend for verification: +security.asciidoc There are two simple methods in the `Util` class: +security.asciidoc This works through a new mechanism in storage where you can replace the storage instance with another instance using: +security.asciidoc To block copy & paste on a specific field do: +security.asciidoc To use a key that was generated outside the app, feed the DER bytes to the static factory methods: +security.asciidoc You can leverage that knowledge to change the encryption password on the encryption storage using pseudo-code like this: +security.asciidoc `com.codename1.components.OtpField` is a segmented input -- one box per character, that advances to the next box as the user types and steps back on backspace. This is the standard pattern for SMS confirmation and authenticator-app entry screens: +security.asciidoc `com.codename1.security.Cipher` also covers RSA encryption, and `com.codename1.security.Signature` covers digital signatures (RSA and ECDSA). Keys are represented by `com.codename1.security.PublicKey` and `com.codename1.security.PrivateKey`, which wrap X.509 SubjectPublicKeyInfo and PKCS#8 DER blobs respectively -- the same encodings used by OpenSSL: +security.asciidoc `com.codename1.security.Cipher` exposes AES through the platform's native AES implementation. AES-GCM is the recommended default because it's authenticated -- a single tag-mismatch failure detects any tampering of the ciphertext or the associated data: +security.asciidoc `com.codename1.security.Hash` implements MD5, SHA-1, SHA-224, SHA-256, SHA-384, and SHA-512. SHA-256 is the recommended default for new code; MD5 and SHA-1 are exposed only for compatibility with older protocols since both are broken for collision resistance: +security.asciidoc `com.codename1.security.Hmac` implements HMAC (RFC 2104) on top of any of the hash algorithms above. Use HMAC whenever a message authentication code is needed -- API request signing, session cookie tamper detection, JWT signing with the `HS` family, or TOTP token generation: +security.asciidoc `com.codename1.security.SecureStorage` keeps small string values in the operating system's secure keychain (iOS Keychain Services and the Android Keystore) so they're protected by the platform's secure enclave instead of being written to app storage. The quiet, no-prompt API is three calls: From eebe28f6834ddab0196df0f6c18cc389702dac87 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 12:56:21 +0300 Subject: [PATCH 02/51] Bank the four holes the constraints chapter no longer has The stacked content change restored the video capture constraints examples, so their baseline entries went stale and the ratchet refused to pass until they were removed. 406 to 402. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/missing-code-blocks-baseline.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/scripts/developer-guide/missing-code-blocks-baseline.txt b/scripts/developer-guide/missing-code-blocks-baseline.txt index d5a5f1f6104..b41e59bf5cc 100644 --- a/scripts/developer-guide/missing-code-blocks-baseline.txt +++ b/scripts/developer-guide/missing-code-blocks-baseline.txt @@ -249,10 +249,6 @@ The-EDT---Event-Dispatch-Thread.asciidoc This is best explained by an example. T The-EDT---Event-Dispatch-Thread.asciidoc To explain how invokeAndBlock works you can return to the sample above of how the EDT works: The-EDT---Event-Dispatch-Thread.asciidoc You can visualize the EDT as a loop such as this: The-EDT---Event-Dispatch-Thread.asciidoc `invokeAndBlock()` works in a similar way to this pseudo-code: -Video-Capture-Constraints.asciidoc Find out if this constraint will be obeyed: -Video-Capture-Constraints.asciidoc For example: -Video-Capture-Constraints.asciidoc Suppose you want to allow the user to capture a short (5 second) clip, in a low resolution, appropriate for sharing on a social media platform. You create your `VideoCaptureConstraints` object as follows: -Video-Capture-Constraints.asciidoc This constraint can then be passed to `Capture.captureVideo()` to get the captured file: Working-With-iOS.asciidoc Repeating notifications will continue until they're canceled by the app. You can cancel a single notification by calling: appendix_goal_generate_graphql.adoc The `@GraphQLClient` interface looks like: appendix_goal_generate_graphql.adoc an `OnComplete>`: From 25557621f702953f63ea25fd7deb8259ed9dfaa0 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 13:01:07 +0300 Subject: [PATCH 03/51] An unrelated subsection must not stand in for a swallowed chapter The outcome check compared counts of normalized headings at any depth, which a collision satisfies: "Analytics" is a chapter and also a subsection of Commerce, so the rendered book contains it twice. If the chapter were swallowed, the subsection kept the count at one and the check -- the central safeguard of this change -- passed. Measured on the current book: analytics appears twice at any level and once at chapter level; "getting started" four times at any level and never at chapter level. Manifest entries are now counted against chapter-level headings only. Nested fragments still use the any-level count, because their depth is whatever their parent gives them. Second finding: resolves() tried every matching redirect rule and passed if any chain worked. The host applies the FIRST match and stops, so a link matching an early rule that leads somewhere deleted would have passed on the strength of a later rule the reader never reaches. It now returns the first match's result. No guide link changes verdict today; the point is that the model matches the behaviour it claims to model. Also declined, with the reasoning left in the code rather than a review thread: adding Markdown's three-backtick fence to the literal-block list. The guide contains none, and validate-guide-snippets.py requires every listing to be [source,LANG] with a bare include:: inside ---- delimiters, so such a block would fail that gate before reaching this one. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 6 ++- .../developer-guide/check-guide-structure.py | 40 ++++++++++++++----- .../check-missing-code-blocks.py | 5 +++ 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index 55f111a0747..92b5826ac25 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -157,6 +157,9 @@ def resolves(target: str, known: set[str], rules: list, depth: int = 0) -> bool: match = compiled.match(target) if not match: continue + # The FIRST matching rule wins and the others never run, which is how the + # host evaluates this file. Trying later rules after an early one leads + # somewhere dead would pass a link whose reader lands on a deleted page. if not destination or not destination.startswith("/"): return True # redirects off-site; nothing here can verify it resolved = destination @@ -165,8 +168,7 @@ def resolves(target: str, known: set[str], rules: list, depth: int = 0) -> bool: resolved = normalize_path(resolved) if resolved == target: return False - if resolves(resolved, known, rules, depth + 1): - return True + return resolves(resolved, known, rules, depth + 1) return False diff --git a/scripts/developer-guide/check-guide-structure.py b/scripts/developer-guide/check-guide-structure.py index 94eabec1adc..4146c10493b 100755 --- a/scripts/developer-guide/check-guide-structure.py +++ b/scripts/developer-guide/check-guide-structure.py @@ -175,16 +175,25 @@ def render(root: Path) -> str: return out.read_text(encoding="utf-8") -def rendered_titles(markup: str) -> dict[str, int]: - """Count every rendered heading, normalized and stripped of its number.""" +def rendered_titles(markup: str) -> tuple[dict[str, int], dict[str, int]]: + """Count rendered headings: all levels, and chapter level (h2) separately. + + Counting every level lets an unrelated subsection stand in for a chapter that + was swallowed -- "Analytics" is a chapter and also a subsection of Commerce, + and "Getting started" collides the same way. A chapter renders as h2, so + holding manifest entries to that count removes the substitution. + """ body = markup.split('id="content"', 1)[-1] counts: dict[str, int] = {} + chapters: dict[str, int] = {} for match in re.finditer(r"]*>(.*?)", body, re.S): text = re.sub(r"<[^>]+>", "", match.group(2)) text = re.sub(r"^(Appendix [A-Z]:|(\d+|[A-Z])(\.\d+)*\.)\s*", "", html.unescape(text).strip()) key = normalize(text) counts[key] = counts.get(key, 0) + 1 - return counts + if match.group(1) == "2": + chapters[key] = chapters.get(key, 0) + 1 + return counts, chapters def main() -> int: @@ -286,8 +295,9 @@ def main() -> int: ) # 3. Outcome check: every included chapter's title survives into the book. - rendered = rendered_titles(render(root)) + rendered, rendered_chapters = rendered_titles(render(root)) expected: dict[str, list[str]] = {} + expected_chapters: dict[str, list[str]] = {} for path in sorted(walker.reachable): if path == root or path in walker.conditional: # A conditional entry renders in one branch only, so requiring its @@ -295,16 +305,28 @@ def main() -> int: # absent. Its level and spacing are still checked above. continue heading = first_heading(path) - if heading: - expected.setdefault(normalize(heading[1]), []).append(path.name) + if not heading: + continue + key = normalize(heading[1]) + # A direct entry must appear at CHAPTER level. A nested fragment sits at + # whatever depth its parent puts it, so it is only counted at all. + target = expected_chapters if path in walker.direct else expected + target.setdefault(key, []).append(path.name) + + for title, sources in sorted(expected_chapters.items()): + found = rendered_chapters.get(title, 0) + if found < len(sources): + errors.append( + f"{', '.join(sources)}: the title '{title}' appears {found} time(s) as a " + f"chapter in the rendered book but {len(sources)} manifest entr(ies) " + f"declare it. A chapter was swallowed by whatever precedes it." + ) for title, sources in sorted(expected.items()): - # Compare counts, not membership: a chapter sharing its title with another - # heading would otherwise hide the fact that it was swallowed. if rendered.get(title, 0) < len(sources): errors.append( f"{', '.join(sources)}: the title '{title}' appears " f"{rendered.get(title, 0)} time(s) in the rendered book but " - f"{len(sources)} document(s) declare it. A chapter was swallowed by " + f"{len(sources)} document(s) declare it. A fragment was swallowed by " f"whatever precedes it." ) diff --git a/scripts/developer-guide/check-missing-code-blocks.py b/scripts/developer-guide/check-missing-code-blocks.py index c486f434842..bda2aafbadb 100755 --- a/scripts/developer-guide/check-missing-code-blocks.py +++ b/scripts/developer-guide/check-missing-code-blocks.py @@ -30,6 +30,11 @@ # passthrough. The container delimiters -- ==== example, **** sidebar, ____ quote # -- hold ordinary prose, and skipping them hid six real holes in basics.asciidoc # alone, among them the setSameWidth example this check was written to find. +# +# Markdown's three-backtick fence is deliberately absent. The guide contains none, +# and validate-guide-snippets.py requires every listing to be [source,LANG] with a +# bare include:: inside ---- delimiters, so a three-backtick block would fail that +# gate before reaching this one. Add it here if that convention ever changes. FENCE_RE = re.compile(r"^(----|\.\.\.\.|````|\+\+\+\+)\s*$") # Lines that end in a colon without promising a listing: headings, attributes, # comments, block titles, list markers, table cells and block delimiters. From 877a37188abcc90a07c4e9202030a00e247c6b40 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 13:06:04 +0300 Subject: [PATCH 04/51] The ifeval branch of the conditional test could never match The pattern required empty brackets, which is right for ifdef and ifndef -- with content they are the single-line form and guard only that line -- but wrong for ifeval, which has no single-line form and always carries its expression in the brackets. So the directive was listed and never recognised. Latent: the manifest contains no ifeval, and its only conditionals are two single-line ifdef attribute assignments, which are still correctly treated as not opening a block. Fixed because a pattern that names three directives and handles two is a bug in what the code claims, not a missing feature. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-structure.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/developer-guide/check-guide-structure.py b/scripts/developer-guide/check-guide-structure.py index 4146c10493b..98f167e168a 100755 --- a/scripts/developer-guide/check-guide-structure.py +++ b/scripts/developer-guide/check-guide-structure.py @@ -133,7 +133,13 @@ def _inside_conditional(lines: list[str], index: int) -> bool: """ depth = 0 for line in lines[:index]: - if re.match(r"^(ifdef|ifndef|ifeval)::.*\[\s*\]\s*$", line): + # ifdef/ifndef open a block only with EMPTY brackets -- with content + # they are the single-line form and guard just that line. ifeval has + # no single-line form and always carries its expression in the + # brackets, so requiring them empty meant this could never match one. + if re.match(r"^(ifdef|ifndef)::[^\[]*\[\s*\]\s*$", line) or re.match( + r"^ifeval::\[", line + ): depth += 1 elif re.match(r"^endif::", line): depth = max(0, depth - 1) From 2a08ef7836ea65794a52dcb6908ed18f17e24bbc Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 14:26:10 +0300 Subject: [PATCH 05/51] Record why commented-out URLs are checked like any other Review asked for AsciiDoc comment-state tracking so that a URL inside a `//` line or a `////` block is skipped. Declining, and recording it where the next reader of this loop will look rather than in a review thread nobody reads. The guide has 120 files, zero commented-out URLs and zero `////` blocks, so the tracking would govern nothing that exists. It would also weaken the gate: with comments skipped, commenting a line out makes its finding disappear and lets the ratchet shrink, banking a "fix" while the dead link stays in the source waiting to be uncommented. Deleting the link is the fix. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index 92b5826ac25..289ad916094 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -276,6 +276,14 @@ def site_paths(repo_root: Path) -> tuple[set[str], list]: def findings_for(path: Path, known: set[str], patterns: list) -> list[tuple[str, str]]: + # Every URL in the source is checked, including any inside an AsciiDoc `//` + # line comment or `////` block. That is deliberate. Across the guide's 120 + # files there is not one commented-out URL and not one `////` block, so + # tracking comment state would buy nothing today -- and it would hand the + # gate a way to be silenced: comment the line out, the finding disappears, + # the ratchet shrinks, and the dead link is still sitting in the source + # waiting to be uncommented. Deleting the link is the fix. (Ordinary `//` + # comments do exist here, for editorial notes; none carries a URL.) out: list[tuple[str, str]] = [] for number, line in enumerate(path.read_text(encoding="utf-8").split("\n"), 1): for url in URL_RE.findall(line): From f69f47cf6cc25b11a6afb6e9097d99e7c070ec6f Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 14:29:39 +0300 Subject: [PATCH 06/51] Four links left the book to re-enter it, and nothing checked the anchor Review asked for fragment validation on same-site URLs. Measuring first: the guide holds 42 same-site URLs with a fragment, and 38 are /javadoc/ -- the one tree this script cannot enumerate, because it is generated from the framework sources at build time. The other four all pointed at `developer-guide.html#`: this book, linking into its own body. Those are the same defect as the fifteen `/manual/*.html` deep links already converted in this stack, missed because they use a different path. They send a reader out to the web to fetch the page they are reading, they do not work in the PDF, and a renamed section breaks them silently -- the anchor lives in the rendered book, so no amount of site-path checking can see it. So the fix is not to validate the fragment, it is to stop writing the link: all four become `<>` xrefs, which check-guide-xrefs.py already resolves against the rendered anchors. All three targets exist today, so this repairs no live 404 -- it moves four unguarded links under a gate. The rule closes the class rather than the four instances: any codenameone.com link whose path is one of this book's own routes and which carries a fragment is now reported. Verified non-vacuous by restoring one of the four and watching it fail, then reverting. Co-Authored-By: Claude Opus 5 (1M context) --- docs/developer-guide/Maven-Appendix-API.adoc | 4 ++-- .../appendix_goal_generate_native_interfaces.adoc | 4 ++-- scripts/developer-guide/check-guide-links.py | 11 ++++++++++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/docs/developer-guide/Maven-Appendix-API.adoc b/docs/developer-guide/Maven-Appendix-API.adoc index 69328d953c9..5b7202bb5f3 100644 --- a/docs/developer-guide/Maven-Appendix-API.adoc +++ b/docs/developer-guide/Maven-Appendix-API.adoc @@ -10,7 +10,7 @@ See https://www.codenameone.com/javadoc/[the JavaDocs] for a full list of suppor NOTE: The Codename One source is open source. Released under GPLv2 with Classpath Exception. -Codename One is much more than an API library. It provides a full tool-chain and eco-system for developing beautiful, performant native mobile apps with a single codebase in Java and Kotlin. Please see the https://www.codenameone.com/developer-guide.html#_introduction[introduction in the Developer guide] for a proper overview of Codename One. +Codename One is much more than an API library. It provides a full tool-chain and eco-system for developing beautiful, performant native mobile apps with a single codebase in Java and Kotlin. Please see the <<_introduction,introduction in the Developer guide>> for a proper overview of Codename One. === Limitations @@ -27,5 +27,5 @@ Add-on libraries can be added to your library in the common/pom.xml file, but, i Codename One supports its own library format (cn1lib) which sort of "certifies" that it's compatible with Codename One. Run `mvn cn1:settings` and open *Extensions* to browse the growing catalog of available cn1libs. See <>. -For more information about cn1libs, see https://www.codenameone.com/developer-guide.html#_libraries_cn1lib[the cn1libs section] of the developer guide. +For more information about cn1libs, see <<_libraries_cn1lib,the cn1libs section>> of the developer guide. diff --git a/docs/developer-guide/appendix_goal_generate_native_interfaces.adoc b/docs/developer-guide/appendix_goal_generate_native_interfaces.adoc index 50293736521..84408f4d2b9 100644 --- a/docs/developer-guide/appendix_goal_generate_native_interfaces.adoc +++ b/docs/developer-guide/appendix_goal_generate_native_interfaces.adoc @@ -4,11 +4,11 @@ Generates stub implementations for all native interfaces defined in the project. You should run this goal explicitly after you create a native interface in your class. -See the Codename One Developer guide section on https://www.codenameone.com/developer-guide.html#_native_interfaces[native interfaces] for more information on creating native interfaces. +See the Codename One Developer guide section on <<_native_interfaces,native interfaces>> for more information on creating native interfaces. ==== Usage example -Suppose you've created a native interface as the Java interface `com.mycompany.myapp.MyNative`, as described in the example in https://www.codenameone.com/developer-guide.html#_native_interfaces[native interfaces]. +Suppose you've created a native interface as the Java interface `com.mycompany.myapp.MyNative`, as described in the example in <<_native_interfaces,native interfaces>>. After creating this (and possibly other) native interfaces in your project, run the `generate-native-interfaces` Maven goal as follows: diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index 289ad916094..d267bbdd7c4 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -41,6 +41,13 @@ # Only the marketing site is served from the redirect table and the Hugo content # tree. cloud.codenameone.com and friends are separate services. SITE_HOSTS = {"codenameone.com", "www.codenameone.com"} +# The routes that serve this very book. A link from inside the guide to one of +# these, carrying a fragment, is a cross-reference wearing a URL: it leaves the +# reader's PDF or offline copy to fetch a page they are already reading, and no +# gate can tell that a renamed section broke the fragment, because the anchor +# lives in the rendered book rather than in the site tree. Written as `<>` +# instead, check-guide-xrefs.py resolves it against the rendered anchors. +SELF_PATHS = {"/developer-guide", "/developer-guide.html", "/manual", "/manual.html"} def front_matter(page: Path) -> dict[str, object]: @@ -297,7 +304,9 @@ def findings_for(path: Path, known: set[str], patterns: list) -> list[tuple[str, out.append((url, "plain http, not https")) if host in SITE_HOSTS: target = split.path.rstrip("/") or "/" - if not resolves(target, known, patterns): + if split.fragment and target in SELF_PATHS: + out.append((url, "links into this book's own body; use an xref so the anchor is checked")) + elif not resolves(target, known, patterns): out.append((url, "the website serves no such path (checked _redirects and the content tree)")) return out From 82ed7bf02798f816ad8298453090d6f995073893 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 14:53:59 +0300 Subject: [PATCH 07/51] Two silent blind spots in the guards become loud refusals Both findings describe constructs the guide does not contain, so neither is a live defect. Both are real holes in the checkers though, and each closes for a few lines, so they close rather than getting argued with. Conditional includes (check-guide-structure.py). A manifest entry inside an ifdef/ifeval was skipped by the duplicate count -- correctly, since the same chapter under two exclusive branches is one chapter in the output -- and also by the rendered-title check, since only one branch renders. Skipping both means a chapter included twice inside a single ACTIVE branch would pass silently. Rather than teach the checker to distinguish exclusive branches for a construct that does not exist (measured: zero include:: lines sit inside a conditional anywhere in the guide), a conditional manifest entry is now refused outright, with a message saying what to extend if one is ever wanted. Trailing slashes on file paths (check-guide-links.py). Site paths were compared with the trailing slash stripped, so a link to `/x.jar/` was validated against `/x.jar`. The reviewer's premise checks out: _redirects declares the two forms as separate routes and spells both out where both work, 32 such pairs. Preserving the slash everywhere would break the many legitimate directory links, so the narrow case is reported instead -- a last path segment containing a dot, wearing a trailing slash. Directory routes such as /blog/ and /javadoc/com/codename1/io/ have no dot in the last segment and are untouched. Both rules verified non-vacuous by introducing an instance and reading the real exit status rather than a pipeline's: structure and links each exit 1 on the probe and 0 once it is reverted. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 9 +++++++++ scripts/developer-guide/check-guide-structure.py | 16 ++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index d267bbdd7c4..d75883d1102 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -306,6 +306,15 @@ def findings_for(path: Path, known: set[str], patterns: list) -> list[tuple[str, target = split.path.rstrip("/") or "/" if split.fragment and target in SELF_PATHS: out.append((url, "links into this book's own body; use an xref so the anchor is checked")) + elif split.path.endswith("/") and "." in split.path.rstrip("/").rsplit("/", 1)[-1]: + # The site treats "/x.html" and "/x.html/" as separate routes and + # declares both explicitly where both work -- 32 such pairs in + # _redirects. Normalising the slash away below would validate the + # variant that was not asked for, so a file path wearing a trailing + # slash is reported rather than quietly rewritten. Directory routes + # (/blog/, /javadoc/com/codename1/io/) have no dot in the last + # segment and are untouched. + out.append((url, "a file path with a trailing slash; the site serves that as a separate route")) elif not resolves(target, known, patterns): out.append((url, "the website serves no such path (checked _redirects and the content tree)")) return out diff --git a/scripts/developer-guide/check-guide-structure.py b/scripts/developer-guide/check-guide-structure.py index 98f167e168a..c6c4c9844ea 100755 --- a/scripts/developer-guide/check-guide-structure.py +++ b/scripts/developer-guide/check-guide-structure.py @@ -118,7 +118,23 @@ def _visit(self, path: Path, attrs_from_parent: str) -> None: self.direct.add(target) self._check_manifest_spacing(index, lines, target_raw) if self._inside_conditional(lines, index): + # Nothing in the manifest is conditional today (measured: zero + # include:: lines sit inside a conditional anywhere in the guide), + # and the two checks that matter cannot see one. The duplicate + # count has to skip it, because the same chapter under two + # exclusive branches is one chapter in the output; the + # rendered-title check has to skip it too, because only one + # branch renders. Skipping BOTH silently means a chapter + # included twice inside a single active branch would pass. + # So refuse the construct instead of quietly not validating it. self.conditional.add(target) + self.errors.append( + f"developer-guide.asciidoc:{index + 1}: {target_raw} is included " + f"inside a conditional. Neither the duplicate check nor the " + f"rendered-title check can validate a conditional entry, so this " + f"refuses it rather than skipping it silently. Teach the checker " + f"which branches are mutually exclusive before adding one." + ) else: self.direct_include_count[target] += 1 self._visit(target, attrs) From 520ced08ab7d00ec66d6687802681f2cce655dc8 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 15:26:59 +0300 Subject: [PATCH 08/51] Check what swallows a heading, not whether its title turns up somewhere Review is right that the rendered-title check has slack: it counts normalized titles across the whole book, so a nested fragment losing its heading can be covered by an identical heading elsewhere. Confirmed rather than accepted -- removing the leveloffset from both Maven includes takes "Getting started" from 4 rendered headings to 3, while only one file declares it, so `3 >= 1` and the gate passed a genuinely swallowed section. Rather than give nested fragments a rendered identity, which the HTML does not carry, this checks the cause. The spacing rule already existed but ran only on the root manifest, and its condition was "a blank line follows". Both were wrong. Reproduced minimally to find the real rule -- a heading is absorbed only when ALL of these hold: * the include is followed immediately by content, and * neither this include nor the following one carries leveloffset (asciidoctor brackets the content with :leveloffset: attribute entries, and an attribute entry closes the paragraph -- the one on the FOLLOWING include lands between the paragraph and the heading, so it protects just as well), and * the included file does not end on a blank line, and * its last line is ordinary paragraph text -- a delimiter, table row, heading, attribute entry or comment all close the paragraph. That is why _generated-build-hints.adoc, which ends on "|===", does not eat the "Versioned builds" heading directly after it. Against the real book, all four combinations now agree with what asciidoctor actually renders: both leveloffset 4 headings renders ok gate passes only current 4 headings renders ok gate passes only following 4 headings renders ok gate passes neither 3 headings SWALLOWED gate fails An earlier draft exempted only the current include and failed the third row -- a false positive on markup that renders correctly. Every guide include is now checked, not just the manifest's: measured across all 120 files, this leaves zero findings, because the five adjacent includes in Maven-Project-Workflow.asciidoc are protected by leveloffset. Co-Authored-By: Claude Opus 5 (1M context) --- .../developer-guide/check-guide-structure.py | 85 +++++++++++++++---- 1 file changed, 69 insertions(+), 16 deletions(-) diff --git a/scripts/developer-guide/check-guide-structure.py b/scripts/developer-guide/check-guide-structure.py index c6c4c9844ea..cae365bdd6c 100755 --- a/scripts/developer-guide/check-guide-structure.py +++ b/scripts/developer-guide/check-guide-structure.py @@ -110,13 +110,13 @@ def _visit(self, path: Path, attrs_from_parent: str) -> None: f"{path.name}:{index + 1}: include target does not exist: {target_raw}" ) continue + self._check_include_spacing(path, index, lines, target_raw, attrs, target) if path == self.root: # A conditional entry is still a chapter: it must open at chapter # level and be spaced correctly. Only the DUPLICATE count skips # it, because the same chapter under two exclusive branches # appears twice in the source and once in the output. self.direct.add(target) - self._check_manifest_spacing(index, lines, target_raw) if self._inside_conditional(lines, index): # Nothing in the manifest is conditional today (measured: zero # include:: lines sit inside a conditional anywhere in the guide), @@ -161,26 +161,79 @@ def _inside_conditional(lines: list[str], index: int) -> bool: depth = max(0, depth - 1) return depth > 0 - def _check_manifest_spacing(self, index: int, lines: list[str], target_raw: str) -> None: - """Require a blank line after every include in the top-level manifest. + # A delimited block, a heading, an attribute entry or a directive all close the + # paragraph context. Only ordinary paragraph text leaves it open, and only an + # open paragraph can absorb the heading that follows it. + _CLOSES_PARAGRAPH = re.compile( + r"^(=+\s|:[^:]+:|//|\[|\||([-=_.*+/])\2{3,}\s*$)" + ) - Two adjacent include lines put the first target's last line next to the - second target's first line. When the first ends on a paragraph, the second - chapter's title becomes a continuation of it and the chapter disappears - without a single warning -- which is exactly how the native Linux chapter - spent its life rendered as subsections of the Windows one. + def _check_include_spacing( + self, + path: Path, + index: int, + lines: list[str], + target_raw: str, + attrs: str, + target: Path, + ) -> None: + """Reject an include whose target can swallow whatever follows it. + + This is the defect the whole checker was written for: two adjacent + include:: lines put the first file's last line against the second file's + first line, and if the first ends mid-paragraph the second's title becomes + a continuation of it. Asciidoctor emits no warning, and the native Linux + chapter spent its life rendered as subsections of the Windows one. + + Measured with a minimal reproduction rather than assumed, because three of + the four ways out are not obvious: + + * a blank line in the parent separates them -- safe; + * leveloffset= wraps the include in :leveloffset: attribute entries, and + those lines close the paragraph -- safe, which is why the five adjacent + includes in Maven-Project-Workflow.asciidoc render correctly; + * the included file ending on a blank line -- safe; + * the included file ending on a delimiter, table row, heading, attribute or + comment -- safe, which is why _generated-build-hints.adoc ending on + "|===" does not eat the "Versioned builds" heading after it. + + What is left -- an adjacent include, no leveloffset, whose file ends on + ordinary paragraph text -- is the one shape that silently deletes content. """ following = lines[index + 1] if index + 1 < len(lines) else "" - # A preprocessor directive is not content and cannot absorb a paragraph, - # so an include closed by endif:: on the next line is correctly spaced. + if not following.strip(): + return + # A preprocessor directive is not content and cannot absorb a paragraph. if re.match(r"^(ifdef|ifndef|ifeval|endif)::", following.strip()): return - if following.strip(): - self.errors.append( - f"developer-guide.asciidoc:{index + 1}: include of {target_raw} is not " - f"followed by a blank line. Two adjacent includes let the first " - f"chapter's trailing paragraph swallow the second chapter's title." - ) + # A leveloffset on EITHER include protects: asciidoctor brackets the + # included content with :leveloffset: attribute entries, and an attribute + # entry closes the paragraph. The one on the following include lands + # between the paragraph and the heading, so it works just as well as the + # one on this include. Measured both ways. + if "leveloffset" in attrs: + return + following_include = INCLUDE_RE.match(following.strip()) + if following_include and "leveloffset" in following_include.group(2): + return + try: + text = target.read_text(encoding="utf-8", errors="ignore") + except OSError: + return + if text.endswith("\n\n") or not text.strip(): + return + last = next( + (line for line in reversed(text.split("\n")) if line.strip()), "" + ) + if self._CLOSES_PARAGRAPH.match(last.strip()): + return + self.errors.append( + f"{path.name}:{index + 1}: include of {target_raw} is followed immediately " + f"by content, and {target.name} ends on a paragraph. That paragraph will " + f"absorb whatever comes next, deleting it from the book without a warning. " + f"Add a blank line after the include, or a leveloffset attribute, or end " + f"{target.name} with a blank line." + ) def render(root: Path) -> str: From 9ffb68c805035b8ab67a39cb933ab46cfa7e7053 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 15:29:48 +0300 Subject: [PATCH 09/51] The slash rule rejected routes the site declares, and Hugo could move the rest Three link findings, and only the first was a live defect -- in the rule I added one commit earlier. The trailing-slash rule was unconditional, so it reported "/videos.html/" as broken even though _redirects declares that exact source and the site serves it. The rules here all compile slash-insensitively ("^...$/?"), which is right for matching but discards the distinction the site actually draws, so the raw sources are now collected alongside them and a slashed file path is reported only when _redirects does not spell it out. Probed both ways: "/videos.html/" passes, "/files/CodenameOneBuildClient.jar/" fails. Hugo route overrides. hugo.toml sets neither [permalinks] nor uglyURLs today, so deriving a route as "section path + slug" is currently correct; if either appears, every route underneath moves and this would go on accepting links to paths Hugo no longer publishes. Modelling a configuration that is not there would be guesswork, and reading the built public/ tree makes a local run depend on a tree that may be stale or absent. So it now notices instead: either key present aborts the check with what to do about it. Probed with each key in turn. Protocol-relative links and fragments on ordinary same-site pages are declined, with the measurements recorded in the code rather than in a review thread nobody reads. The guide has no `link://` macro at all, and its one bare "//host/path" is a JavaScript string inside a source block, so widening URL_RE to match "//" would start reporting code as a broken link. And of the 42 same-site URLs carrying a fragment, 38 are /javadoc/ -- generated at build time, exempt for that reason -- while the other four pointed into this book and are now xrefs, which check-guide-xrefs.py resolves against the rendered anchors. Nothing is left that this script could check without building the Hugo site. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 74 ++++++++++++++++---- 1 file changed, 61 insertions(+), 13 deletions(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index d75883d1102..b6175c5eb5e 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -179,7 +179,7 @@ def resolves(target: str, known: set[str], rules: list, depth: int = 0) -> bool: return False -def site_paths(repo_root: Path) -> tuple[set[str], list]: +def site_paths(repo_root: Path) -> tuple[set[str], list, set[str]]: """Every path the website is known to answer on, derived rather than listed. Returns the literal paths and every redirect rule, each as a matcher, its @@ -188,6 +188,10 @@ def site_paths(repo_root: Path) -> tuple[set[str], list]: """ paths: set[str] = set() patterns: list = [] + # The sources exactly as written. Every rule is compiled slash-insensitively + # ("^...$/?"), which is right for matching but loses the distinction the site + # actually draws, so the trailing-slash rule needs the raw spelling. + declared: set[str] = set() redirects = repo_root / "docs/website/static/_redirects" if redirects.exists(): @@ -196,6 +200,7 @@ def site_paths(repo_root: Path) -> tuple[set[str], list]: if not parts or parts[0].startswith("#"): continue destination = parts[1] if len(parts) > 1 else "" + declared.add(parts[0]) compiled = redirect_pattern(parts[0]) if compiled is not None: patterns.append((compiled[0], compiled[1], destination)) @@ -236,6 +241,28 @@ def site_paths(repo_root: Path) -> tuple[set[str], list]: continue paths.add(normalize_path("developer-guide/" + relative.as_posix())) + # This derives a Hugo route as "section path + slug", which is true only while + # the site leaves routing alone. A [permalinks] rule or uglyURLs would rewrite + # every route underneath and this would keep accepting links to paths Hugo no + # longer publishes -- accepting a dead link is exactly the failure this script + # exists to prevent. hugo.toml declares neither today, so rather than model a + # configuration that is not there, notice when it appears. + hugo_config = repo_root / "docs/website/hugo.toml" + if hugo_config.exists(): + config = hugo_config.read_text(encoding="utf-8", errors="ignore") + overrides = [ + name + for name, probe in (("[permalinks]", r"^\s*\[permalinks\]"), ("uglyURLs", r"^\s*uglyURLs\s*=")) + if re.search(probe, config, re.M) + ] + if overrides: + raise SystemExit( + f"hugo.toml now sets {', '.join(overrides)}, which rewrites the routes " + f"this script derives from the content tree. Derive them from the built " + f"docs/website/public tree instead, or teach this function the rule -- " + f"until then every link it accepts is unverified." + ) + today = datetime.date.today().isoformat() content = repo_root / "docs/website/content" if content.exists(): @@ -279,10 +306,24 @@ def site_paths(repo_root: Path) -> tuple[set[str], list]: if asset.name == "index.html": paths.add(normalize_path(asset.parent.relative_to(static).as_posix())) - return paths, patterns + return paths, patterns, declared -def findings_for(path: Path, known: set[str], patterns: list) -> list[tuple[str, str]]: +def findings_for(path: Path, known: set[str], patterns: list, declared: set[str]) -> list[tuple[str, str]]: + # Only http:// and https:// are extracted. Protocol-relative links were raised + # as a gap; measured, the guide contains no `link://` macro at all, and its one + # bare `//host/path` is a JavaScript string inside a source block, so widening + # URL_RE to match `//` would start reporting code as a broken link. The scheme + # requirement is what keeps this off code. + # + # Fragments are checked only against this book's own routes. On an ordinary + # same-site page the anchors live in Hugo's rendered output, which this does + # not build, so a fragment there cannot be resolved from the repository. + # Measured: of the 42 same-site URLs carrying a fragment, 38 are /javadoc/ -- + # generated at build time and exempt for the same reason -- and the other four + # pointed into this book and are now xrefs, which check-guide-xrefs.py resolves + # against the rendered anchors. That leaves nothing this could check today. + # # Every URL in the source is checked, including any inside an AsciiDoc `//` # line comment or `////` block. That is deliberate. Across the guide's 120 # files there is not one commented-out URL and not one `////` block, so @@ -306,15 +347,22 @@ def findings_for(path: Path, known: set[str], patterns: list) -> list[tuple[str, target = split.path.rstrip("/") or "/" if split.fragment and target in SELF_PATHS: out.append((url, "links into this book's own body; use an xref so the anchor is checked")) - elif split.path.endswith("/") and "." in split.path.rstrip("/").rsplit("/", 1)[-1]: + elif ( + split.path.endswith("/") + and "." in split.path.rstrip("/").rsplit("/", 1)[-1] + and split.path not in declared + ): # The site treats "/x.html" and "/x.html/" as separate routes and - # declares both explicitly where both work -- 32 such pairs in - # _redirects. Normalising the slash away below would validate the - # variant that was not asked for, so a file path wearing a trailing - # slash is reported rather than quietly rewritten. Directory routes - # (/blog/, /javadoc/com/codename1/io/) have no dot in the last - # segment and are untouched. - out.append((url, "a file path with a trailing slash; the site serves that as a separate route")) + # spells both out where both work -- 32 such pairs in _redirects. + # Every rule here compiles slash-insensitively, so the normalised + # lookup below would silently validate the variant that was NOT + # asked for. Hence: a file path wearing a trailing slash is + # reported, UNLESS _redirects declares that exact spelling, which + # is the site saying it serves it -- "/videos.html/" is declared + # and must not be reported. Directory routes such as /blog/ and + # /javadoc/com/codename1/io/ have no dot in the last segment and + # never reach this branch. + out.append((url, "a file path with a trailing slash that _redirects does not declare")) elif not resolves(target, known, patterns): out.append((url, "the website serves no such path (checked _redirects and the content tree)")) return out @@ -353,7 +401,7 @@ def main() -> int: args = parser.parse_args() guide_dir = args.guide_dir.resolve() - known, patterns = site_paths(args.repo_root.resolve()) + known, patterns, declared = site_paths(args.repo_root.resolve()) if not known: raise SystemExit("could not derive any site paths; is --repo-root correct?") @@ -363,7 +411,7 @@ def main() -> int: if path.suffix not in ASCIIDOC_EXTENSIONS or not path.is_file(): continue name = path.relative_to(guide_dir).as_posix() - for url, reason in findings_for(path, known, patterns): + for url, reason in findings_for(path, known, patterns, declared): entry = f"{name}\t{url}" current[entry] += 1 reasons[entry] = reason From 4f6f2a586b46e7ade9d110e42f6fea0bd424848c Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 16:06:22 +0300 Subject: [PATCH 10/51] The PDF branch was never rendered, and an admonition counted as a listing Two more holes in the guards. Neither has an instance in the guide today, and both close cheaply enough that arguing about them would cost more. check-guide-xrefs.py rendered the book once, with the default backend, so anything inside ifdef::backend-pdf[] was dropped before a single reference in it could be examined -- while the workflow publishes an asciidoctor-pdf build from the same source. Native-Themes.asciidoc already has two such branches. It now renders twice, the second time with -a backend-pdf, which selects exactly the content the PDF build includes without needing asciidoctor-pdf here. The two runs are checked SEPARATELY rather than pooled: an anchor that exists only in the HTML branch must not satisfy a reference made in the PDF branch. Findings name the branch they came from. A/B with a dangling xref planted inside the backend-pdf branch of Native-Themes.asciidoc: old "Cross-references OK: 1741 anchors" -- exit 0 new "Native-Themes.asciidoc:506: <> ... (1 reference(s), pdf render)" -- exit 1 check-missing-code-blocks.py accepted any `[attribute]` line as the start of the promised block, so an admonition standing where a listing used to be hid the hole. An admonition is prose and can never be the listing a sentence promised, so the five names are excluded. Excluded by name rather than by whitelisting the kinds that ARE code: measured, the bracket lines legitimately answering a promising sentence already span [source] (582), [cols=...] and [options=...] (56), [listing] (3), [quote] (2) and an anchored image, and a whitelist would report the next kind nobody anticipated. A/B with each block planted after a promising sentence, using the real signature of a removed listing -- the two blank lines it leaves behind: [NOTE] old: none new new: reported as a hole [source,java] old: none new new: none new The baseline is unchanged at 402, because the guide currently has no admonition sitting in a listing's place. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-xrefs.py | 53 +++++++++++++------ .../check-missing-code-blocks.py | 9 +++- 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/scripts/developer-guide/check-guide-xrefs.py b/scripts/developer-guide/check-guide-xrefs.py index e1fe0a5049d..8da769687bf 100755 --- a/scripts/developer-guide/check-guide-xrefs.py +++ b/scripts/developer-guide/check-guide-xrefs.py @@ -32,14 +32,24 @@ ANCHOR_SOURCE_RE = re.compile(r"<<([^>,]+)") -def render(root: Path) -> str: +# The book has ifdef::backend-pdf[] branches, and the PDF is published alongside +# the HTML. Rendering only the default backend drops that content before any +# reference in it can be examined, so a dangling PDF-only xref would ship +# unchecked. Setting the attribute on an HTML render selects exactly the content +# the PDF build includes, without needing asciidoctor-pdf here. The two runs are +# checked SEPARATELY, never pooled: an anchor that exists only in the HTML branch +# must not be allowed to satisfy a reference made in the PDF branch. +BACKENDS = (("html", ()), ("pdf", ("backend-pdf",))) + + +def render(root: Path, attributes: tuple[str, ...] = ()) -> str: with tempfile.TemporaryDirectory() as tmp: out = Path(tmp) / "guide.html" - result = subprocess.run( - ["asciidoctor", "--require", "rouge", "-o", str(out), str(root)], - capture_output=True, - text=True, - ) + command = ["asciidoctor", "--require", "rouge"] + for attribute in attributes: + command += ["-a", attribute] + command += ["-o", str(out), str(root)] + result = subprocess.run(command, capture_output=True, text=True) if result.returncode != 0: print(result.stderr, file=sys.stderr) raise SystemExit("asciidoctor failed to render the guide") @@ -66,28 +76,37 @@ def main() -> int: guide_dir = args.guide_dir.resolve() root = guide_dir / "developer-guide.asciidoc" - markup = render(root) - - ids = set(ID_RE.findall(markup)) dangling: dict[str, int] = defaultdict(int) - for target in HREF_RE.findall(markup): - if target not in ids: - dangling[target] += 1 - raw_id_links: dict[str, int] = defaultdict(int) - for target in RAW_ID_LINK_RE.findall(markup): - raw_id_links[target] += 1 + branches: dict[str, set[str]] = defaultdict(set) + anchor_total = 0 + + for name, attributes in BACKENDS: + markup = render(root, attributes) + ids = set(ID_RE.findall(markup)) + anchor_total = max(anchor_total, len(ids)) + for target in HREF_RE.findall(markup): + if target not in ids: + dangling[target] += 1 + branches[target].add(name) + for target in RAW_ID_LINK_RE.findall(markup): + raw_id_links[target] += 1 + branches[target].add(name) if not dangling and not raw_id_links: - print(f"Cross-references OK: {len(ids)} anchors, every internal link resolves.") + print( + f"Cross-references OK: {anchor_total} anchors, every internal link " + f"resolves in both the default and backend-pdf renders." + ) return 0 for target in sorted(dangling): where = source_locations(guide_dir, target) location = ", ".join(where) if where else "not found in source (generated content?)" + where_rendered = "/".join(sorted(branches[target])) + " render" print( f"{location}: <<{target}>> points at an id that does not exist in the " - f"rendered book ({dangling[target]} reference(s)).", + f"rendered book ({dangling[target]} reference(s), {where_rendered}).", file=sys.stderr, ) for target in sorted(raw_id_links): diff --git a/scripts/developer-guide/check-missing-code-blocks.py b/scripts/developer-guide/check-missing-code-blocks.py index bda2aafbadb..062f478eba1 100755 --- a/scripts/developer-guide/check-missing-code-blocks.py +++ b/scripts/developer-guide/check-missing-code-blocks.py @@ -47,8 +47,15 @@ # listing by more than one blank line is untidy, not a hole, and reporting it # would make the gate reject valid AsciiDoc spacing. Deliberately conservative: # only unambiguous starts, so a genuine hole is never explained away. +# An admonition is prose, so it can never be the listing a sentence promised. +# Excluded by name rather than by whitelisting the block kinds that ARE code: +# measured, the bracket lines that legitimately answer a promising sentence +# already span [source], [listing], [cols=...], [options=...], [quote] and an +# anchored image, and a whitelist would report the next kind nobody thought of. +ADMONITION = "NOTE|TIP|IMPORTANT|WARNING|CAUTION" BLOCK_START_RE = re.compile( - r'^(\[[a-zA-Z%.#"]|image::|include::|\|===|(----|\.\.\.\.|````|\+\+\+\+|====|\*\*\*\*|____)\s*$)' + r'^(\[(?!(?:' + ADMONITION + r')\])[a-zA-Z%.#"]' + r'|image::|include::|\|===|(----|\.\.\.\.|````|\+\+\+\+|====|\*\*\*\*|____)\s*$)' ) From bbc2ee530b4e532ca1407e9c1a6573c147f1bd3e Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 17:15:55 +0300 Subject: [PATCH 11/51] Three links from the old wiki went nowhere, and a directive is not a separator Two findings, and this time the first one is live. The rendered book contains exactly three relative hrefs, and all three are broken: css.asciidoc carried link:Images[], link:Fonts[] and link:Supported-Properties#text-decoration[] over from the wiki this guide replaced, naming pages that were never carried across with them. The guide renders as a single page, so a relative href resolves against wherever that page is served and reaches nothing that ships with it -- the reader gets a 404 while every gate reported success. All three targets are sections in that same file: [[Images]] already existed, [[Fonts]] is added to match it, and [[text-decoration]] was already there and already used by a sibling reference. check-guide-xrefs.py now reports any relative href, which after this change has zero instances. Absolute URLs stay with check-guide-links.py, and root-relative paths and fragments are excluded. A/B with one link restored: old printed "Cross-references OK" and exited 0, new reports it and exits 1. The second is a wrong claim in my own comment. check-guide-structure.py returned early when an include was followed by ifdef/ifndef/ifeval/endif, on the reasoning that "a preprocessor directive is not content and cannot absorb a paragraph". True, and irrelevant: asciidoctor REMOVES the directive during preprocessing, so it does not separate anything either. Measured -- with `ifdef::backend-html5[]` between an include ending in prose and a following heading, the render contains zero heading tags and the paragraph reads "...preferred tools. === A parent-local heading". The rule now scans past directive lines to the first line that survives preprocessing. A/B on that construct: old passed it, new reports it. Note the rendered-title check cannot cover this case either, because a parent-local heading is not the first heading of any included file. Co-Authored-By: Claude Opus 5 (1M context) --- docs/developer-guide/css.asciidoc | 7 ++--- .../developer-guide/check-guide-structure.py | 17 +++++++++--- scripts/developer-guide/check-guide-xrefs.py | 26 ++++++++++++++++--- 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/docs/developer-guide/css.asciidoc b/docs/developer-guide/css.asciidoc index eb415d6d4e8..50773702d66 100644 --- a/docs/developer-guide/css.asciidoc +++ b/docs/developer-guide/css.asciidoc @@ -188,7 +188,7 @@ a|3D lowered text. For example, `text-decoration: cn1-3d-lowered;` image:img/cn1 |3D text with north shadow. For example, `text-decoration: cn1-3d-shadow-north;` image:img/cn1-3d-shadow-north.png[cn1-3d-shadow-north screenshot] |=== -For other CSS font settings see link:Fonts[the Fonts section] +For other CSS font settings see <> [[border]] ==== Border @@ -270,7 +270,7 @@ WARNING: 9-piece Image borders always take precedence over background settings i ===== Background images -See link:Images[Images] +See <> ===== Gradients @@ -558,6 +558,7 @@ include::../demos/common/src/main/css/guide-snippets-theme.css[tag=css-css-026,i CN1 resource files support both PNG and JPEG images, but PNG is the default. Multi-images that are generated by the CSS compiler will be PNG if they include alpha transparency, and JPEG otherwise. This is to try to reduce the file size as much as possible while not sacrificing quality. +[[Fonts]] === Fonts This library supports the https://developer.mozilla.org/en/docs/Web/CSS/font[font], https://developer.mozilla.org/en/docs/Web/CSS/font-size[font-size], https://developer.mozilla.org/en/docs/Web/CSS/font-family[font-family], https://developer.mozilla.org/en/docs/Web/CSS/font-style[font-style], https://developer.mozilla.org/en/docs/Web/CSS/font-weight[font-weight], and https://developer.mozilla.org/en/docs/Web/CSS/text-decoration[text-decoration] properties, as well as the https://developer.mozilla.org/en/docs/Web/CSS/@font-face[@font-face] CSS "at" rule for including TrueType and OpenType fonts. @@ -701,7 +702,7 @@ NOTE: When a new iPhone model ships with a resolution that isn't yet in the iOS ==== `text-decoration` -See link:Supported-Properties#text-decoration[the text-decoration section] in the "Supported Properties" page. +See <>. ==== Some sample CSS directives diff --git a/scripts/developer-guide/check-guide-structure.py b/scripts/developer-guide/check-guide-structure.py index cae365bdd6c..68e9694175a 100755 --- a/scripts/developer-guide/check-guide-structure.py +++ b/scripts/developer-guide/check-guide-structure.py @@ -200,12 +200,21 @@ def _check_include_spacing( What is left -- an adjacent include, no leveloffset, whose file ends on ordinary paragraph text -- is the one shape that silently deletes content. """ - following = lines[index + 1] if index + 1 < len(lines) else "" + # Look PAST preprocessor directives rather than treating one as a + # separator. Asciidoctor removes ifdef/ifndef/ifeval/endif during + # preprocessing, so they leave nothing behind to close the paragraph -- + # measured: a heading with `ifdef::backend-html5[]` between it and the + # preceding paragraph is swallowed exactly as if the directive were not + # there. An earlier version of this rule returned here and would have + # passed that. + cursor = index + 1 + while cursor < len(lines) and re.match( + r"^(ifdef|ifndef|ifeval|endif)::", lines[cursor].strip() + ): + cursor += 1 + following = lines[cursor] if cursor < len(lines) else "" if not following.strip(): return - # A preprocessor directive is not content and cannot absorb a paragraph. - if re.match(r"^(ifdef|ifndef|ifeval|endif)::", following.strip()): - return # A leveloffset on EITHER include protects: asciidoctor brackets the # included content with :leveloffset: attribute entries, and an attribute # entry closes the paragraph. The one on the following include lands diff --git a/scripts/developer-guide/check-guide-xrefs.py b/scripts/developer-guide/check-guide-xrefs.py index 8da769687bf..8bea98a472d 100755 --- a/scripts/developer-guide/check-guide-xrefs.py +++ b/scripts/developer-guide/check-guide-xrefs.py @@ -23,6 +23,14 @@ ID_RE = re.compile(r'\bid="([^"]+)"') HREF_RE = re.compile(r'href="#([^"]+)"') +# The guide renders as one page, so a RELATIVE href resolves against wherever that +# page happens to be served and reaches nothing that ships with it. Three survived +# from the wiki this book replaced -- link:Images[], link:Fonts[] and +# link:Supported-Properties#text-decoration[] -- naming pages that were never +# carried across, and a reader following one landed on a 404 while every gate +# reported success. Absolute URLs (checked by check-guide-links.py), root-relative +# paths and same-page fragments are all excluded. +RELATIVE_HREF_RE = re.compile(r'href="(?!#|/|[a-zA-Z][a-zA-Z0-9+.-]*:)([^"]+)"') # Asciidoctor falls back to printing the raw id in brackets when a reference # resolves to an anchor that carries no title -- an anchor on an image or a # paragraph rather than on a section. The link works; the sentence reads @@ -78,6 +86,7 @@ def main() -> int: root = guide_dir / "developer-guide.asciidoc" dangling: dict[str, int] = defaultdict(int) raw_id_links: dict[str, int] = defaultdict(int) + relative: dict[str, int] = defaultdict(int) branches: dict[str, set[str]] = defaultdict(set) anchor_total = 0 @@ -92,8 +101,11 @@ def main() -> int: for target in RAW_ID_LINK_RE.findall(markup): raw_id_links[target] += 1 branches[target].add(name) + for target in RELATIVE_HREF_RE.findall(markup): + relative[target] += 1 + branches[target].add(name) - if not dangling and not raw_id_links: + if not dangling and not raw_id_links and not relative: print( f"Cross-references OK: {anchor_total} anchors, every internal link " f"resolves in both the default and backend-pdf renders." @@ -119,9 +131,17 @@ def main() -> int: f"(<<{target},some words>>) or move the anchor onto the section.", file=sys.stderr, ) + for target in sorted(relative): + print( + f"css.asciidoc or elsewhere: link:{target}[] renders as a relative URL " + f"({relative[target]} reference(s)). The guide is one page, so this " + f"reaches nothing that ships with it -- use an xref, or an absolute URL " + f"if the destination really is off-site.", + file=sys.stderr, + ) print( - f"\n{len(dangling)} dangling and {len(raw_id_links)} untitled " - f"cross-reference target(s).", + f"\n{len(dangling)} dangling, {len(raw_id_links)} untitled and " + f"{len(relative)} relative cross-reference target(s).", file=sys.stderr, ) return 1 From 9a508aa7e1ec09d6fdb368f8d1dcec1cb6c107b5 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 17:41:26 +0300 Subject: [PATCH 12/51] A Cloudflare function serves /files and /demos, and the PDF surrogate has a limit The first finding was live: the link ratchet held a working link. docs/website/functions/[[path]].js runs after context.next() has already 404ed and then redirects anything under /files/ or /demos/ to download.codenameone.com. Those paths are served, so the model was missing a whole class of route and had banked a real one -- /files/iOS_UI-Kit.psd -- as broken. The destination is off-site, which puts it in the same bucket as every other off-site redirect: reachable, not verifiable from this repository. The rules are appended AFTER the _redirects rules because the function is a fallback and the first matching rule wins, mirroring how the host evaluates. The baseline shrinks 37 -> 36, and a new /files/ link is now accepted rather than failing CI. The second is a real limit of the PDF surrogate, and one the command line cannot remove. Setting backend-pdf makes ifndef::backend-pdf[] content disappear and ifdef::backend-pdf[] content appear -- verified, and that is the only form this guide uses. It does not undefine backend-html5: the HTML converter sets that itself, after command-line attributes are applied, so even `-a backend-html5!` leaves it defined. Measured both ways. Content guarded on the HTML backend would therefore survive into the surrogate render and could satisfy a PDF-only reference that the real asciidoctor-pdf build leaves dangling. The guide has no such conditional, so rather than model a construct that is not there -- or drive asciidoctor-pdf and try to read anchors back out of a PDF -- the checker refuses one if it appears, naming the alternative the rest of the guide already uses. Probed: planting an ifdef::backend-html5[] block aborts the check with that message. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 18 +++++++++++ scripts/developer-guide/check-guide-xrefs.py | 32 +++++++++++++++++++ .../developer-guide/guide-links-baseline.txt | 1 - 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index b6175c5eb5e..16b2d74f907 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -216,6 +216,24 @@ def site_paths(repo_root: Path) -> tuple[set[str], list, set[str]]: # sits in this file, so trusting destinations would accept a guide # link to a page that no longer exists. + # Cloudflare Pages Functions serve a fallback the redirect table does not + # mention: docs/website/functions/[[path]].js runs only after context.next() + # has already 404ed, and then sends anything under /files/ or /demos/ to + # download.codenameone.com. Those paths are therefore served, and this was + # recording a real one -- /files/iOS_UI-Kit.psd -- as a broken link. The + # destination is off-site, so it lands in the same bucket as every other + # off-site redirect: reachable, and not verifiable from this repository. + # Appended AFTER the _redirects rules because the function is a fallback and + # the first matching rule wins, mirroring the order the host evaluates. + for prefix in ("files", "demos"): + patterns.append( + ( + re.compile(rf"^/{prefix}(/.*)?$"), + [], + "https://download.codenameone.com/", + ) + ) + # Hugo's published route is the section path plus the page's slug, which # 1055 of the content pages override; deriving it from the filename instead # both invents routes that are never generated and rejects real ones. diff --git a/scripts/developer-guide/check-guide-xrefs.py b/scripts/developer-guide/check-guide-xrefs.py index 8bea98a472d..fe260fb9be7 100755 --- a/scripts/developer-guide/check-guide-xrefs.py +++ b/scripts/developer-guide/check-guide-xrefs.py @@ -48,6 +48,37 @@ # checked SEPARATELY, never pooled: an anchor that exists only in the HTML branch # must not be allowed to satisfy a reference made in the PDF branch. BACKENDS = (("html", ()), ("pdf", ("backend-pdf",))) +# The surrogate has one blind spot, and it cannot be closed from the command line. +# Setting backend-pdf makes `ifndef::backend-pdf[]` content disappear and +# `ifdef::backend-pdf[]` content appear, which is exactly right -- verified -- and +# is the only form this guide uses. It does NOT undefine `backend-html5`: the HTML +# converter sets that itself, after command-line attributes are applied, so even +# `-a backend-html5!` leaves it defined (measured). Content guarded by +# `ifdef::backend-html5[]` would therefore survive into the surrogate PDF render +# and could satisfy a PDF-only reference that the real asciidoctor-pdf build +# leaves dangling. The guide has no such conditional, so rather than model a +# construct that is not there -- or shell out to asciidoctor-pdf and try to read +# anchors back out of a PDF -- notice if one appears. +UNMODELLED_CONDITIONAL_RE = re.compile( + r"^\s*if(n?def|eval)::.*\b(backend-html5|basebackend-html)\b" +) + + +def reject_unmodelled_conditionals(guide_dir: Path) -> None: + for path in sorted(guide_dir.rglob("*")): + if path.suffix not in {".adoc", ".asciidoc"} or not path.is_file(): + continue + for number, line in enumerate(path.read_text(encoding="utf-8").split("\n"), 1): + if UNMODELLED_CONDITIONAL_RE.match(line): + raise SystemExit( + f"{path.name}:{number}: this file guards content on the HTML " + f"backend attribute. The PDF render here is an HTML render with " + f"backend-pdf set, and the converter re-defines backend-html5 " + f"afterwards, so that content cannot be excluded and a PDF-only " + f"reference into it would pass unchecked. Guard on backend-pdf " + f"(ifndef::backend-pdf[]) as the rest of the guide does, or teach " + f"this script to drive asciidoctor-pdf." + ) def render(root: Path, attributes: tuple[str, ...] = ()) -> str: @@ -83,6 +114,7 @@ def main() -> int: args = parser.parse_args() guide_dir = args.guide_dir.resolve() + reject_unmodelled_conditionals(guide_dir) root = guide_dir / "developer-guide.asciidoc" dangling: dict[str, int] = defaultdict(int) raw_id_links: dict[str, int] = defaultdict(int) diff --git a/scripts/developer-guide/guide-links-baseline.txt b/scripts/developer-guide/guide-links-baseline.txt index c2d739300eb..990e6d1c4d0 100644 --- a/scripts/developer-guide/guide-links-baseline.txt +++ b/scripts/developer-guide/guide-links-baseline.txt @@ -6,7 +6,6 @@ About-This-Guide.asciidoc http://github.com/chen-fishbein/ About-This-Guide.asciidoc http://github.com/shannah/ Advanced-Theming.asciidoc http://freebiesbug.com/psd-freebies/iphone-6-ui-kit/ -Advanced-Theming.asciidoc https://www.codenameone.com/files/iOS_UI-Kit.psd Advanced-Topics-Under-The-Hood.asciidoc http://developer.android.com/reference/android/content/Context.html Advanced-Topics-Under-The-Hood.asciidoc http://developer.freshdesk.com/mobihelp/android/api/reference/com/freshdesk/mobihelp/Mobihelp.html Advanced-Topics-Under-The-Hood.asciidoc http://developer.freshdesk.com/mobihelp/android/api/reference/com/freshdesk/mobihelp/Mobihelp.html From 9d351ff8ef7b38fcec6432ff1a3ccca69087b94e Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 18:02:05 +0300 Subject: [PATCH 13/51] A five-dash block is still a literal block, and both scanners read inside one Both scanners matched a delimiter of exactly four characters, so a block opened with ----- was invisible to them and its contents were scanned as live markup. The guide has 20 such lines -- eight in Desktop-Integration, six in Working-With-iOS, six in appendix_goal_generate_archetype -- every one an ordinary [source] block wrapping an include::. validate-guide-snippets.py already accepted -{4,}; these two had drifted from it. Nothing is misread today, because those includes name .java, .xml and .properties files and the reachability walk skips non-asciidoc targets. The failure mode is still the interesting one though: it is a FALSE POSITIVE generator, not a missed defect. A/B with each construct planted inside a five-dash block: a displayed include::Working-with-UWP.asciidoc[] old reported a swallowed-heading error against markup that only appears on the page as text new clean a displayed "The wrapper looks like this:" followed by blank lines old reported it as a missing code block new clean Both now track the delimiter that opened the block and close on one of the same character AND length, which is what asciidoctor does -- so a four-dash line inside a five-dash block is content rather than the close. The set stays limited to literal blocks: an example (====) or sidebar (****) block contains live markup, so headings and includes inside one are real and must keep counting. Baselines unchanged: 119 included documents, 402 holes. Co-Authored-By: Claude Opus 5 (1M context) --- .../developer-guide/check-guide-structure.py | 34 ++++++++++++++----- .../check-missing-code-blocks.py | 21 +++++++++--- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/scripts/developer-guide/check-guide-structure.py b/scripts/developer-guide/check-guide-structure.py index 68e9694175a..e992d9c9d09 100755 --- a/scripts/developer-guide/check-guide-structure.py +++ b/scripts/developer-guide/check-guide-structure.py @@ -34,7 +34,13 @@ # Literal-content blocks only. The container delimiters -- ==== example, # **** sidebar, ____ quote -- hold ordinary AsciiDoc, so an include or a heading # inside one is real and must not be skipped. -FENCE_RE = re.compile(r"^(----|\.\.\.\.|````|\+\+\+\+)\s*$") +# Literal blocks only -- an example (====) or sidebar (****) block contains live +# markup, so its headings and includes are real. A delimiter may be LONGER than +# four characters, and closes on one of the same character AND length, so a +# four-dash line inside a five-dash block is content rather than the close. +# Matching exactly four left every ----- block's contents live: the guide has 20 +# such lines, all [source] blocks wrapping an include::. +FENCE_RE = re.compile(r"^(-{4,}|\.{4,}|`{4,}|\+{4,})\s*$") # Inline AsciiDoc markup that never survives into the rendered heading text. INLINE_MARKUP_RE = re.compile(r"[`*_#]|\[\[[^\]]*\]\]|\[[^\]]*\]") @@ -45,12 +51,17 @@ def parse_lines(path: Path) -> list[str]: def first_heading(path: Path) -> tuple[int, str] | None: """Return (level, title) of the file's first heading outside a fenced block.""" - in_fence = False + open_fence: str | None = None for line in parse_lines(path): - if FENCE_RE.match(line): - in_fence = not in_fence + fence = FENCE_RE.match(line) + if fence: + token = fence.group(1) + if open_fence is None: + open_fence = token + elif token == open_fence: + open_fence = None continue - if in_fence: + if open_fence is not None: continue match = HEADING_RE.match(line) if match: @@ -91,12 +102,17 @@ def _visit(self, path: Path, attrs_from_parent: str) -> None: return self.reachable[path] = attrs_from_parent lines = parse_lines(path) - in_fence = False + open_fence: str | None = None for index, line in enumerate(lines): - if FENCE_RE.match(line): - in_fence = not in_fence + fence = FENCE_RE.match(line) + if fence: + token = fence.group(1) + if open_fence is None: + open_fence = token + elif token == open_fence: + open_fence = None continue - if in_fence: + if open_fence is not None: continue match = INCLUDE_RE.match(line) if not match: diff --git a/scripts/developer-guide/check-missing-code-blocks.py b/scripts/developer-guide/check-missing-code-blocks.py index 062f478eba1..e15a1b7b189 100755 --- a/scripts/developer-guide/check-missing-code-blocks.py +++ b/scripts/developer-guide/check-missing-code-blocks.py @@ -35,7 +35,13 @@ # and validate-guide-snippets.py requires every listing to be [source,LANG] with a # bare include:: inside ---- delimiters, so a three-backtick block would fail that # gate before reaching this one. Add it here if that convention ever changes. -FENCE_RE = re.compile(r"^(----|\.\.\.\.|````|\+\+\+\+)\s*$") +# Literal blocks only -- an example (====) or sidebar (****) block contains live +# markup, so its headings and includes are real. A delimiter may be LONGER than +# four characters, and closes on one of the same character AND length, so a +# four-dash line inside a five-dash block is content rather than the close. +# Matching exactly four left every ----- block's contents live: the guide has 20 +# such lines, all [source] blocks wrapping an include::. +FENCE_RE = re.compile(r"^(-{4,}|\.{4,}|`{4,}|\+{4,})\s*$") # Lines that end in a colon without promising a listing: headings, attributes, # comments, block titles, list markers, table cells and block delimiters. NON_PROSE_PREFIX = ("//", "|", "=", ".", ":", "*", "-", "+", "[", "<") @@ -65,13 +71,18 @@ def normalize(line: str) -> str: def scan(path: Path) -> list[tuple[int, str]]: lines = path.read_text(encoding="utf-8").split("\n") - in_fence = False + open_fence: str | None = None findings = [] for index, line in enumerate(lines): - if FENCE_RE.match(line): - in_fence = not in_fence + fence = FENCE_RE.match(line) + if fence: + token = fence.group(1) + if open_fence is None: + open_fence = token + elif token == open_fence: + open_fence = None continue - if in_fence: + if open_fence is not None: continue stripped = line.rstrip() if not stripped.endswith(":"): From 425e7495a9b87ffa5be32d9b8b8cb76d0415023b Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 18:21:10 +0300 Subject: [PATCH 14/51] Guide figures render with a bundled font instead of the host's (#5668) * Guide figures render with a bundled font instead of the host's None of the 24 generated figures could be reproduced outside CI. Running the generator on a Mac reproduces 0 of 24 byte-for-byte, with 3-20% of pixels differing. Two consecutive local runs are byte-identical, so the generator is deterministic on one host; the variable is the font. `PreAdvancedThemingScreenshots` styled with `Font.createSystemFont`, which resolves through `JavaSEPort.fontFaceSystem` -- "Arial" on macOS and Linux alike. Arial exists on a developer's Mac and not on a stock CI runner, so AWT silently substitutes and every glyph changes. The differences are exactly that: for `flow-layout.png` every differing pixel sits in y 10-130, the title and label rows, while the colored blocks below match to the pixel. So the byte-exact gate has only ever been green because CI both generates and verifies. A developer regenerating locally could not match it, and at the scale the guide's remaining ~260 app screenshots would need, that is untenable. The figures now load `native:MainRegular`, which `JavaSEPort.loadTrueTypeFont` reads from `/com/codename1/impl/javase/Roboto-Medium.ttf` on the classpath rather than from an installed-font lookup. This is also what the project's font rule requires everywhere: never `createSystemFont`, always the `native:` scheme. A null return refuses loudly rather than falling back to a host font, because a silent fallback would restore the exact non-determinism this removes. The committed baselines are regenerated from a Mac. CI byte-compares them on Linux, so the check either passes -- proving host independence rather than asserting it -- or fails and says so immediately. Composition, dimensions and colours are unchanged; only the typeface moves. Co-Authored-By: Claude Opus 5 (1M context) * Pin the font on every component, not just the ones that get block colours CI reported one stale figure out of 24: `guibuilder-2-insets-3.png`, the only one containing a `TextField`. The other 23 matched Linux byte for byte, so the bundled-font change worked -- it just did not reach far enough. `applyBlockStyleToContent` styled `Label` and `Button`. Everything else kept the theme's default font, which resolves through the host, so the text field and its hint were still host-dependent. Enumerating the types that carry text would have left the next one added broken the same way, so the walk now pins the face on every component it visits, plus the hint label, which is painted by a `Label` that is not in the component tree and so is never reached by the walk. The first attempt used `BLOCK_FONT` for this and regressed the figure: at 29px against the theme default's 13px the field grew and squeezed "Submit" down to a clipped sliver. `FIELD_FONT` is sized to reproduce the original height, so the composition is unchanged and only the typeface moves. Verified locally by rendering twice, once with `JavaSEPort.setFontFaces` pointed at a family that does not exist -- which is what a machine without Arial looks like to the port. All 24 come out byte-identical, so nothing in these figures reads an installed font any more. Co-Authored-By: Claude Opus 5 (1M context) * Publish what the runner actually rendered when a screenshot fails "Committed screenshot is stale: " names the file and nothing else, so there is no way to tell a real regression from an environment difference without adding a debugging round trip to CI. The generated directory is now uploaded as an artifact when the step fails. Needed immediately: one figure still differs between a Mac and the runner after the font fix, and host fonts, JDK version and working directory have each been ruled out locally. Co-Authored-By: Claude Opus 5 (1M context) * Pin MigLayout's platform, and stop demanding byte equality of a glyph edge The artifact step paid for itself immediately. Downloading what the runner rendered showed two figures differing, not the one the gate reported -- it exits on the first mismatch -- and the two had nothing in common. `mig-layout.png` differed by 12.8% of its pixels, a real layout shift. MigLayout takes its default gaps from `PlatformDefaults`, which reads `System.getProperty("os.name")` and answers MAC_OSX, GNOME or WINDOWS_XP, each with different spacing. The figure was rendering with macOS gaps on a Mac and GNOME gaps on the runner. Pinning the platform fixes it: with the pin, 23 of the 24 figures now match the runner's own output byte for byte. `layered-layout.png` differed by 173 pixels, 0.113%, inside a 25x25 box. That one is not fixable. Measured against the runner's bytes, the material glyph lands at exactly the same size and the same origin -- a 55x49 bounding box -- and differs only in antialiased edge coverage, 946 fully-white pixels against 916. Java2D rasterizes the same glyph, from the same bundled font, at the same size, slightly differently on the two platforms. Demanding byte equality there would mean deleting legitimate content from the figure or carrying a permanently red check. So the comparison moves from `cmp -s` to a comparer that still requires byte equality by default and accepts a bounded difference only where a figure carries a `.tolerance` sidecar explaining itself, in the same key=value shape the CN1SS suites already use. The area bound does the work: a per-pixel delta that large is meaningless on its own, since a glyph edge flips between white and the block behind it, but a regression that changed the icon would move far more than 0.3% of the image. Verified by running the comparer with the runner's own output against the committed figures -- which is exactly what CI will do -- and by four probes: an untoleranced figure that differs fails, the toleranced figure fails when changed beyond its budget, a missing figure fails the count, and a clean run passes. Co-Authored-By: Claude Opus 5 (1M context) * Guard the iOS font branch, and stop the comparator gating itself out Two review findings on this PR. The first says `native:MainRegular` does not give host-independent output, because `loadTrueTypeFont` resolves native fonts to the first installed SF or Helvetica family before reaching the bundled Roboto. The branch is real, but it is reached only when `isIOS` is set, which `loadSkinFile` does for a skin whose systemFontFamily contains "helvetica" -- and this generator never loads a skin. The measurement agrees: figures rendered on a Mac match the Linux runner byte for byte, which could not happen if one side were resolving Helvetica Neue and the other Roboto. So the conclusion does not hold today, but the risk is real for tomorrow: a change that loads a skin here would put host fonts back into the output with no other symptom. The generator now refuses to run under an iOS platform, and says why, rather than leaving that to a comment nobody reads. The second finding is straightforwardly right and is the more serious of the two. `on.pull_request.paths` triggers on `scripts/developer-guide/**`, but the `Determine changed components` filter named only two scripts, so a pull request touching any other script here started the workflow with `docs` false and skipped the steps that script governs. A change to compare-screenshots.py could have merged without the screenshot check ever running it -- a gate that skips itself. The filter now covers the whole directory, which also removes the two-copies-drift the surrounding comment already warns about. Verified the guard changes no output: all 24 figures are unchanged, and the comparer still passes against the runner's own bytes. Co-Authored-By: Claude Opus 5 (1M context) * Count every changed pixel toward the area budget, not just the loud ones The comparator incremented its mismatch counter only for pixels whose channel delta EXCEEDED maxChannelDelta, which is what the CN1SS comparator does. With a sidecar written the way this one was -- a large delta bound paired with a small area bound -- that leaves an unbounded hole, and review gave the exploit in the figures' own palette: recolouring the green #06a806 to #a608a6 moves every channel by exactly 160, so with maxChannelDelta=160 not one pixel is counted and a dramatically different image reports zero mismatches. Reproduced it before fixing: the recolour changes 4191 pixels, 2.73% of the image, at a worst delta of exactly 160 -- and passed. The two bounds are now independent. maxMismatchPercent limits how much of the image may change at all, counting every differing pixel; maxChannelDelta caps how far any single pixel may move. The measured legitimate noise -- 173 pixels, 0.113%, worst delta 141 -- still passes, the recolour now fails on area, and a five-pixel solid overwrite fails on delta. Co-Authored-By: Claude Opus 5 (1M context) * Correct the sidecar's rationale to match how the bounds now work The previous commit changed the comparator so every differing pixel counts toward the area budget and the channel delta is a separate ceiling. The sidecar still explained the old behaviour -- that the area bound did the work and the delta was meaningless on its own -- which is now wrong in a file whose whole purpose is to justify the numbers beside it. Co-Authored-By: Claude Opus 5 (1M context) * Compare figures in RGBA, because they have an alpha channel The comparator converted both images to RGB before counting differences. The committed figures are genuine RGBA PNGs -- four channels, currently opaque everywhere -- so that dropped a real channel, and any change confined to alpha was invisible to the tolerance path. A regression that turned the whole figure transparent while leaving every colour channel intact reported zero changed pixels and passed. Byte equality, which every figure without a sidecar is still held to, always caught this. Only a figure carrying a sidecar could reach the weakened path, so today the exposure was one image -- but that image is exactly the one whose comparison is relaxed. Verified: making layered-layout.png fully transparent with its RGB channels untouched now reports 100% of pixels changed, the real runner output still passes, and the recolour and untoleranced-difference probes still fail as they did. Co-Authored-By: Claude Opus 5 (1M context) --------- Co-authored-by: Claude Opus 5 (1M context) --- .github/workflows/developer-guide-docs.yml | 46 +++--- .../PreAdvancedThemingScreenshots.java | 97 +++++++++++- .../developer-guide/img/border-layout-RTL.png | Bin 10475 -> 10375 bytes .../img/border-layout-center.png | Bin 10451 -> 10416 bytes docs/developer-guide/img/border-layout.png | Bin 10547 -> 10515 bytes .../img/box-layout-x-no-grow.png | Bin 8072 -> 7969 bytes docs/developer-guide/img/box-layout-x.png | Bin 11498 -> 11348 bytes docs/developer-guide/img/box-layout-y.png | Bin 9115 -> 9209 bytes .../img/flow-layout-center-middle.png | Bin 8561 -> 8650 bytes .../img/flow-layout-center.png | Bin 8562 -> 8650 bytes .../developer-guide/img/flow-layout-right.png | Bin 8621 -> 8714 bytes docs/developer-guide/img/flow-layout.png | Bin 8393 -> 8416 bytes docs/developer-guide/img/grid-layout-2x2.png | Bin 10759 -> 10897 bytes docs/developer-guide/img/grid-layout-2x4.png | Bin 10345 -> 10597 bytes .../img/grid-layout-autofit-landscape.png | Bin 10033 -> 10153 bytes .../img/grid-layout-autofit-portrait.png | Bin 10691 -> 11441 bytes docs/developer-guide/img/gridbag-layout.png | Bin 10810 -> 10780 bytes docs/developer-guide/img/group-layout.png | Bin 11908 -> 11976 bytes .../img/guibuilder-2-insets-1.png | Bin 6196 -> 6070 bytes .../img/guibuilder-2-insets-2.png | Bin 6057 -> 5955 bytes .../img/guibuilder-2-insets-3.png | Bin 7263 -> 7092 bytes docs/developer-guide/img/layered-layout.png | Bin 6849 -> 6627 bytes .../img/layered-layout.tolerance | 15 ++ docs/developer-guide/img/mig-layout.png | Bin 10475 -> 10699 bytes docs/developer-guide/img/table-layout-2x2.png | Bin 9313 -> 9460 bytes .../img/table-layout-constraints.png | Bin 13418 -> 13573 bytes .../img/table-layout-enclose.png | Bin 9718 -> 10008 bytes .../developer-guide/compare-screenshots.py | 138 ++++++++++++++++++ 28 files changed, 273 insertions(+), 23 deletions(-) create mode 100644 docs/developer-guide/img/layered-layout.tolerance create mode 100755 scripts/developer-guide/compare-screenshots.py diff --git a/.github/workflows/developer-guide-docs.yml b/.github/workflows/developer-guide-docs.yml index 7393eaee936..e4a0423550c 100644 --- a/.github/workflows/developer-guide-docs.yml +++ b/.github/workflows/developer-guide-docs.yml @@ -50,8 +50,13 @@ jobs: docs: - 'docs/developer-guide/**' - 'docs/demos/common/src/main/snippets/**' - - 'scripts/developer-guide/migrate-inline-guide-snippets.py' - - 'scripts/developer-guide/validate-guide-snippets.py' + # The whole directory, not two named files. on.pull_request.paths + # already triggers on scripts/developer-guide/**, so a change to any + # other script here started the workflow while leaving this filter + # false -- which skipped the very steps that script governs. A + # change to compare-screenshots.py could have merged without the + # screenshot check ever running it. + - 'scripts/developer-guide/**' - '.github/workflows/developer-guide-docs.yml' # Triggering the workflow is not enough on its own: the HTML and PDF # build and the steps beside it are gated on this filter, so the @@ -122,6 +127,7 @@ jobs: run: | set -euo pipefail GENERATED_DIR="$RUNNER_TEMP/pre-advanced-theming-screenshots" + echo "GUIDE_GENERATED_SCREENSHOTS=$GENERATED_DIR" >> "$GITHUB_ENV" rm -rf "$GENERATED_DIR" mkdir -p "$GENERATED_DIR" xvfb-run -a mvn -B -ntp \ @@ -131,23 +137,25 @@ jobs: -P guide-screenshot-generator \ -Dguide.screenshot.output="$GENERATED_DIR" \ verify - COUNT="$(find "$GENERATED_DIR" -maxdepth 1 -type f -name '*.png' | wc -l | tr -d ' ')" - if [ "$COUNT" != "24" ]; then - echo "::error::Expected 24 generated pre-Advanced Theming screenshots, found $COUNT" - exit 1 - fi - for generated in "$GENERATED_DIR"/*.png; do - name="$(basename "$generated")" - committed="docs/developer-guide/img/$name" - if [ ! -f "$committed" ]; then - echo "::error::Generated screenshot has no committed counterpart: $name" - exit 1 - fi - if ! cmp -s "$generated" "$committed"; then - echo "::error::Committed screenshot is stale: $name" - exit 1 - fi - done + pip install --user --quiet Pillow + # Byte equality is still the rule; a figure only gets a bounded + # difference if it carries a .tolerance sidecar saying why. + python3 scripts/developer-guide/compare-screenshots.py \ + --generated "$GENERATED_DIR" \ + --committed docs/developer-guide/img \ + --expected-count 24 + + # When the byte compare fails, the message names the file but not what it + # actually rendered, which leaves no way to tell a real regression from an + # environment difference. Publishing what this runner produced makes the + # two distinguishable without adding a debugging round trip to CI. + - name: Upload generated screenshots when they do not match + if: failure() && env.GUIDE_GENERATED_SCREENSHOTS != '' + uses: actions/upload-artifact@v7 + with: + name: guide-generated-screenshots + path: ${{ env.GUIDE_GENERATED_SCREENSHOTS }} + if-no-files-found: warn - name: Verify developer guide images are referenced if: github.event_name != 'pull_request' || steps.changes.outputs.docs == 'true' || steps.changes.outputs.demos == 'true' || steps.changes.outputs.workflow == 'true' diff --git a/docs/demos/common/src/main/java/com/codenameone/developerguide/screenshots/PreAdvancedThemingScreenshots.java b/docs/demos/common/src/main/java/com/codenameone/developerguide/screenshots/PreAdvancedThemingScreenshots.java index b168677eabf..effa4dc28ae 100644 --- a/docs/demos/common/src/main/java/com/codenameone/developerguide/screenshots/PreAdvancedThemingScreenshots.java +++ b/docs/demos/common/src/main/java/com/codenameone/developerguide/screenshots/PreAdvancedThemingScreenshots.java @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ package com.codenameone.developerguide.screenshots; import com.codename1.components.SpanLabel; @@ -5,6 +27,7 @@ import com.codename1.ui.Button; import com.codename1.ui.Component; import com.codename1.ui.Container; +import com.codename1.ui.Display; import com.codename1.ui.CN; import com.codename1.ui.FontImage; import com.codename1.ui.Font; @@ -12,6 +35,7 @@ import com.codename1.ui.Graphics; import com.codename1.ui.Image; import com.codename1.ui.Label; +import com.codename1.ui.TextArea; import com.codename1.ui.TextField; import com.codename1.ui.layouts.BorderLayout; import com.codename1.ui.layouts.BoxLayout; @@ -40,10 +64,33 @@ public final class PreAdvancedThemingScreenshots { private static final int BLUE = 0x0b57d0; private static final int GREEN = 0x06a806; private static final int WHITE = 0xffffff; - private static final Font TITLE_FONT = Font.createSystemFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_LARGE) - .derive(35, Font.STYLE_PLAIN); - private static final Font BLOCK_FONT = Font.createSystemFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_LARGE) - .derive(24, Font.STYLE_PLAIN); + private static final Font TITLE_FONT = screenshotFont(35); + private static final Font BLOCK_FONT = screenshotFont(24); + /// Sized to match the height the theme's own default font had (13px), so + /// pinning the face on components the block styling does not touch keeps + /// their layout exactly where it was. + private static final Font FIELD_FONT = screenshotFont(11); + + /// Loads a figure font from the port's bundled Roboto rather than from the host. + /// + /// `Font.createSystemFont` resolves through `JavaSEPort.fontFaceSystem`, which is + /// "Arial" on macOS and Linux alike. Arial exists on a developer's Mac and not on a + /// stock CI runner, so AWT silently substitutes a different face and every glyph in + /// every figure changes -- which is why none of these screenshots could be + /// regenerated outside CI and byte-compared against what was committed. The + /// `native:` scheme reads `/com/codename1/impl/javase/Roboto-*.ttf` off the + /// classpath, so the result does not depend on what the machine happens to have + /// installed. It is also what this project's font rule requires everywhere. + private static Font screenshotFont(int pixelSize) { + Font font = Font.createTrueTypeFont("native:MainRegular", "native:MainRegular"); + if (font == null) { + // Falling back to a host font would quietly restore the very + // non-determinism this exists to remove, so refuse instead. + throw new IllegalStateException( + "the native font scheme is unavailable, so figures would render with a host font"); + } + return font.derive(pixelSize, Font.STYLE_PLAIN); + } private PreAdvancedThemingScreenshots() { } @@ -53,6 +100,32 @@ public interface ScreenshotSink { } public static void generate(ScreenshotSink sink) throws IOException { + // JavaSEPort.loadTrueTypeFont has an earlier branch for native: fonts: + // when isIOS is set -- which loadSkinFile does for any skin whose + // systemFontFamily contains "helvetica" -- it resolves to the first + // INSTALLED SF or Helvetica family and never reaches the bundled Roboto. + // This generator never loads a skin, so that branch is not taken, and the + // measurement agrees: figures rendered on a Mac match the Linux runner + // byte for byte, which could not happen if one side were using Helvetica + // Neue. Guard it anyway, because a future change that loads a skin here + // would put the host's fonts back into the output without any other + // symptom. + String platform = Display.getInstance().getPlatformName(); + if ("ios".equals(platform)) { + throw new IllegalStateException( + "an iOS skin is active, so native: fonts would resolve to installed " + + "system faces instead of the bundled ones and these figures would " + + "stop being reproducible off this machine"); + } + + // MigLayout picks its default gaps from PlatformDefaults, which reads + // System.getProperty("os.name") and returns MAC_OSX, GNOME or WINDOWS_XP. + // The gaps differ per platform, so mig-layout.png came out with macOS + // spacing on a Mac and GNOME spacing on the Linux runner -- a 12.8% pixel + // difference that has nothing to do with fonts. Pin it so the figure shows + // the same thing wherever it is generated. + com.codename1.ui.layouts.mig.PlatformDefaults.setPlatform( + com.codename1.ui.layouts.mig.PlatformDefaults.GNOME); write(sink, "flow-layout.png", flow("Flow Layout", Component.LEFT, Component.TOP), PORTRAIT_WIDTH, PORTRAIT_HEIGHT); write(sink, "flow-layout-center.png", flow("Flow Layout", Component.CENTER, Component.TOP), PORTRAIT_WIDTH, PORTRAIT_HEIGHT); write(sink, "flow-layout-right.png", flow("Flow Layout", Component.RIGHT, Component.TOP), PORTRAIT_WIDTH, PORTRAIT_HEIGHT); @@ -328,6 +401,22 @@ private static void applyScreenshotStyle(Form form) { private static void applyBlockStyleToContent(Container container) { for (int i = 0; i < container.getComponentCount(); i++) { Component component = container.getComponentAt(i); + // Pin the font on EVERY component rather than on the types that also + // get block colours. Anything left on the theme's default font + // resolves through the host, and that is what made + // guibuilder-2-insets-3.png -- the only figure containing a + // TextField -- differ between a Mac and CI while the other 23 + // matched byte for byte. Enumerating the types that carry text + // would leave the next one to be added broken in the same way. + component.getAllStyles().setFont(FIELD_FONT); + if (component instanceof TextArea) { + // The hint is painted by a Label that is not in the component + // tree, so the walk above never reaches it. + Label hint = ((TextArea) component).getHintLabel(); + if (hint != null) { + hint.getAllStyles().setFont(FIELD_FONT); + } + } if (component instanceof Label || component instanceof Button) { styleBlock(component); } diff --git a/docs/developer-guide/img/border-layout-RTL.png b/docs/developer-guide/img/border-layout-RTL.png index 95e79675f1fa51b1e97f03a66042de73aa6fd3e1..edf98faecdae43b8bc6bd1af7b4546d191561d68 100644 GIT binary patch literal 10375 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 Ycgs29lWRLK7z+J)$>w6|1+NGH3rZ-On*aa+ literal 10475 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 LMmOGTJ3ahAIDn4X literal 10451 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 diff --git a/docs/developer-guide/img/border-layout.png b/docs/developer-guide/img/border-layout.png index b88ae54439085b61d3bd991e2b32169282391e2d..b31ed1a2f835db450add8c2fd25af92a44d5bd2e 100644 GIT binary patch literal 10515 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 BZHfQ@ literal 10547 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 T?x7jKzM1rN4Ik9rcX<9kNrm9{ literal 8072 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

W^lmSe8OmCNErJk@B3 za9exz0}&^d`6t?2e?!MS0L75r8QVW!r63&pHcVUOe+zgXIR=1+ZAV9*=ypSGS2y_C zUcPcYn)^#rf93VA+QKd8K82UI?NxX>!Bvm%o9sHqk9XZlA2`mZ&%Z5HHoI*?vZ<2I zz}Yl~O`qIM9h+%!vr^bBp8kInhIQtLcVGWL^*rFC-CS3r)ml&r{mazL$2R_91{^;c LdZgj&b65WZR2-yt diff --git a/docs/developer-guide/img/box-layout-y.png b/docs/developer-guide/img/box-layout-y.png index 6c5aa6e082b09406fc956eb7f4c75aed7b17fb2d..aff6e8fa8ba46f7cf2bb6c3cfda1ef567621416d 100644 GIT binary patch literal 9209 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 OpmkSIqxkldm;VpSiWs8+ literal 9115 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 diff --git a/docs/developer-guide/img/flow-layout-center-middle.png b/docs/developer-guide/img/flow-layout-center-middle.png index f67dfa2281b75936119d1ba830abfc1976afc444..291aff0a991f36dc5eb80c2a86182319af8cd5e2 100644 GIT binary patch literal 8650 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 literal 8561 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 I!`qMl16(gyb^rhX diff --git a/docs/developer-guide/img/flow-layout-center.png b/docs/developer-guide/img/flow-layout-center.png index abb0f26a28aee8e35f07ffb89893d2d48944449e..1f1e88ca09554ead7958af632b637e8e1990abf8 100644 GIT binary patch literal 8650 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 literal 8562 zcmeHtX;>0?yS~{mE61G5vRpIGB~vmp2NNyJ)N(0Hb7ykP-PBwFMQgNjB_-EXrrgH8 z+zdtn_aaL654f%|M{|a5C5Ctv#?QuX#>V|z_eyA=qSuvOhm3ok2v=r5 zmsg6z0^Lf4E*h`iShYqtND###b#cPUzi$<9mEtR(&OgCA81K5)&mLqCxsSAm4(&|C z>XlT)ZX#^W@2}RV#?O~*v~PKvs=Z63E^{`D)=2g6ZF$;W5qs@?Tw8%;!OIbesY1C| zLK-D?TcgPL-vdbg`r*#llu@4Hq|3umgVC5CUp*LA1r48RRHo0Xf*omaCLR)q8p0Qk zuzH-aWt-Wiu3TSV(tOjB*GOBFULO2o<*)&&hP&7>jy)cLc!mF{QiRt}kHL5+vT461 zk=7FY$myS)NOM&a%`$JyX-8+IMKXRVBm-GD%yyrL#tQP#nP?3VQ80v zD4?R3ZRvDyAs96wdPaP+sU7uH%et45X0yKH5Bmw^dO;CncghsZ%9YXfacSYq<)EWN zr;QHKB_5%F{ou7#eK<*MXkHGF=7}y;8ueK9u2Yj&8?4O`v&G()$Dsk%Kk9W% zCr$Js(rh1;ey!%VvzLd%%7Rfo481+D@p~(^y=4$XqGg4`k^HFJ+%z|TV`$~|?sTPg z?4cL$k$*7~Q1cRl2z(gYG?`k>8OOql#-nRnr|y< zPv`0EqfOSl$ixZuaByHvBLP+8JyC*?wrURcYKf-t$om4>n{w_><8Z=kKqee3fzo^1 z2yZV52&6p;Xy8S!NvM|2eKhm{yE#qpkof-4ZvJe_uM(zUgeKjU$GrTd1DMFfrH%ac zKy>4|2{ertvp(pvvItKa2gQUaXK#huPwqhJnf8eLp8cP78+7#ynt##NqV{|P=9HIZ zkF1!sL#*cl$Ae~#U=bv~ywBJuOnIxL*R+Mo2cP9V?7OOWZ*!@E#n6F20~fq~bwO)> zhiTY{i?#}gTGQ}LXIM_gNA%t3l^{x`=Cms6x}Fk@X*bw)#xVF^Gd7I74m&&{$C<-f zf_|@}fTzB8wkZd+4%__>waVTN$iBmVYRXO9UXV~Jo_qLV%kdDOEeQ^Xb@0Y&@Afd^ zwVS2*s8-n0^0+L}0bqI`n%al&Ls3R>u13D>zSRld&r{pp9L>zUrJ*HusPDLrJ@d1 zSiS9f!x(x7pzY^2XaB5Ac-Y#H`c_veRR?2*I#{DjL^<4fz< z<%qfMaebgeHU6pPAG|N{)yACw$t-RI95udMX)$PNMLgB2dii$SmgUMz#* zUl*sx*!96(2kmZ+d8V-q6UH=6FuC)G-O4gCwRJUBZcv zhiC3snjtb$41z*FTH8Wn?lE!EA@x$JF|691fgDnY^BsSe4cq~~QadUWa@-a9YqMjy zrXqDecO%`WVf{lzqw)l0!6Xp2{vNp&5;i%zN9XvY3(o4V5yav~kvuB# zVUw_txGw`TMqF6mv8k2o%i4EaGyP-06L5-xm~~&xV#7UtGEFo&a!1(Ct|;mXl%)Fq z##nxLPY~B>J>znh60y3xH!bw`G))`FE)7Dk+L0R*E|l(>4>9Em4j@t^0Mw?$pImL4 z*zp2VTPZ&5Jp*ctxIdfvXk&hET`w?nUr?sj&TxwL-RPRxZrs+RRb4LoDevd~pp|d3 z<@Y$1vpD%?Eiu5=kj^ou8RCLFHL0+6W!^?is9)%wWC!w!2M1k~pO&itf8iH3;e=b; z7hp|zKS0){)5JNiPYm>vqNu;$XCE6ZrnE$0K z2{T|ypLa(lQkSNwa<#d5=n< zU3Eb9_fyMP!?wlFy85t90};s@pA6}5FIp1U(oy|aQ)9;U|pxxr=h6;;1e&!sL<&=VSUU&T#eOOWws54-2HyPoSDY>K_ll zbh~rd_v3`s$DzK)F#(XY3jB1bTgOOaX9~;ADVx8NKAIkLr{YK1^nI(ldJ9LH9sIR$ zJ3Pi{8-=-LLL{S!tRNCBb5SP65udiBjtwLI?4?MXO#ankW93~7uB_mh7>yn-T|DPzdoz^rbmJr%_1C`#TH((uAvH!Xh}Dh5`U&G z?~;}y0eB1;p_*p&@d8Wyy~F$}{p4Mfc5Bnhu{RBCD$d7|z=BFzGB~Dq=oU2Q5ago< z$}MfGk}b77JV33J*0(4$kA=_R)uvM=*Y(*j%@0~U`!0a{^UxHV zNSj*v2(JWR&f&~%Jb*hne8goW*#-JU{8=_IUT{c9#LTRa@aX|yslZ^6VZ7@Q{TgLU z5gNiQ!J8AsM9c`m7r8A;1*DV8Z9a}fMG!#pgtnY|GY=bntwjbE6zyj2D^JaNC6v%b zNzf@ z+UxX~eQDP_$^AdaI*@H*gK)emWu;ts)v6%eHd^FI!v3$k zp?URo=RsE8#TReJYD)5-jU@6L!8{b*|0bUQY|wFl`HOni%B5Y6H~G&THTcnH2j$e> z9ThzD6GU@v-YxRknE%YDiXZL8jfmfcoYa0ustJyLOCO=qs$?w@c#4>H^q*v%C3(G2 zvc=ZU$S65i(~mT)dz&09vYUkH{7Q&sCLl^ip8M8FSt9NimsdtFMB|H;{5}?S&j^Y- zJT!nGW=0k|>rS6W<7hnTfhDts)%+5CosI2?A+yzeFs;GUW;VFF{bh;J#^$xM=4vJC zg1avitEQT4py*HsnedAEIP63!6^$CFalT9jBH*y5-KbysqdBYK2(%UM6RvTyVc5}z z1}mkmpHr_xoC^)puWhs_H?WFWcq{T*j=C^fPF;VUY_EUPA+(P%U({(fa|hC=3vyNQ z+`Q!#7*X6k`k4=rm4#`Woh3rblbjjWl}l#R3Z#`%ZqEWonUOg!#!PcCfy1hvdF-x|${39B3Jwd%CO?P3Kvygssx8`bmu6DNzGxY)im+K;THTLzlF} zMepeoTfNg$7Br&^x$*$yIriT9%xJAdc~x1B9nACdGc5l-Ln4tI9Tk2to0OA}dsyB5 zHN)3WAtu4{oNdSeGxAnvHECUe&7HnsWRarV&6bY_+blyG{ipuwgRWE#HzPpnZz*|h z2XS-#m!CGDlF3@|(MFbZg_B0bEcCfIm-&U>W zqF(bBEA?HP{Iul~IG*d%)vR7osw{PnvcSlXo}wCZ zDR}Z2F`wq@%ynzQrz@BN%O&0Il7sO-T~q-+enCh}2CQS2=9_Wyqzdx*b6Fo*!|exX z;uW^CseWmSVXx*y{h8w}UW2-{5!zS~k@ANbVKj8Ozt9%}VZJFu)+iOBP_Oy4vFKh_ zx-*CIX8!UDi%Rk`MD?zfsJ}Z2wQRBqlE6RFl3om7th?>&{1<{tq2tzd1*qYv!GEpD`2QJ1uN++0Zy zp=xBQ_^DJCyns~Oz&{sRd^qI}@X?#=0;NLpDLwaz7M-eq%Dk7Dl&31G znrfh}I~Pj-1BnEN*j^;9$T2CG%XAL`RZmf(+?vQ>IU_h_y-e3oHATOyF$QGEUz=Ix zInj}xsH6u~-zasS!Sa8iXSr*UmSR)iH}rJt-q(Yv&kt|V?d((IC}+W1#}-&A@;WN~ zzGNU1T0!nw3K0+*t=yUP9F2#k8Y!r%VxlQ(HYY`-GykaESfUswsD;LzkusOA8snvL zkic5rgBElsD*v`0Gw*>@&nRX}iS1b(@IxuDY18%tL=znp(d(>BEVQK$0?5mPq{qz8 zWpt&zg1`Ji<#h08DVKo7(R5m@Yo|)3KrRzn^PAoMOZ3SL_f5JR2Bd+i>K?r5aL%?v zSMFg(*baW!PlmtrJ#D-cv_lzllz^b~b3;Azb;s4-J&U5OBbsiTq80-SLPBX*afFN3 z#iIhc$n}cyHvjZ!^Fvow1t8B!DMT*sE@PP_01x#i0EL;R5)ji^D7+BZfbYR*ULABW zJ@bv3UV)Q&SXxSFR4yy(!fp|J#ZrVJ$N@0Fubn1Gt|`G^l!o{zQKXc&1C+8-EgHK% zT>-VJabIW^Q^Ln|5L;J4xnR`|J3#g8s-j_%; zZXnxQfYa|n8dtd+hh-WAz0odQ^m8W>W^OiLCWS!W2L_VU{b6q#?X|YlsR_!+lg|~H zbTPbhb|vyw46x0c?sS(Kq;ArDnV0Q13=#hS0sDveHXT5>!>sv0?{AJ`GR z0+PU~LJBBZ00K=Ha3Y~v!mn|a!)yFGQ#yd$o0js z5R=VQYIuf=rHTUnbPX+F@=FgF{d?AM+cS+a3HU~`=ap1@V;|5 z?nj4Q{##N1nvQ+87YNmRY1iCU!`>4?V^1{Y?bv7D@NF?7xoh5j)>Q*{tvcBS$n7q& z@PPNs#0hSP;n(e_$chn(9{35CbQZQ%8RMop&!!NVsiP}|Ge;GGuaW5XkW^EvhaX1) zsNETb&KQpA3SihzIiyH~h?E_un#Ag3wk!g@TKzg*FbGw2GwByrC&kqS7;u8`Kqagu zMbfk9i@Z~#NY<&3XJP7S20`MDvp8?_S&*LdOTK*(EQNoykZq+?K=krv3D^HyOxFM1 z+4XCR>=mkt75c|hctd0W33Ltri?x?c$?QKh7P_$;tmybR<=c3W6|(NRZGumI4`q^2JlYWA);gCBwB>X2bw{^TDVm*kmLB(Om`l(2XQ1ul zZ>8G3IPK>M(vB(p{_u{&;kuPEPom0o`b3e~w) zNuAQ`f@)6txz)m#c0Af(pr*UNXXdos=kDzL)~(~M@=BkLj<5M{b9WN>)`0&@i^NT* z^LAcV8Q)<%Qrs=A0J#|U-CdEJHJ8$r#953mWOXP`ekCIpkO0AAfzz8xPi3h)eblA7 zD%AXifC)-t;FO~b5s9vGe=4`M16Wwi40O(2_S8fcsDb2!HyMfpSCN(1iP3 z^N}9!pq+7Q;Hv1BRkWOmKuP75>W-ra9oW>x`TZaM9=QNVO1xoA`&SQg_7QiIc6(}Y z%hm)aK~|A3!wbh>w!i}yvA26>W_$OEJDl&3TW1~=_-qP4XWiVh%VMIKc2R|uO^7#& zVm4PlP>S(M%)oH5$jKYWDhTZBS_iN<*?xpaB6Z9Nzkv)Lzqiyr7NZ zD2y59)I|-^!zbM30YRx*8;yE?1(OB3_vZ~Smh$_>;RI&qzW~UqhF9NA{#!C8Wwo8) zU~(~0t4tf^qVQQar_Pg|`7MyuWO#lyBwyFmlwV0%t%{e+K;(e^ed54(@o5Mmn#Qt0 zwcvB5%Ljjd;VZbU`q~VAztq%kWbJ8wz5e=bUqRt_VGE{w4IqO5Kdt5S*t)X;qX{{q4xtaf>tp0did0J2rmWnzZBhUFj>Ali@JHJ= z^3F=8be2YYNWA?*#k-Kg`d? z?;h`Js4-o@_fAynz&~w!6ubzUlnC!>b(>rGrkjpR4e6lbANj5P6clDp+w=JhUHu@d z{+X+)-mQp5^_|sjY^SaP*R~R$(DVKvP=vH!_Xo{(jg><>_RiPY{L-Z z*k-b13}z$NFygD!D#a#FO`(4ZLdws9(J@-5_Gr20r ze}o?Z00;L+oLzV6$@wG2M5x(oow^ch~hcq_zlff(B0;1RLp&ne#Z=-4$; zVc@aB95a-@-O;bb>lOUgi|-qct$1Z$8du1<^=q=&eAI1~>V3YVzdk;```R&?p4~}+ z{q84sr5!qW7PnI6hcV6y%3QPaMl|AdsP6gOI!jxdn0X@ZHY{s})`+nk&}nc%skX~K z7M?f*E)x>I^fc8h>alQ5HekPupFYpQOJh%Xk3X&zUXCcS_?%LpnZhAT>mC0KL(SXrY zxVN2?t&rdy+m~SI5C;ck_3@B**YR zcU2!rrdG?TufpChgnygAOMsY1i8xzi14f1Te#^(kr|_17frhwCJk`?tr;QL2%6v9t z`^3y>ULRc%=U1BQxB1I3b;m&he8ccl&8LF=szA!kEbNlR18dv*~(@F_tptN&fi-4`%?!<&}w=fsU z>BVtHh%W9GUpjwxTiOM6&K9+9;j9suq(0s1l%4`ZENBIbrR)!-BJmY3(D&|X2IEyX zaCXU7O*J*#($0^0!EQ#4>~plO)u;(in?t8)WV`Ruoo#s5nc}NeIbFqb&#k;$GK`)V zxJy8dc6+fIA}5vt>)_j%4m?wYj;~b;!sh3Y>3H_!jsj#wro zt~WWhR$x50|EZVZ3; z$L05R9vB!dr^Q>|iL=%+7EqZg63M71sq>c+{&ptcEUSXZP_nC3uE|gnS@^iU(9~-R zL1Q$5SO ztBeqkclxB^YKNFcUFnK*8)Jg11NtP@NNu^p=Yt~r4r_F7%YMtN3Xxm=F7 z@>K>YZGHYSkeGkx(ZINKLr<1d68WXnVf0CLc(cZ#etkD%oVO78>h;dlPV>|m^^ss# zN`*Riv3EIVD+?u-(pPr@Mp}02$?*15mRxM_Zt%7?Y>VNzl9M#aHTC?b4~SnJ;iCVO zU)92V9)L5N8Y?j}cOoWNW~BSsoI9HRB_Y+eHis%~D!ymJb*qJm2EOtF8&J9)nmUk! z;NF}{xxC2-K;UpzK4Q3zc7tdB_tsCkOR-q<5f2gKb18{sSGF{dN6+)^?9~rYU{Aca z5RlPdDp*IaC;xpkJ2{*1n@I#*pZ)+<7e8|D4$cKZ&()~&sDl0)hkD9heuj*nU{kD4 zs9$9CMp*uvC6Z4nLk1`q}ekH0HeK@obqGLH=3_LbccK3Np7@_IVxnb{*45B z=EXMY4sl6>Z`g<1v%$Fz<-vB#y<{byG(|rrvk;^e-}>amjTLiEUC*r6J70^ovr|Dh zDAtrR(;jrzDZyKIP+9gP9|!EW2t|~8K^RBFu*06g3Ucx-K(E7NW zr|)&L^n$siyrQ1N{sh!(Z_{;RDvK@bWZgC?Afb>e%MK3kWBp8<+kJMTUs0Jo3D!hU zG0M=@l+-jc?;2u9q!!5H4W zq1E4Cu6tGM9R!#>;P)n(WQRZG!B^zv=sKb}I60yk2hzcW=z9Fjoy%A6`OU0fA1m?aYJ@ zIA*}{Y+0*($a`&d! zskv_*RSU)$$gvjAa=d`MXN{(+tkJP1l+Kn4bs~OEbyi0UeI~`h*H=BLH=m)mkUR*> zbVzf2|Dn4Ya=@%l)QvSM{8*p3enyg?I^&J@BQB*QApG~4Pk5i-#9t|?QqW^9G}{n* ztNp8>VouYd2%*Yu#Ck8X)uC_P>g|dHU0FGDV{NXkTw?E(`XZAR!4~@?GY?rem<_%z zF2Vp+ZkII>d2hkbC`H=bYf`|2+qzmbjfhL5dogcR^csZ}ytcIY`D`M0DBrirsDyV= zDn_H&m`%~`RnRtl%EF+q)5*laVnHCrP+eynj0#cMl-z|_5x9dH3UbLy8a$tB&4ytH z17CZm?%#N_vF9q3Z=D|bCr96fwG;`ARGEj91Kq0fS1K8yuUebV5r89BJk^lbi|4sR zr(W%Lz9o+WWB#pQVY&K@!pI@m7n;GWUnJW8DZ{aAxTHPS?}2>oA!aaPC#R|!#H`e( zig?GGr8bI6KAQJd0dQ9Hyzqcb4GZX>p-EOJmel#VvG)WaRI70L{e#kVWnD9uVBu$A z7TRtZNPD7Kv; zUhqv_;I?2j%-H;?pLO5L(MoTj&PD&bLd>mQ;)T;8YbeJX;E?L>r;X1DGov#pS#K>j z@GMMngn_wu$vL5sk}pyS*1Ut6RaAYQRzd4MQ54(>(OT6FJMf*7A{?T+#KD$W~9A=43`j%e&=0C`Ex_1RL?h1k|0?@ z7;t^mfWzK z-`ZGQ^2npS#(Ore$>HQ>GUF+$6}(JNSU4UGged@?U*e_;JDkD&4tdga_@SUlu9UzyYRmi zhCdYK${v`-DL}|Y9^U(LyguUzi!51YIqkw-V2Y&N^!`)LVzjo<=N=t~5Ux?)RF9|H zSq|%_q-F9Zj%y6%u;9e+uDCS^|h& z?oOET=FmJjmUVL`kiLr}Zw$Wv*X#X;4U!T#Ea}NmCov2nDSpTS9C% z=POC0p}9L=tdpCAt?hCywx)*fU7HPtC)NrKzr$ylx4~ZU0$9~ zOgVK$E-}RvQ*EY*T1AgnfT_uRvC3x+6v&_QHAy zbMrTA#$pq+9xlf>Y(2NoV7_yBB}Vp9`r-$apQ|HI^56ef@~AQhqe|C`rVD8=KPcTD zWE1}9t{9ONdLqg1&j*rVbvf@79rn-$yb|9B5s8!oBraI#@v z+8lneAd%R*M>0jb?CS$}Vs%jGtY~hf$1PX&>-92e4PgPde^+?<&by!hc5|=p{rlBp zE%5@C_%aho_`PvY1uoJ`av<=JS%R#}mfD;;ejR2HCBSX(7*ub$cR%?$vnXis{@T!& z&Zi!-iN=n#$3rI@!Ajbx%P+Rbe{4H<2_?#V7v!zvthJZ^mSn%tpPU>+*do_N2K3f? zCzdOA6ri$$+TR~dwO1dn59|R-^Xn}oFk)9#=hp&@n!>x6^EeIcPPB9w)CDxHBE^cE z8jlt#6yLSFG6!N!{HekS(?389LC;kI5{`u5(li~wo0wM9h7*;DRp&r8u=TgC5bEko zC35x4j{-Z1ye<0rkU+gtI2ofIa_y{dZxzj-`XL^5Vo7qD6i7HJ@Qsd_!VPUO+Q8!N z$u$Q;yu z2b1Gp{i`ym>H=(g_18jAs@J1R$l=twuRKlOY2P}6aSvH$UnOPP>FB6<;ZDdaDE2L(K)XS~xG`8o zP#3bodui(3C)51>l(j%45*-v6d+akQD5L=$2Z-GKmUYK%#JP3yk)z}*5S!qsV;7=K zln@WB*dZul;O!^|6A#Mzm>Vb6E48#*Ny4vO*%=Q=1%DnBoAWZn8!E;P_yKIp?_)60 zt1&6#jDu-SF7Qp%f&tFyRl^D!DwbmXMyXlY*IgIE81NBN`@H|#`V%iL5`rlh>QryC ze)Zxd`RZ7b9HAU?b$sk?PMqO`6u|_jH9+%&aFI{zBt7(sLs2>E%c!76+2le2lDBk| zrNt^`uKjE@#4e>Rvr~~Qbd$*)WO|yi`0Twh#@Qf$8ArJ3spbn=VapbE`qv$5_lsW) z6s>lUmST(tN;;J83)K0HakOoj<89286zJ2?>2raFlqT`M{@`cD2qAo#{hRw>_jnjT zoOLY%xxz$0aF#(dB;OD^(b}#+mr1Wc3z)^IZt5v4g|365{S7Fvzz?VQ!5(a4i+qUX z=No%3N!VImB7A}be{J3+fU-Fnhdk=e(vkcK4Qr#MT=&9B+f`1$XnC%Cdu z%=sr~X-M9|aRehw#6kFJM_`b81`RJ05PqS7>y+aCaNYiOJkVx0<+-L@gwJ4wIl*nj zqKf*;fSJkXL0PHte>@;OKJmGEV^?L6N!UbQi>AWVTOuUNlJB%LJBmifTu2q=GQ@v& zxV=6pjcX6IdlrGcDh5i7=XAD4CW53=jly#SwYYQ5b`^pmR;xKU!UD3wmy`0l+n5W{ z6ZOH{9|&&s<6j&P4~A*>B*fX*pmx*0Sf3yb48~WD8@YymQX32YHOC{+?)uvmqzkv$ zpOv*PhWj7e4yV^4P1L5EU(}?7J^;4DNZ&E%wnY`ppB(Mz(;W^btn(6m=4l zNlHCYfBGO9Ew*%bF7}-t`2u{F9-Z}0DMb<$i(yL4Qu?XzAewbjTvpSC4N~6HG%$Gf z(NVagsGWAf3T%`8jl8`G?uRX`=7&9FDlJ4rZ5|=<;T&FKthBS}5mC40blPt2pNH!& zJiF&6aI1yBQE0-i*OY{X?AeSl(oM%?A0+3>BYeKk#(&3$f}VlXorI;R8k(i$bd{%R zWn4a=OBR|N*%Gjxl{XJ$>&evzZCz_1`RgYbbKI?xE$ysD;T=}w-RAP`WHs~E_@oMM z4|FkSV_sn24;b>C$_m|7ox@Le&6c=dl#>W>?ilUOydCu~_NHNZZ?!-j*VbelKHcgp zy5^T2YPa}V9Xss?#9=DmNjwaS%ycN=MgSH~9u+FwKFxx^$H>2JycpqWCGLkg%TSC~ z9FnPjoz44&Z(oG&txrf4fbBkS+P@S(GA-I0=Z85!<{P>(fCENUk5=HVhXQ2`VIpDi z=k4%$sCWAGij{nXh~85y@t&!LuJtxzXx$8z^u1f}m;&|kQ8V%XJNoedSfcXO8hqEs zyT6L@?Q2%%7mlxxD>RHKr`1w+iyS-Rq5C=yV-q|E;oZ3+ef_4BlGdUI58u-(1fi4f zR8l0F8Bx5Kb7^~%2Du^_W}?TFW6pSFIL{R}Ag%!JJGJ%k_!?LJW^(1T*DIED;wD!+ zci@_9;2YiJ{olttHzDP?zTBy5qIWCN1aOk>JcQ2xE9b6|ACN$ZlO3 z;x>kol649uL*jcfJ;i|)=8Jbj?@k*NaO>4uq!bD2&$YUn!&j3GB*ae`t0^0rz?Y}S zRwOTcYj$6G(d$6%sXbq}z7dy%6XJwdU$=nhf6v-BIV3lu_MU41VYXWVGBGJ9Hbg$u zKX^rIm|i>x!pnjDZ!*I5#SX|nSG>_H_`QU8EGOavW?QnO=^XyM_hf}=A(r!*)b)*G z1~&c8k0@8~@Ubrc&Y(j`;||)gY-)UuW4GV^tH0>{ zE&;now;)WaC`HOd__Q(vJ6#?fFqX3UrWaNbxf!e5a~}Rd%A1Y<6Gq!ns<`a6Kpo|frI*ZtgoS~~tUy+XEV&wD7giK9z9N1SZ`z<^Tkc_?7Cbj= zEYRd>siftYY%)_{3SiDRS#N4(s?KNl(D0R!2%Un4e6rnf_W@|S4=IVC4N^oVRlhaT%#5N+Kh=NXA@WKM`|a_SF*HpCD0HoBAW6(_OIHd ziaHZk))+^fi9bw` zFzmMwu)w#s5B7>W8qWpFqQZKuxD(7$GmTonUsm(4Sg^*?hiLWl-W`{!m&P)Is$fH;|8x^& zCvpr>b4m~3XC4I@%K`kCLGsTHe+|@s>hMn;xIaMt6j=Y@;U7HwU*lno!?R>l|IyS) T*qZwv4}hV8$z|jv=ZF6RO%$0L literal 8621 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 diff --git a/docs/developer-guide/img/flow-layout.png b/docs/developer-guide/img/flow-layout.png index 609f84de599c504c9ee0ba9db4362da12446d070..20825fa27fb14227692fa4f0086a97e86b2dff91 100644 GIT binary patch literal 8416 zcmeI2dpy(q|Nl4FLE-Q zvM>=7JtztQ0K`l$U%CbW051rBUv~Z>Sm}+cyaWIo#+hEacq0ftGaO8m^GAL3-tuwU z^SiZ(0Wc@#aetn=hLx0~ZBEZS;X%8nqEA(^H})j&XIdew_duogL?}i)zhH3K{cpt! zLW7?TmLjJ4WY;&YeymNFu5TBZ%{=ewxf(Wt0&7mJ-|MOk?830SLgr&g7FoOZ7(8nw zHd-8x*sYlZ5IN#$2;6JHj1*Fg_#h^Hd8fCm==0s*v?UK8Y4$jN!QdIg3LUY#CI`TH z#ZYjRdK$LWFvrx3c>cf;Sgj(si3E|n{d{V(^xSo5Cy3`d-$S2+qXS@F_5^hui6b^q zLVw=X8MQ!vklMx$c^Dh=-pfZFn+CoiYTstey7At-h}6>`@T1lH1lik1@nP2cPi z9tb+#aM;DOQu222)XOu{qNTG|=!*kVSYiEIrw zhNZ#Szo<~91X`|V8Sz8)>oevkkc^~Ye5+D1r8DV!qNe+0HVrvAtGJKtDGomsv&l`@ zWU&fUwdgJfFs>UT=sfD{v~+A9BH$7ukekr&F(h*}v;G)i=BpHS2U-7UO`H$?Szj97 zb+S>tHn{Q1o79cX#i0QCJmswPxlOzUg-Gdw)%ngV1`lU0mnV>Xpn3u9q`|BjD1lEV zJr(-%8q1h*1^D1-kTfklRdhzvyC_|_*o%wW->|Q0HKb69^^6LOCz?gwT=3Y|{HHeNa`;?$M|p)YZ*wlI zt%>!z9XDj3n;3?;=Sj{C^Zbm6INs0|`768|Fl;Sy(0k9>2lLf1sxnzuZ5d=~F)>t; zgaub?uHOy2Cr=&8#qbooGB9cE5h}uG-cOLAaoMF;qZOK-ZA5rrXD{HE%-Dg zkPFX1YK|l7Z@o(M>MCES!~5CBKwH_L)%7?k9MpX5I#y~bz?nsh#DZUIZu(sGn^50{ zb%YSKhRVTpj9hSe?&kQ@4g_kxYnmQ516z$pc2^)y&p%Ta9pAC6-r3>%ITPQ~MT50D zq=LSS%?$Vs@aK=T=UT!bYWm;7W39fqRGRiZ){A|envWF398zQyAg;b#(yJe59&t9B zX0;$S<)S~b=ar12;Cjar)D1EFu6z_HKlI`HgMaDSxYO~)=m%Mq3z(y#>h=|+AEnbM zyQ_&Q>0%a9PrmAfqx=I5L)@5zjuoJ*Wt>F3I;jLqlskX+mXZnl<*=JF3nGSwOX5OgTC`&XV12}19ClXs0pt~ zJAU$V!$}=VP@=*uE-Nz@Z$UC#sqab*^W7e4yF0GX6mxpz27}4LFis+ns$1DL%EJ(An9MONzA$GFs3{4DgU#29uORJZ(QlqEn<`fp9&jsJAAOp(+?(?r!)`||$s1BS242h1`AlK?Ro;(lYwoR{=*00TTwGb`{^;nG%41%gKfID8kl} zs&=Nks1@}H?Cy9bSaD`!*e{$8H~(N=UwYdd1RJem^(D78KM`hkAH142b*;sjQg>g| zViZyT0`bkiSPu+F&gRUrS*9VSj)({*~%q;bw}JhMvzL1_r>= zn1!18^{Cq2*=jFnj+3e&jIue4G&@p)zqmX&7+=PDfXG!rz#d5S!c9s1!oJx)sIJ#h zHb4q?s$Vnel23uG1udu4lU&`NvQazeZvhO@7MOIoHZ-qJsCQKSPpM&dS!1N@R~tBW z^`!2o$S4QIl#=s2=0{c|=8b#RYacxwV7N8?aic4|bL6j{D{atJ(1O^+<3_Tpq(X`g z6y1i8bdfNh$@M{*lys@*zS^iIvDF5JdfC~JtMR#3=y5@RUh6k5^0Pw^jh!^{r$W}* z)66NwG75jv0ZzSIJoKe8-LGli=28p}%R80h8y0PEPSA*}d|BQSe+L?;xJ8kPsKRhe4b5OR|zpI;^Vs<_Jd!s5;dT4CdVEQ*xyX`UO zQE7HmxL|Z)DavuHUi_B-JRYmSdPupFQarqeCpJJg_bF3}zeLS63VM3(tt@Va*x6jt zZtSIEhGp0+fJ}IUhUG|yp{9*Zbe{Kl_#z|qn{4Kc-d(S|)vGDBq4y;vcn5Tyf$wsbjfRh z;cT9W_Q5)hbgBK>8X*yu<&sqS{NZ`)LXHGr0IwcLrdyq6>$eNi3dF&8JeY>?)uX+j z5>isx*!eJ{;|=b=!rTC=66SDhEB|wE1&uJ(BOh53GC6xfj@w57-IPSuMOv&ef?sm( zCwA9w>GMO~)daR?e+Q^U%}VO=P+l9`3Dp5j-=L0mhnx1Y8$Ztm*Hy_@uz`!p4bxK* z)MEW3$#EDQTu|Kw4p!WTtdH>R#^2vUMr&}p6cF0nxXAchcFX7Cb8`~^3o86KKC+~i@~r?r9t-{c#TJUj z6WPgJr$O&)uoJo#F;CV62~Lqy?rSL@dwZ@RQGkU17cYUXp%o5p=D4-=OHn61igFVn zo3qRyuV|N6Q_6h$V7)1wXCl9G*^_8{LU$w~?xy}Sj2!+)UgUpE?S81MRxMA(7Y9?YSnYKXX3RYw@JSYqG+(if7XLw@MAc2Kh<{FF|~^spE2 z*K4aFNJolHgwOd=yO}|Kg;>Cj`ZMQXEJhL;BO6XJZ*Z1-c zu9Yx9VEvOFWPzDl37e2)eM>X&8t%#x8B(lz7PC?^Y_YKG+7^&pQW(4+N15PJK_da zZ#cR`K?aYLnR30v2=Ita@v@iCVu0Pd@1(he%vF?BA_aN1lguvove#F;Bf6E(994cp z_6z|HL(79r7ZQ%}p0SI|0a2PVnHuxOrlW1~YWS%w!V2?cxm`V}XTk*X(9eNW#XP;0 z=^!$Rgnzi7gE^arS3VzS?$i9`DE2c#nPGojwYq7CLZ-da3AA#GKJ~2c?ahy?-jAZ% z3%}UxHA?YO8K?E#QGKsrh;!11;SrgRr_cro8O%{IJW zw`$~hU#`%5HcLha*M4Ts(3?)I!=m`S^k96gEc>I=+8vSQ$9~UJr)LY#H9ju-b|`yp zLz?U*ow%G3roG{Mw%tnh`Zts7;jd(9BY3ixb)hniB7?FZ#4U+8xr_vj%F^Q9CQ|Yy z7HGzqDH^$AT_x?MhbRa9jY0eOU-631QlqOz+(_tXy6?Q2 z&HmeaJ)9w!O`4yCcFw*pU&W{a#LPhPU{~UmIrEDzuT5*LWjNEhuv*_IF&aw8&Uk5& z;6P5Vfq_f<6$#4eNrQM4zWk?b+f*B%qv1u6DGb!>)1);pC0M+a6J@a4p#a&}IdoDD zqnT6m_fUIp%hQLOBUb1;`bz_?T2ZeF50e~zr`ik{lfno1V=jJWf91?STH1(tnW53m zA1qS@wJL+$E%U3c0V;GlEO64WcnySM^;mp<&HmfCZP!HsRY3|^!y4X|O^eXuY3}d$ z%9pEPG%m<>adun_W<2p~k5>bY<`zATcGk3_#I-HK7-NhRl`s0tt_6Gr={{_DRJ*Kd z7Ig6#@ow6sDV3ak+|LWPqKEbD{6B3(eIF@$FE*H<^JWB!{&}t{;esaJnZ@IT!@CnE zCOv)19iu*d{rV8M%ZiQI`?dC@EUff$26$~cXow?~OS?aGy|P`>XgTv(Oc(q9*kubt zMd_$NP8@iy;rlIDnU!LFMEM|i$IT+ZnkFa9!i!xin1*g42w=cZQSJW{6%~F?j^=S} z>8t{D-3qjsDzWJT0-s3!VLV}ccW@TVnS$3lq4esPzU!|InCxPU@EGPXQ*T7*Z)tu_ zMI^0)alh9J`)fTNO(X0alOI}M*XdER+uNj8{n^h}~>tSN_x(CRk>a#Aptg1ir} zt~L6?eu;geSa_gtG4eh978)dhbv?T;WX@39c0^|yMWufXS0`(l``u9_2C6e@JyO?) z$==NFF(1e4)`EGd7Q)rZ!JG5=$=;698X+t!r!J{Jy>=i+;rsU~o3f`)pn4oT3bNcv zX;~hc$O#cyJ~4wrhy2M~$59eT)f}?EqR>z!z2<8olVOH4(GQ%=3nH54EsG`5WMvHd z3P(DbtPRfDJCdvNKfP&;{5=UCx@OwOX1o_?QB~0*e8;iwc#0fedN}Obl*VR+h2PZD zi-)yNQS!1|pWj3K-5rzo@^#3)m+}tidtf=yN!VCZkz}5=#Gz#S{A3|3{n=*aZ>{4o z9P9E+zuZ|+9aYRtfx`QQ3lu5D$=M^YmK&c7E_-795v*>V4i_g)^Q^&MvA+orO4oJC z_Jly`WQGK8^JEy=)>72X%Zk!5+1Q!diaH`f2 zFZ!J|+9ScG6}+S1pzr|ee|zcT z;u5wt?ri9`2U6;Ebu6txWu9mY#5+J!xFkt;n>0OFM=~wkzXuR)q4sp0t92@v0LFWU z556#5ayZ0&!l`yOrYG9}H@`P^LZM-c^Aq%yHKb#f%v7_nXDcEv*?;426a53~BgAvi zY8QLI9w%iNIIjV?!}wO9#|-oyOPy*&agaoXG~;N&@8CKYa8(XJu~9?L_kL%_$@K{4 z9O;OS*LM6iI9*vk#)NN=aO9vE_s8E+IHyESlpbbt zy3KX$etLjsjJTYi+nI-78&;gRUfVcfjnbv_+Hd0G&K-m6Ge0FB3Uywu>bwa#I#i9g zRTjq#)7Y2MLwiHnMJsr$5@&Z zoj&P)yU$->C~qGlaC&5qf+~EQZv2xLdVlA%3U=|_n9iL`RatD|)17;c=k>su$VdP5y+ zSZan5KFVC~<^*eaFux82TV|yu44+y~U{3XKW3wPxup4M2Je}r?o`G)5fCS)o@=`4{ z3D82r_m@UjQM3ucPWr#`zmJ&T_d8m{3+{OC)Kj)S>XF0HZKkU%FVVI6*V7K@ee^3o z8M~1aR_QF$sazMpi&^5<1ai+x2*{mvHfejiCx0Azh1AUJizoIY1Ekvp`ca!Ayc0Ts z*shQdP&)*!dj9W{B67fq&t1d1W5F!1j4X>>K)NGc@^E)Xwe*)te_D@AOv&yChUT38 zY0ef`j9PZ!T`vbVj(~&_)B5`d+M}$3-11a#zCF zpKO%~l}fAg_FNn7-2bJ}67!}j>D<=D{8-t4%t4UPcXYAt`*JE5#?eTLXIt`^OzrLp z!c;XrRx`xm^w&4c)qKS$X82`4egHCw_z7E(4)Sasc+W=E3>;Q|Nk zrSgUI{du=ijFln5K6<2mvbDd&Xt~R(&}X|iH-Il$0yn1s-x&j|&!@;OAIg3pc{~08 z*pfF;2yG&H7*KQk0>IN64Pasczz;@1p@*^m-MRm{;nxKFClCMR;h(sl?#+~sG6Jp1DR?5nxRP4fNL_pY_x^{zL0^5BXc zXrF|vgqWDvKC4US*Tlrc&x>B4cI^^;}s`4l!O}+Hz0i1MYrV#p@K?MV8a#?1p9p+A#|?v-8$C8p(v<{~5pGKVa5-Z`-ltynWj*?K&+d@%ZOk`cl6rzYSJDZ+3s=N>cLA4bQ}O zEBjp(&$)aFzTfOldY;B>$aKQY`poIMNv!fKYxURiJUnlMm&gA)_Si#J>gG=nFGwP! z7ZMj*VA^JB>|HO$ch1*^B-ThF3z?E=a{rYi)xqiYrfYv4*a}@L7`C3o25x+nW$)eY zd?tOuOEZO4E^H5KJS%mxD{F*iTBJwzfGlh?2p@Abhy@o?TYTfCgxo=Nb&ToC)VA2y zE(dSTLH%?>s!W)top6eB0z*#6$dJywt^YVsO`pW7B0x&dggFwur#U6NXX+q}I=OaH zgoL;Ua)w}>TXXYx$ar&m&3H>+pL^T8eTN%Hi(^?P7(pfa9VG?K;iqS#*-nz$8R`BE znFJXJ3jRZ#5VmBuFQ)l>2IJ`P zi%vI~>*b}pcr7H4-*a}xkIj(UojRDpOOq^^HS-)vg|9bn_M|qTG8wIEg$jPbJvzTtGIV|yqPuiD- z4p8o$0u<=lpT!%mW(^j&g9dLq68yBr4txo$5NbAyE^Iqh3b_$IS~CMm10Njl_Pv%R zf22J7sT5KQl^f$D&vY9my{yjsJSu3Ue-8c-#1@?i>~g)H>`6^~CT4SdVWYpT#?|$f z1<`=yAgL9J+TiG7Hjf+}gDGU1dX3lFD(MwLdcN4L8ZEyK60Pa9fn;ZdP40D|8b#d0?LV?plvef*Vv zbBq%xU*RKXlMwfAZ|r!IYBAE(@WADGW38|R0NAFQh&bc3*4kZAsN^Lpm#e$jv?OYA zBi#kzpOKQM^;(4od$LqPgwo~0IkU6mj^&ZUu~m|dPF|u>Vtt`*Y?SZDo8++1PW~Y; zAN62?IQX9V0;eNNE2FK`P(*AOV9zaXJ2z#@FElMZ*Xj~HyX%wFFxKAvfKFI(;@Sk= z4nznHyDmASF6?uotyv9B+9+&)$x1fleb&fUGFiO%xzsf8K;fV?y6M;!SNv^}hKJ0= zDNhB6MpFQjJ8sN$WOjBz42=e(qJekFQkY+(_%GPTgoQO*XwTFT#yPUq9=%`+iSb=y zCAv(*pbNisZ^Aym)2kCs3g0vyE!-k>ZU68_ydR^Efqg#(6zp@$4?@zH)N&n|K>p(B z$Cffp&ma->=c=RvlPIm^ZPgbR)B;6Q%DT&PbYNbJnBg=g)4~%r@h=CRm-hj2Qvqu7 z@vBx-Kt^bbRu}VRM^^9ccT;ghTs@ghy!-CI7w(aBkpaRvF9v&|v z&OXQzHm&EHhp|~F!yfjBtzgQnDA7{66QDfSaWuLYH%X=sw4OTm{1*&$nRTP$|Ehpi zzUY3qJiQF3Xy0>zb-B74fnY$OZ_8#4<^}WB6P6M0ys8A10Ns}>&GQ?drs)N+p?De{ zZy2`xmS0EIDBK#?byCsK3cvbhdmP9|3#6H4g?>)V?(GlDl*A&nNvksnd%UNB9(>o- z|C71;>nB|erin2QozgY{J0fA4<2B)RvUMlOk){tYeg=7drj4LwVybGef0aE+ zZPr}XP6ODDh^j~Kqot#!S|)~sm&5l&m$`<%;_$Xtmt7Lx4S`;?BfTY4zy6){5~kTi=YLLWwZ=%-K`0_+BMs?Zmu_lcLV*b$;h8IU`|4$QMmv znx(c+T;wKFad@O zC}x;8#M;9zDqG{KUN;_})C<+LJv*>7fseRTCgL7+yNDoKIhFqCiTG+ z;In6gA_^_J|7$IpdS-?9seRPE}>3^bJy#fil2Rck#{yqV%kW zp>Vpu-Q@8=Cj5Dq^ukwfUu7Jjv2$O)Rc+$2bs6dD=yyR16Kd+7`B-uS7t?S8m68Le zc2Qx%qUZxSQ`A?5r0Q&vx|(!&Rq8gae3jK8Uf3>9rY2&vX?-w}So|n3GWi*6s1TB} z`ULZ2QkvollPS7>a3#p*p*!FwQ|Y74F}k5hcw@>;+OR9|OaZV}WtulQ=4?qId+TC8%Z05B=uIu1Tg~nZMpbMRiTeHk7 z!Tg!Ln^cuXJP0%{R!fJ~Fsz%#ULY;{v%B4H<|_@XE@omQIqS6g^sTC7MAf@-2D%6DzHun~W`(9?o)i>`aY*<%#LJ|*vdo)qE zGHGwMobEmUS|-If`3(BVR@>(o06$^xNN4*@Cwnclsg_@sU3ayq>ygwH`tFUay((dE z?KrVQTQSEH2y5{zFG{N!6Wyv+RAZ0umrczMx5~wKS4v}L=T*lMAXgoc_Y1RxDV3;! z!XQPBo+1}$HzuShaOj7Wg|>r`p8|1LlHNv_O>c1TxfF*&@l%z)b>K3+i{b|mR!5!u z8bWU#uaTB`oOk(vP%2%1-z>H)X6rK!-SHRUjeBEUK?=%$lbCsFF6DnGeyU4dqSqT0KGS@qYlWZt>J+5kwAlucEsSdjVPR2jBpCgPe_ zO~$tB{kCufGp(FxRo7@F@rUKV<3Vfbo1TGlyd}Skaw3<$hXnnTUpzS6H*ty@GSNIz z6XeAzM;FfTI4Mhq>CS`ZOYIYMo9|_<3QA@;Wm(yclDGwvO8=0|EO3$I@Zxso1@GIC zHpklH=o%`Slh`yJQ#KY<@&6umauT0qH(k5q0jLz5)&n535g?R&%}8rP)vJUR_Wa=Q zK=x8%Tq1^)lrZ+pUSSr$Awa(}E~iaSIB!}8pVSbH2142{rF|*wbT5Wb4q4?B17pTr zlK`0zf}<_m-}l4fRdNB>%fwXQ@^(dURP78$MWY_B5*2^K7vJFs5~tiRCpOeSOSstR zw;&!*?6}0v0{80yJdar{UG)jIf8IO%akjNdtbvl^P26kT!AA|#PJV28-4qfQMZFVT z)w@c6ZQn}h->52l^=qhZ^UILz_z-^3eC_Z;Bxo;CrJ10+!Wk5ms5*EAuj(50sdQ&Y z$0A)p64&mr*8MJ&UY{B2OYNSn;k~ilGyX%AVmRu^TK-3N*|0Zm%=UU%Bx3k-Mq2z-b2=FnRuow}#}7b%gjy{Z6`lJ0qd_?N zJOBh3|7OCu7|j%fv~k31;F0_B?^CLO*8wNRjDA?(iG;ZE9w@fDt2RMOX703 zq_=m|BA!T-k&Z7|Qee-I$@Hh!tbV+%^sryUj~tXCA6e$s?3<5ttc&Ij*qORRO|b6~ ze$178GT0vHDB+I3FgRwyXLh6bqtyZ5I@+$ub&rF@f5%e$9ZTA;Huta-q@@h)L&;H| zE_`cUU>y0TK&Xt0U4Si*lZ)*4t|hdlQ_f(DSfX$~11c+Qx?SiDjqnp(B#IsdgnGM0eah{q%lmjVbVSzcv#Yb-x8x3DhM zvN3dYG>~j@*l-2vzZu&KH(ig2o!G;|<~rfWX6op2*D_ALYjKzw;~dR^XZ)fXd2GrC zy3rvFC8P@G8ugEXWI>XEQH8Ia;^fT!d~Z^;=BT5&_pm({KiHbE^NXB<^ll*}Lje}d zI1QJJaOcG&^SB6UTeyr>Wm+glX;7eumIm+9@MUzl9Te`=NLjAQq*-g3Yn)IP?4Bow!9TXphY>J^ zK4H%n!j0xGK#H05m0Snc+BkMvKwnnV^#de_ZiB+C$`U8FMR8KZRlyvm@8j``h1mq(E=Ghs;g~cKEBc^~hu`8LQhhhRb!omm1b@hQGqZ6UM!RctzoENHq5;@h59{H<7;UJW*Nw zng*0{p|;mmFFc%w0^Mu}rJqjJMorqt97oc&?M(f_QO-&-f*^)Vvs6l2~2wIOh zxJ8^1hQxc;QG3|i;?qleW2ueQ6Kb;-qu>)b;MVwu0hck7ma85#Jigwx+a3Dpf#h4J zzbYv+$qsq+d?N4hogZJYh6}EPd$Xu!$I^{%k-s$@%q;J-qIw4PRv4p5jtxDBp7y(V zlhPJ+&g zmKbAB0uv8`)fj^NUAhdr%Kn=?0`s?Jpu=7?X`{f5v9goLtC5f6PTSyr z5<;F(D58b>u&fif*lSyeXvR_U>|=qb8o%5V=Y<_PRBL+1vgA7ZBKhG-8EO1E-oyF) zcO>(y#S^I$lPND=!H-;IFMme zOzFhkerRwqgVO0d3h;?UKh^fO-^2y=We#7i^?WGf*!J`Ir+FoARXag;yywusYVUuS z%xhP=eD=ouJom#^C4%BZBFL(e*pm46EV)}j4EYM31}#W2^ned##RcN321(DVBV09j z;GUgh|8P1+q%Qvb{yP(!Bm2)-l>)I(|4Y4`^X4Hyw?1u$q{YA;;2!;3Gxxjw?=n8$ zh5B3u5>E(RXY?X{zZ5(eHuqKGa!u^E%Ef56hn;J^z5aeIwFDh8!t^Ce8ynKpK;^N7 zh}c_o%boj++Z1x5Od?C%@GznL3wcI2+cYxqndi~WqaI)+{eCE$(nQAjN1o;48s=>i zOt3?YoJx$j;6!)e4-eK{@DT&rkLh5$dS)kaov!ZeX@e~W;qNkTFJnLnub88a-9HhtTdNfFK) zKj_MC|JW|dt8zzxuEZayrQZXl>^Y@_3w5%0TE}f|`L+Sd4Et9)LDe{Nq;r~}skO;j za^<$uM-ub5f&%jv%*xvRKH&MDD`B*31ZyG7 z-!4A@Vxs9wp}Ppy(paS&w~Fyu2!PUqWB-X^coxRm{b$6#pY7@hkt6|bZMRw5qJ#6ikfl5pjIg>5y zJ~dUK0T`X+A#@k#&o*x}iR{b_9m(;{=8q2a*^KZ19e%%t%Ud#uYMVRm{^`q7=V>a7YiTI5F60UUxyKQ#pXvtICcEm;GN zO@k$dxp0CBhr<*7qSiKPbMMvo3j2`UuqdlC!vq#DJ>9AwyipVY9VoD>tNWG*_`4?| z#ZmH*gF__gE9g*-*Qa}k=2ZJ53D&{Atj5z77EzWbm9m%PATXq%=fbZzZ*Qw_5mNyP z&cT->JEv03ry@PC!+k}g<S&x*SUiF`!?udLvw(>YzDy!h8@8->mgu)q56a(xolkrh1Bb=G?SO7s z!2r9}j3qlN*Ti$QsF7_1X6oI}5KU3TH9uQqjLVdZcRI542VGZ;)J^2k*S{+os~247 z?Yd&E7h*Shr`Uums|ONIpNmGraZ+nFr@GFPL>8B=agzxDl2%8S6+Wu`w%kBEO5=g6 zp`s$lVanx?+C(>;bn-Fv6I49mcXC9Xe_Vl|J7 zN}L_eYW5)Je!>5+l%6g<;)FCbDo`X@=j(wfzUc;oQQJRMxk+4^7k6t5jA)#Ho~?uR zPE~TlN`7tGPqYy1kia@!q3u)`r0o_S`*X(IE_NpnaWHnkL#(YtKgX zy$wKSg^e2AK_)QrOSeq*UnM;Ya5|4`eJ-X70z}(eV~ec9iisldU31`taMmN^Qc`B< zI9{*yiVEt~@+ggPD7_-VHjo-aH|y3rh>kc*>AMd^7c^=I7TW!b?8C*MbXfjdweeqx zt;P0TVu!9KiS?Fyg>AHJKIf9mj09sYN8 elCt^3-jLsR_(LyQivFS?W@TY#UTb#qxBme5+w`db diff --git a/docs/developer-guide/img/grid-layout-2x2.png b/docs/developer-guide/img/grid-layout-2x2.png index ba2329cce9b047b06a29cb95a0783c665742f367..898c1124e72c971c39487865332a62e639f9bb3d 100644 GIT binary patch literal 10897 zcmeI2XHZjH*zb1$K}DJhs5CnkiUooYnqoaPJxU85q!Umep(aETP!O;jLFvj7FoY6F zXn}x4M5P3Ugc3sN2uY|CN(kKGdGC8?-h1cHow+mj!=3YCf7!G5v(|c^wVwU||7JhA zX>mx?+7WtAjFx#WIx|8&6+IeY^7&=?eg+h2pATwY&$$+{L7;jkh!0G9XLFKeg$0q1Ue0R{8-ppNLoe=D{}C#r0ovl%Zg>Y(T^{< z91}d)_{TpFvg6{Bei8RO0w?5E7^|hUT9!w&lkKAc?i{9H@A1AKlq^~-YW3?#(dLrF z*^%$mX7-hg1Z{;%*^H{06RFsKsM+fp(n`wn)&$F_Ku;KPaIUT>TOGj;JBwvA#Wxpg z`t=xRuL3iXwC<4+zZ}h(tnz%@x*$KC2R+%1k+ETQqs-4VS8gwrhbinwfY>?bsZ0He(RiN9hsTEGWQEEK{*>f6DJtrmL)A) zbm(M5raji7XNl+jHn?qhH0p*{h32v;^R|#Q@f;7pr+(z@vC&rSEiOZlxg(=#9fbx? zM9G}aYN=&2r`z@gkm;}eFM;)qq@)z8tU?w0=lx#1oAYcMsX)Yqx$2zf>>W1C@ipuD z`kgI&@8`-Zi9oDtT76!&?d^5nl@}w0Al?IPO{QA{KA)0!1J z{)0|t1FN%}>re{xbwqik0(x`O*;AhGT&oqD?M!;V((^Vkv7#i?d3{uyB6~!|o>6^i z-t9u&%wO5g2*lk4{*UFq05)Vt8a+rzXhy*@C+3-75N9i%@T3Z z^izE<5%S3FP1W1pN&MQ4y%^O8@M`+dlae$jgMtv6i;fPxN_Ow{Lr!i+Vk)y&`!y{z zJg=YNuW{cKmLkY^c<*OVf_g)DqwCq5{CReqPPg~_=r3!#2wjY;`{DK7g2Y+?sKpfV z1InWtsy#H?4nDcQRe{zprFkFP@`1Zmqq5nfKxALhj00^huK(DplCI|np*}5f8~eR- zFAjlg{acN=oc-f2E#iKasr;vvQlxfjsLo6ZKN>lBQvto&#cxdvH`S5PsAQk8=Ik23 z=84rLMe>_Qk|6fD-wB~@)l-PpY)2mHGx6y8Gf>R#W5FW@p3S za`#QxQ^L!m3=Z{(%w7weu?g*7##af=#mF1n<~l-E$}C6i>QVM*;TxY9;GtTYzv6JG z4{#@^Cc%PL5l&}5n=_DL_<0ret=;0-A`yLwEon-V!D;>)aZl~-GP!|^2?my!z)94K z0!2$d1+FlqS3>A~wM^0?kF4<&8mjf)74>BO@E4xL^|2HNKb?6Rff3DxD`ZDC4=glF z){MV>MFkg&<~r6o*DO9-){SW|6SlHUMhKM=r@d*KQlVwu)2~x|e1r>QbRo&v^dP6D;27 zIWW);;A70mA15mN-p^Gbl!uI}eQxO@3+xgPBY=LxN4x0ZtADdzi)Hcdgon$!<;`1H z&^UP&2TX=($}^!wJZeJyel+5%LOFbr`oQs9^hA8cH`BqF(PyhN@0BVpF+SH67&Q>) z7dGZ~+f_U1C&C{aMB7$rCU_K8fwAr&FLg@v3a4T`>yJ$&MSOf-uH21NIihq9pxT4H z^VVoeZod1VIk`P-i-X7khqiM7$NaV-pS-4HM?~yJ)AmPyswzlR!4d$jxM8)mP-no> zPP^JgG-2b2BSka}%RGM66Ud&QT|AK8noX>Lc(B0@(!@`M){B0z@wP@TmJ@b}(1zM_ zK|0rHmo}yva!QNck@peTZhmRF5nbW9a7r)9Z!@cfXucOIm+u?&uVM>c8kQ5!r z%q6@fp-Sk?Ul*S_bz7Vo?>%lFzDW9z#LR534*oG62TR{JloF?gF+h0RfL4r1>vxNn zCe;f(H-c>4TMt?T{l|)&z(}5D)-uk{lrmu-*UO^HUAL?~*56lJ!WPu!Vq8UZMQiff z1-Nn^qo9P<`)T!=X^CG{7VV)pZezAApe0rGu9wYanw|tsGxeV2aZq)un($m>bfH)- z`~)k)GjN;BwZ-m%5}{7XFVe)Pc)5p$$wjJuPXRpbuS!w&?k*vV9xIN8JnVg3?=kz+ zDP3*ZY#XoXNJ01Zx5|i8ahpvnStMi?w@4F9^|35iDwizd$`HEn2|AWlZ)4p>YAMS} z1qM7)LEdTh2}wVuBRn-g-puJk?G}%28rVfbfMR9~%H`mvwb|PA>&m`ecImEsGlXAm z2{WM{=dAQ$)+bOTmyznFj$zH%JDH`|zs;m|QRQO{KihX?Llu68^TIWi0|Qrn{1um4 z7W-TqXyQa4vJnU0d{22ht^Rk~V42@s>^~EjK2e5DoYu>4XH*yxI=@?LahsQ}02?b4 zpDh;e0q@^Llyf}+XwDD(Bp9quGS4bAJ?U6=o--B*9v{gOgAY1(KCdVIo|2{T+@q|P z7v^@;lI=pBc)5VbDiqo|ah$tN74^x8QoGbHYB+w_!Ax+N`b2ZN8NE7Xf+nkHS*$74 zxh8E=Tbpswk~X;0n8o_O+yQl%UHfCQwDb-5Fm_LNQb|+&oBEo6h7sy~c!S5l%6g@h z#;7>hDZA&J@7XzZ0?_{XnG_QGH2EQYyd=QyNd2J(n5zXgz`d)YP9Olz(ExTx282q*mL{HFDJu|jw#Hrrn#NqI#uOlt# z62^Y3zAEqeg>eKIIKz4kFoz&Gl1ExJ;bafQ$pP%?p@J$cCr4X=rH84!04w|KCo-f_ zAz@5>Ww!cl7ODU@lR+bD_PVLw^r|{C^|ikXz^f!t8_RWFHd!NUTA9|}#7lVXyIJf& zy*yMoroP@eOHgGZs4(Y!y>+BgZFZk8klsKnn&0<>_(0U4cO5hQ%UQ=l-WPmBuUquu zuga^emS1aPq``e?nrh#z(T9Lpq0_m(Ctct4aeG1D!J^tn^)fKI>I2!Lx$R3kaVn3f zH)@J~ZyU;$c;YqNi$oJ%abALzZ{sU+OqWzm*78O9Zj|*bJcCMdAFf?;ClCO|5z72UmjDhcC?Kp56Ft1;(IPz=EM-|9$%nnJr zhwm3X{VOfAIOkN91+iNSG9!_pxi7c@Y9(Aoe6;ySSUeR`milJKrqB^J?G=dsq3+_m zD`LEJKX;E^OX$51{zlLuM{w~EHGtrJ_EW&l&ZS_Svq-MbBF|I9f3V3fj-QTa_+e7q zKkqW`I$nZ6`1cK*<2|Q669|Dm^%%ynT?hPzAN9^2o&MXQOEmA2zgt-rfa4ZfMV<#Z zFPJDP+<9#52Xz&3Sz?;wvU5Gcl6PY0ocblxp+yZj6Eye6$-7U0AvWO^4aichOcW{8%?LHZ@WJm(Be4RWQ=;K z3yE*%z4Fa4@mwbMv!nU^s&0_C&Ue=AA;d3Y6!=@Ak*tUCHdLhbmdp}-IYNplKS~a> zTV$|H9xa*tcZqPKtzYjNC!}O7Z8Og>O|u(id+4%#r=!o2O2lTFjzLyNw59AlNtJ&)kSI+6wbQ1cpZ*p|4rYV_;XJTjBo)-JF% zkBKpI+Yimwlo`H$fII?v+#65gtrsXj`)My|@GU_q!@Ev&pl!;PFOjDrwgm2D8G_0u z0?H>tt0YDqoIc2==?GN0@u$bx3#~O0Z{^*D_tzS7i$xB)U54y5&d|iL+?b}o;j6!X zrcH4A8sp7lYyEyqTg;9&lm1U!+S<9S+#SG~n+E}qOXHv0hMXC{Y#t-?-@!k<))P5+ z{ML6pH!~$6>6eAxN@w#WL62|T!6)y#9S?judJ1~&=?4?QZMSUkkN@Dd-rdc|8H``Zai{T<(3*9kF~{xU%B7*+T9n!_)v`aAroh@AaSXknYH*w5Q8 ztw%EJLW@ZdjJJU*CF7nG&WCrLF)mt?6%3pIcCi!-gFHJ5oY&sfc=B|?Ut%HGly%p> z^mB2?fJK9iWaZ!xocrYFE?(%ThceAo*(=ub)D{wSJz!!sL4ppxQ#vf)g}OyY9lQZ} z`tCy?k$;M%-Zlj$BG)CNQDKA>X3hd1$`=krpjgQ)_Vufr}9 z+ONFSz@!>2G#wc)U!v3G1C_Y65!z&cIxWD_-ptnUEwtqlJN|aGt$xk)*M+gNJ?{O} zJ|5z(O#9_xnthq;#U;gW^X@67oUWO_-z_=d4UHy|N0>H683;4ooSMz^5`-S+`q~KO zWy5W!a9iduM!hIOEX}|+bMcFAb8BEkI0x6J!(5mcDX`qchea%PjnBK&%^eJJ)pIy; zNL?F>(O!C51GPTl_9NlOcyKQ`r8KOrI%MI!hk1_*F~q;70ioCsF;~=z#7|b3^5ww| zH+N+lRfq97fu%4n)YweQ-cYsbJjH`}euewy-}hBz&@~5+021OCygK@IJ&+A_?&)kh zz8S&64)1#F{+Gul-{3nM9lZ_YuW24|?1kI1kdQ zNlLEv*)S(acDv<(OU9# zLjY?3&@e)7E~6@tW@VZh0EP0+0nfWwK#NVMrS|E(qi&v=l(K5y*!WqPl6u=$v|Z(n zdX;bojj>tDZx!x>iX~?OmHw2Eku;DnmJw{2IlBT}#~tqMTcB zST6#h7Il9>KC#qn{ST89(1ze@^WG7>`*d48MXe+2UI2MP#b7nhH^XLE#FeuFebpF5 zPZKfW_UD{GGr65U5+6O)uiN)ji3{JOC&N6V^9|Bs*B9Dbi_){iNbL&oB%I>j5Vfbp z$0CRG z$%c(}DGfRLOM4iMa`-Qn7mDG!5BmCoQS{oRgf{VyvQcuGrjhf;`*~+fC64A=-JTH; zep}WsQAeXBHG24?<{i4N%k)|KxY4hp7A3x}0JJfV;xRncdv>N({b%N_#H-r+X-X7J zY}7l<9`yeGr-2N37+t5>_0V!nLsW@%;BnCF&H2y)ev531M)aLf;$8L&Tr+PrDw@3J z+AstnOBNbr$G&oHc|ySY_a!X`U@LvV3d7|m(`4P{QcfVo@>_=r(?MBlk^C%u^ zW`?k)Fa*D%86I4Ex+7u*J5n0B%IaS`4(g3gZXjP(vRo2z7nlTA)}>_o2MCoKoChy;BzIWs)uFEE%7|gyQrz3X zLIa!gWYDYnIJQ+0eSWOhI94-I6(Aduss^~J{lPNmH~lsOC9KYc1wgNb+E#pboc&a3 zIyM*d`uA8U4OO=IZCGQIE`0sNc=>$mXPZ{+`$D=_*UV`|`qHFbVOVIA)H?|z!kf^3 zYgy5X{#mHchagp!2PiJEpZV${(flu@osB6;8@5&zQ@ht*hicSSU>aD-p;oQrm&Y)bss*o_FBH zMY5>1VMtGWLZIPByBjOHcsxj9-;T+#3$?HD=mpH6KKKTXLxY-Vg+TA z^^)Y2$)D?MmdfAAbuA+cH5%E7SC)D5BN3Z(lbZ{xK_yxI&N!J$HMnvvBQEr_iPv8g zS>@1SePjCZIxRu_T8*RaCOivLdqhSN5kj3#FPDP#xUm5|&(Ok0!FCdYbIm&iv`Y;x zeT>^bpO7q$ePmoJ!n@G$IEgPTh~CF`KyeU%Q){R?BJa7 zi_rgt_^-15U)u#MKnU2SwcQxl zS0;@H&bS=fawbg&xBu%!{xw+t)qEznrzIB;X7U5+4c37ZGI=Q{QejYQY;WDW3!ZIf z2@%8%6nC}=xw>MYQcC4jB+$+lb27#FH@vFE8)q#x0+vQ<$y*|{DsVEU!L47G3hrsE z&9@G;5jx|XQa@{p+@TaieOly8pA3LZUX1>62ylL<3JO~(Bqzoy$jO<4HBKgzmVZL) z9d|TFF_eVnaIz^@yz1rlNS*F}U8%K~9Rc!al{!{TbNHSPzquAmes#ph^R%`?YP*dT z3SNV>P|*jyE_DSg>~!BF^ke^VD!SK!nK)2y+m>Fbcj37Zl+(M!EP)BX|F9#x7?Fb@ z+wTwKZ#>t8tEao2 zGb>49tg#F*0iugf*$>!n*MTM8O+4a$Yx z@AfCow-w{Ypuw9*Pb+JtXctYbjix3QWt)=<8KonVOVVQ=fbt31{2ScH+F38yQRJv0`?vjM14tR2Gcq|&{o^{IVYtso@xv{ zek}uNYefjp!N^Q&Ge>Rhu<<1Q`n9QZ-A%BF-RL;wNQOkCHRZntZh*JY%7uAb5?muA z$PO2^xPU>-JPIy?L3bFFNgUW40vEgS`E8(@m__FI#H;d?`au@=w-k19j6h*)(swj& z$#s+048mN=$Y1jXdkYLgp!b<0Jk0o>G)uLfB~HWv^wltSpL;KY7CNPPZsb`|Uv|v0 znqbrD|FqN-$=!#V<35NdbgAgoV;pssYkk8{gTlyl3JE>C!p+H}cAdI;a!IG0P+bD4 zuk`poBy@P+^ohAwU8UH{)utHd!c=?d*qr6lV)f;Rep)Dp23fIu05F8xX3Yca4FnrW z5_AGVTa6T0=c0aw_-sk4K=bk#wa%QHI0GXrCVFkdvS%7x(0K@0EYAWI^`q|zMCF$< zN0eU7gcK%qSqsQeiu5c36;k@Xhj-?LY&XVLNRjelieCZ0!sFh$I(KFSh6fj0{N80R zZ7ej18tFd4myrtglwOj1q&DYNh`^x2!pxipy8wR#`;7pYUZeE=4wNNDV*J*zR#m14 zi}#>c`z=&*r3`xuOKAfzNaZV5o3l;>^eVt5306_L__0a>?W)4G4~R7VJst#f0k(wq z&G5`Ckh_#D@o+UrsBBq)k8r=^ZYfHPg^CL@D^uXG;|(GB{)xiKWDJ!Pua#LQb&vhR zv1JSr5PgjdR#JNDs1$h|bRD4iPsRl5037hiYmk?)ZVmR4qrdZlpVCOSj17Wa?#*w$ zplTTAW+g6W+4S9Y(R8%o4z*SRJ(`wOO2ciml+il=BTK(0fe&O{QINA@4b;qajIiS= z8X8gTrZ`=wDCl(>M`TDjhU@*4TPD3eQmrXhkZeR)7YbnqB$ZiS&?m7qo(Ae~B#mI> zDW^)Z;c(q+l&JtaH%noXVcRhU2^o9qQJl4yYcwT|c7v!y5kcOlX_BREMr9y| zCXTaDQT)A6jTf`38Y*5B5Y}_w6mXD>zs~iniId$A-JPkep)v)BVvq6#0bI}>eS7{J z^gr5FGs18sTO@aN%Y;;l`d6aDH1CByF#{$%1cQ(^CVJ%4EbHt1$LaO8MO9c0F$0b8 zkrza)nh4Ns zz9YS@4s(GwT#-mg=KB*m+)pbPO>ZGyGFN0MQE03Yy>pA??wvHhP->E*h`bAnT-y2q zCE3=x<4+C)Nu^|~T8v;>&&@pm=aRaTm?R_Y9|7p{zt^@KJ-_YuLPT7mw$7cuo276k>e%PLWg1e! z_jertQ12(fKXB%Yg0B)T=WDqxa*Li|Wzd>C1;^55Pvil#fMZ-DBnNL15pAKlEB_ft zKYC=9YCsaeMvY|RW_6G*XyqNCTSgZi@=fb0@t&2xiI;h81fhCI?H z;_h`<1NQv(^YhgYsTX$dF5CO`rgs^&?1`1^{pXnJKPHa%8O#LbLrts(Ge>17_;w}{ zmj~)-2G@ptb1M92&p<^ z8ebj7E)JkS^$mD0l(4>G>tm6J6cy-ZXQNy;3u_PCa*j`xjwU7q91?y;H#_Am`qz!= zis-;hxDL)nyoQIe--;5?DSJC@_VxeRgdP`83f!e)AqGCUm>LDwGBM|mMrkodSe1k^qC#F zf^(5Pq!)_7y6$*vBimsODq6+07+?_b-D~NwkzuJl)oY??E+3aqrnvO$nKxYFm%*d? zJ-$Qm;7YAlOyIAv97lI*H{)Cz9TL7NXYNi5@Y*?Ki6P64?MvZP zCFv?(^S-F_^RKW}oB5fHr?-O>W1VF)wKTq+8`bo4onUC}$&tF4_VlY?HM`dCDs$}s z(imHx21sXi$AR+W7)OdRCk&=*^58sHsANG}s(YJg5EGlQQu_@xlMa9(1o8%;bBs>Rz{Y;8vGn>gDAB3x^5agmEAdyV?otdca;+9Ty4b1Vk+ScB`53|~zelwlKK4KZBfP}}?Oob=Y7Uw?U<1K*XH}yju11@cgn0m$HQQ9q17sGj6F>6M!|y93<~qx^o)3;w^3xExVeptp_Z?SqalHQDU}1d=5MPaQhtSYI}+AkoA636_+&HWG^4ulgdN{B9UXxKIm8m-SC@ z28`qoQg4rQ8iTvPiQnB&J`M%yA|>gQPc5w7`W0WvPmx^5$;otK^Fz|BX)Tw5tHal=n7(y|Ev@Fz&n^F|5Eg_X3{Stq0R;HJJTy|BEi_C++!3zdjl*$ev82^$@Nq)fvdN&9mr^F~;&u7W8|-G;IAjaL`Bzw2@u+v#p;cNi^R=wl-0sJ4 zD4669Z*@%}`i)ljxRgBZU87x@(~6DyW30=o)?_#Bd#z@(>4H#>xW~{y6AEaJ!C8je z4Wllo&|8a%#=P&LOyidym+fCb)#B>ZICxT$cO;FG9afq$m3}GE1QPU8a$0%3C+@*r z(kY28%^(XNTnczsO&idDvPD#f?uk@=`@p!b3g?%mr&S^r1HeH(JpE!~0AWTpQXs*; z3xnS~B^~UElaw&KZ!IP`TT6u;&TCQ%aVOFUQ$rp;hV4xpO}!)egxpy`^_l49PEQBJ z`=;LBOI*)diAwFs4ri9aavmFNznM(~pr<`~g^5B1mmJ!^=VG3vca&4S{GO`;uRdS? zTwr;CnZDZ4dvQ@<4&@rZgwHcRjK6>#C7D)mOI+<9rL@+GV~DyBwqVNy<^vartOfcZ zF^Ob(JnU5>+sRDQNYc>^?I&vg0&ue+c*(q=MaLI8-8qwc=Md!R)J-=tF`~F>HsgM? zz~y)Zbhb7!M)QBoPx=HD4)s3w*X&#iWyXO7K}(Ej!jE zdIQ{&OcZh9Epq3Os$peL^Tg%|;XJlM80w+Zs(wNPnVivviD5 zTO5H-zD=5v^;X_Y@As?%P8&EOI}mYtms^GqE`NAGP$Lvj5JEG$E^Fu)EFth`EUxxxaYU^g)2Q0NQh3?aDy%wHx!dlniQyeD8w#++_90zZByTS<^7iHquw{B zd7SC(P4krzEh(|(PwvF0;@woDMg4mH%fW8f_8HzH**zpgnz`J#m1PD3g0Kl6F=o0A z;nOY%W=RJ`HEj9DW**jHc{rzQU9oKHOVj0Hre(u{Lr-rU02(3r8Nq=kc`@mY$*?C3 zM?ihusiDR#Y;nOtK6;7D+a1yv6a>6t>WP<8SfV^%_71yPW{<}cuNP+O(KNq^Wpo3RDukJ-oxjFK^lPQaiisX03A4pX0 zz>Ae#MDl}#FA~?~IXl+7dDN^kh%UN*4*&vFdw#HX)UKXGdwU`;)%S=}jkbz|VN;hw zwF4x@YtfrH0wfga`5WKv4)hHkqo3GH6?b0)K=LHLBR^K2Gx;6gB$0{49{ls`(O+p%bz>n-|^} z2~VP`*uU0Y`lG1C;e(e5kzcgKnEo~h5AbRngg)+jv;^+2XxdAt7!o#EBoO*K)$iF!3eBb$s{?xwsAk z4|+u+sws*=_pHV`h+ip^onEx)kliN^X)xwnWFLwSU%0|_+>DF4*>`=WCm((Rb#SxO z8v0!);a%ee$+zDvT$Gylc<@^u5Oa@o4cPj-RZs5@`ZIfwgg2Rq)wkUQ5sx(+WkhUn zR&NrT|2bG{ORaXg4ZBConu6+AiT<27pe9A&z~wAd=S!eLvY)iG*QT_8=fxy^q`r*6 zm7V}UI9y|Ue`eFlPOaKzBg2bQ;d^lYBUgtUI}B)7L6Zl$ga+`aAIsz7!wu2*7~U2< zd2KPc0nz((quZ@5rbxGl8q;S}FOW*q#HRC*)FBSj)en14MV5QL;`KO#O{Xa0^9LNY z$C9KI6adD>1a01aNqpmZ`#zwCuR5sju6sHDc~zC@x}-Nn^~I4t?x%H_E#03SOeMb+ zxb$Y6P^gaBT6&8{wyDH9Qcbk$%6QmqV)h;Qy-|(yO*)(GuBWt?i$mVD-1?3Tl<;~D zo5wl6S`cS1UfQPqo`9cBDULZ0N@rqC9xu^+~l?98Hhv6Nw8cOa@xu63L%HHFISQutn`$MeR$?OyZ|$ibi|8sre=T45B2Ts zC5PVM5;#@HVFtYz0Jx>5NMt2>%nn+{$-E({(u>u*hdLQTuIas#N@25Q-@9B*0@p5{ zY?yiJs$EG_3?;J6))++A-d|gy3U3pKGF0Zm_ukb;Reri~;?UIJ~7u7`7fCFN9ItF8faqDl1*E;+z6%ybXgogRIO#Kcz`Z)v) z+1Z@_194wEO+Df`IL8Swy&vd+^GwzbasJeVC;!jl(a|^?s|DKsavMm)|5KON8z;q_ z(RQizrplcq-P=Ky_wV(rcNea^@$A?!QSu(-s>7d)ijeOfLsx7II?I4wItgC3uC^=$ zZ25AnM)I%c3F*(yC4t_V?e%s!{ptwllHT88{-@L?!x6;m>UPWI&z6Ny|1mhpv$-Ah zG;f2nH^D9TGJ9tLzawoZJuT+;DWkfB2~t7loy{u2G2g^$ap%J$papEUV*J}Z;hW*oUCxX#as*|0&F$fvwlq9jyi)suq-&C3T^=wpnISFW$f`@!!5=jDoHPlZ-$INzs2eo1V3Jzzn6lI0Kv+D~0jJwx!YBHO}KF^ca zI3-lz?yC09QIV_O+|2!j2feTqT#%Q81JIx1+{ViTu%|GQ;APcs{ZzwTAAG{8XZ4qY z>LS|`1C&xp0K2#WDp~mBk&~8F{isR6oM6O5G9=MW;`Q|FHK9ji=s0t<2V0T-gnX_{-{$d!1x2QRqPB5Q!dwx2D!MejY;v9=9jfm3)5{%RV0XU0!8 zfR|;K905T%xPmA}Gt=n5AKEuR**=u#Nv(z6JSZvaI5I!5Z|3gu4k!Qf zgZg&Y?Y@6ILU*PeDuW8`7Px$Rwj`{ayXAg|J}Z(oEyty=)8XZlJ2B`{>%nU*yK+e~ zgXX3MRf8M-JaHI9vB$S#uA*YasjVm$%t=w}zM;~3eC*rDvLe|zg8MJprme0r@$!h@ zW}9$>o(9Q!=kK;}=!+DFgS+MXjwOM@t37FcM2=hEWC~Y9 zg0$=LaJd_=5Rb(hs~2x_6BTb4IG2i0R>e-<>$q;fGgu*EM{_Th-U*{QLX1N>3jT;f zf$SlM*5)l_bIBY3>LBqfVZu-qT;K7kM6=l@axp0Q3^!zJ24f-P>@m@X_oFId97`U_ zt$$Vfx#?@_=)$*pUkSQb@Zls7wPMUA5ax1&+XT<)2$MhCL0|8`eXUX{6S8qVExLZn zx8=074J~c0l!25NMY5D4om=|y8!O|@APT*8*+1j~<yb1V=7}vpS6($o-o0d#in4Nn(zno>`?+AdnNhXXFS!$x27w zT3-IYB@l33!`*j_U4I{46wa~IFD)O7Y@AOUBAa4;WDlGUmcUH+hr0kujb~-*#_5cn zXX!p&D5UHS+kgek3t;G)`nak^iHQE)t~93QYj`qU`F?s%9I?g@T5I88u(=jTlgCzC zbS_@^xDU6G20xcAgbf(w%kP(ZDAOGh-j=ZYs^xdjCWa3Te5y3XIbI0M&IpcLX`QO> z7)oM|ii7tvU{}>QWq+Tjnj`f_;sigmj6wg|rK&t(yn_LJ%XquTzWT3@upPFXC-~h2 zs!b_y-|sAZ6GSQs=+Tx0tMv(WJOY5MmIMZfGoFg7aa|~KvOFp}E(cQ8BxdDVwn6JQ zyjYi{QpL+e9#MdxDKGz`?2AVp`Zu7kFXF*#Gz3V0BCo+AN;{m0imzTuNR`!D4|Ot& zS($dZ>D;Kf6FGkHg2U@_$}$9Bt=bo;4NaZ~W_U28cf2|+tM|@ww3{UVn%y_@p0g0z z8Raw7_ef{U{)z_T@6nsx zJJG^2h%%21m%$Kyb@G-;d2ghyo9)D&Clhr-@Q@%W(vWDFn3kgEtUszhlI+_k9gN4a zItN-~{A3*+=r9*|GQNRW-rq1XaP`fc=9>9<7;q_D-r%PaarJLuASYSdK`$k?Z5`v~ zStb`_e)fP@W1KzP86(#K`K?-dV6Z(27m**^mg12!CmKyMX-_!k+3#p}A7Un~I3@aX z?c5(EQQrU)&o+swcIK=|@8lA#M?`g1ny{Mk<)O@$apIs%2xkX9>pcDnx}uQau*5(S zC25^oAgE$%m&{fo9dBQO6Zq9Cvdi0lk4hJp*SCIlD5*8CgdJ7u!w>^PXCEsHH{#N1 zOTh^Y?PfUTX%bCjRjGtWxE3#op(@zKE&nR+OjeDXnlKQ24cS6hr#>Q&eE|qBycj06 zGEX=j?CYJAyoA00l1wceJrm=p2#tfs0STub5{(`h~YL%+Ng%Cr% z2dV_pgy>*a(BKv&iq+Ser>wgm%HI7~Bvw@&DJ~LlO3oz5QA;4OHWozEf`grauJ{T9 za<~WgO?XDxxoA0*{CIW6v%vuMNm*Y=Bi}OA@Ge`5jVFcL_yH%owu3Z7c-^gJUzWo>OG1RgQc^TdN@&@=GmP%BfgT4;Yb$1|9-Vva8`+?k!y`v;94ArfJgijK=eP_g;? z2A`wK-hUt(=tU{B9c$E>xae?YU{4;&@)jNk%Xy^kF8|uZ5=UiGaME~;Yn60$Zw=aI zQ?jRh?6E_`**kym^BiB=&6;pr8b43X&8lPR!$Ja+P$0Qq$zJ(m!~UR|q*mqa{k8PyV-_YxJ^pApde_ z(6Tp=?|@d^*rTnn3goV5e$!u1RWNdl~T zSE^@qbro66Jy$t%V_J8toEX;*0gM}#Hf?P{l}ui)(-rhuTfMjbX)smG&;9Y@QF;~B z{^GYcy8>h+)}LOd+T09KJQ@$+u4GdDum`mM?QK^zL+QSB@RZFy9nE~KKO1uTPb5^- zz-fLmKWiZHv$w73Pw{ilhYI08od?UnSjkjCyWHACl6ovST9&7V*qg_z-l#3Zx&re^ z_X!UsWYo;A6c?0#wO`94@vUN|FY)7_aC1HRq!gs(xt}5j7r!ZVNC2p$cA5+;2tJsS9vBbDCRsQFMQk(Yt-hj zW~kNgOJ%NZ!KmU{ZdoxWOAVQ%#clr)tjS8QqgL|PX1#SUC}c7o=s!S&{h9u>5cKZ) v()hoR*#FPIGPYtH=*{_COI@#RaiyjZoVyF=kgooNC+Ng6*Q5BK{crvkSEses diff --git a/docs/developer-guide/img/grid-layout-2x4.png b/docs/developer-guide/img/grid-layout-2x4.png index af3242b504a71d0050708bf353eed9985bd58fc4..34f340e6257f884812630378383f5364684b2268 100644 GIT binary patch literal 10597 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 diff --git a/docs/developer-guide/img/grid-layout-autofit-landscape.png b/docs/developer-guide/img/grid-layout-autofit-landscape.png index 4cf353d56262515b609816626450cee82f0b71c9..e01088fc2ed9e90a61852ac40e9ef0c9273a4818 100644 GIT binary patch literal 10153 zcmeHtcT`hpw?5#Y4n=fmYABA56(iU{2mvdo2&kwuAt)j(2|bh~fTG|~RRpAqC`b)0 zp(GRsAxaBKNl1WD3=xvh0>MDajn4PY{k~sWcin&P{b#aP)>-SEG}d*pn@; z)9M(y2yqIs2%CT5agj!Jgd>T5!7!y`@2SYyPaBzGhO0dcOg-*6AT=(`#Z_CQ{ z{qBR#?#G;uBP}~gFOLR0!7{=J5;n`mkJjjBbN@Mxzpqjk8PoW~VIteco!_OaZi4ZYmm2fB?;wQ7h9nr{e zm{lj~XTf;aUaTjPQ8$JJ{kbsG36qIxt~)0e(v=fF*pVtruW0RI(yJQ2_1Rm*Mu6R} zEyi)R5679?*Wb5T6hy&G8mD(PO+xOc#MF~vBM!Hlh4fEz=&xpvWO&Rv{f_3QkWh)C z!?!DojE&y(C$;)Dt|DfSHBU|e+YGFn2dXh9f}UAy*k5Mj=fuf;pnRhrqx583dCb_g zOkSmS-CJW*f*Whk{y?pXH=VZz3M|izKDpW=(jc1gJ=ePqCrt-ViUl+2IIysQ2u|`7fkek!#kF*MF=rY{qQwa_()g zqHNoZ?m4AFM9$w+?nEWes|R0{PWmJka*z&cA+0@+X9A0}kK@jfj&2ezH&FvEO90#C zD7jOV1CTIUE6{Xmlup3gsRHQ$eV7h{PbtGP6R7`(KgPT)H=sNL%_Vyp88Vhs+cFd# zbs_}Bx4`<8!1#o69Fe}mFMm1>9a|dZ!XjKFV?H3vjUF_&)JbM%~1V0GRZf-gSUq{Xdc7O3H z#CY)0b9E7DScV;_c$+JxtpBC8pf`Tf)tscuB%wP+%jr}?HvXQg-)xFb99o2SUaV6Z z$W=#i+~=TtLqze}!kEH0Uw4d#Y;u5&9p&d=l3Az>di2lpOpf5^z}*mDkd zyG_s;0ltcaLod&xtGIm{)5qwrMy>Yswu#GvO-UJ!saLw@ zF=Kuq7+UO3Z@|a=!XvO@-$S^{zSo!EMsl_`E3Q4WnK{W84v!nqT!^Gv@CinW=0+T) z9`$xKXyn$e;7@sE1SRbRzUZNeDZ%VY^4@_G{T97_?4aRL`b)svT)3t0p?UQ7fBKTc zmiS^J@#Q4TaZ`@Q5_dw=Y)D2Qs`BQSTnG#Iy4``l<*b}66giDc8&hhgIu9*+Q^q=l zN^r0A>5s{3L*c3XdWfz^`rO#w6}k{iZz#0G=b88z-Qg~BAkBE5QPGR5rn4VK3ycrE z-LNk{UEZ&sHG0X-qwW53p=-UZPm*Ep5r7A)==m{fU=+1HlIG`-D+>iEjB=ftJsm?o zE^uj`(<~dclr(EB4SyvslJhj6YZ^$4b;U*Gg^&&Ajwl&MENlws%*;CA!}n*c4AD(p zFIj|h8#z93Up}XdX~1C;>z&Tx*m>Q+eoFK(k072YTuli+x`vV0K5RO*U8hi8*i3VD z_O{!*yo`2NBN;B>u8*Fkh5qpr9Ppg!CT2b>Ba5hMJ3$S<_^(eYbLagt_Tpw%O}h9V zTLRMOan4F>;eLVFTU>k9ycpSZ4>2rcD@b)=Q5~o|_N{H05$leOS{zS>>v%1^PA_pR zux~);D?;s#ovwSbHHbRI;1(*mJSOLbI0XZp;EF-n2Q70sv zmcs9xWtr)+u)`!turEm`omp=$CFHkGyt9DAM&rDQh6dn)r7VQ3pv*>n&>4hyt-8{T z7T~C37$;&WMp-bCUWWYrph|^eqT%>UO%vB<9-Ym(zws!-2cF#y_u9&RtgKe^1;;}rFxrv^@Eg&xd_6)FVW;o{~UCF?r2p3Td(PM$|oxP1d| zO|}PI#FD@*go87SF_H9c;sh!dkHZmHE66@;I}a?n}W0VCub*3>!tC3A7Z&+=GD!0WR3U1 z?!n@n+Iu-!UQlIOLHd*$qxFdSoo_vpsci?=f8zg!&g;Ok&DTg zBC@Xr;@6Q8tE*+^Ds1^ktNdB5T1B-V7E2JK{_@8;hsDC`vOV*esQK2Mr0I&((16z~ zMiiE0XGmE25G#|f#PP&^a+EEj?RM!w__sOm^BG56ghJS^D}|j7VL%tII};ZU z58G6cjPZzg(;~X>eFdKx_`xA`SSoirC`oh47Tth-#MbjE)D3JslIM(NeT;c;-2)$W zg)TKJAx$z`9j3egZWGxYQATg>Hs3Y!?*#Ejd`(sbJZ1% zueLk&to3baWwo5c-z>BuTY*17KR`qo;q$FoKhUX8TcNUZ7A3%Vi6itZI!6YK`e)qPK7^AhcGTc`o199^UreY2&}`S~`5 zv@*&%nLgU|5yf0?b2HQq7i?fC8U*e<=kq#`x(+9vk8o+_eXcph7SrC@;XR*t0?dF% z06RwJd`{E$>cwW4)RNxwW?{PK%>-F$%2VgC``kgf)-g=>`oIj{Gve6scKC+kwEIC^ zwR%u`ws`{gPo_D-ojNccKBk*!C08dMw9DL-@=6KdqS8F}PL49LzAN}_9Mn#BL^lF3 z`b)3=lc?UgjhiYFn{UuDdBMS6%uR_Ijv$9##r1v!GU(I?z9~*@47Tjm;at8*Dr=`C z*afb^XVH};PJohyxZ<&91J9}(dSHW7{vu4vdiWcCFH9Abv8{Mm&3XaRdQV22yNB!Vbek@HK;Y*Oe4$v zs{(3PPPrv+&o0ENTe;fa8$LF413K9xsoAQb@<&%d4WARk^*ivw03j6uAiU`h>WA|^ zkljbaf-4IotUI0mJr*w25|>)jWZ+kIHUr+=A^$`Vr>`yPrNRW9tT(U|>~cHAM{19a zq#-b#mC>gQ-r_r0PO$mjx!qX*?$o6)s;=n%nb7?QgpPFwReXERrl`+0tWPQ6$aizA zogiK@Yp{y+>{=&m!HV$$QJfzR^eGkIiP=u;Wt|wUxrRr?nSow-iubruV@2DAahz?t6# zLq%ogA-6EJ>qqt&jh?r{R|Y9O6!s}(7f3=M&zFS0PL9G}6;ArTjoh}WSO5A^T~MjX z=1towGgb8N<~DtK3hHQl+=2}b(yn>@gkmMPy;6zei`CkR4R~gxxqI@wWX4neHrqOX znAApdstD{&7>%wPE!)3s+y3V=W?3ytVqdt$OglwNBU@`*rTRga4?nYSv>*~{tm2+f zN>ubFf0|qTxRRs4&~c=>D)Vw6UaY(OuI_(la7_A~DKD9RTfXK+N=r%Ye06BtG;_)Q z<+Ir7uZ|Z2mdjonuIZnab}yD3Z}n-QOFR;r6tA|V7fX&ePngpWW#s#8Q1LDJepK!5 ztCjqXCMBCy^!MNY4&C2r^Z(y6!zv2^-4NGGXlvEowszIF9QAqo&R~7jZog&GQV!%+ zuGmo*3*L;#Sq`! ziH$7ElA(FGQE?c%4xc0uEP4uF^Y4uY&6c+vtxh@!hXf%j?{hQm3R73w2q(F*%FLWo z0|~F)&FjzDp3qK%ZMg|8%LjlVTS#VI-(d`C2mOS*yhc4pGt~PkDIAKRn?1M?b+}zL6e*Z8Io2897ON?82 z8Xn*9NqwP4w%;qXACcKt^v=WNojcg~)=CB>laF-}6$d!qOsUXJ9b?2hdG)goC;CT~ zdyKuofW$$A^KJl>ZdV(sUZQ{aO37<}g(W(Z7B`CPJP35ZzbjM5WO?me2~#7ye`0Wo zY!U+FQ>Z}iIA#_OQnOo)g-B zykthL)bXlN!3{Hm91Jhqck_hy4GBN);qZSGZ zCV2H1PsY00s%&ybx-2qnLx;vgrj8>ulLbrelmNK1Ux43-_&pt03YB!;0r%sA?>FZQjX?vV@%Bw|Hq*J+2@6TO zrC^c(&lQ!QLcSknyxO%cgbuH@q-bxSk-$K>v60Dw4tJZj z^{VGTvdO)gGj&`$pu@G82oVs~(;!fzqi&)X4nNb}BgEA8pwDva=sza9#<`@ha6eYD zqvV9nEyuno<_Ddxd*gJ6kNSNOoaA=uZe8TE<)h0!aO@iHc&^Y}$6o1V7|gtqMYS#g zip7cP)nQhPA8c~%!0x?4qfoCu^Fi}oruUYra?659#q8QfXxb+G9y3pu!b2{tO?ktv zJVnaV)I7MUgWU{?5V1NtHLP+X{8#E=Phk#@c2Mcc#@a~LM_^u^jh5|tcE*i9)Kz*! z+j`wSy^93lvFlw!J_a?gg`&<35}g z&j6&^rUTt446Q*zPsZt2k?0*2V16t7ROtxd$qwE>QSPScr)@y71H`jk7#wO&pVS(# z(TSY-pDePaLDE@9CWMUfs{Y#TbpUgcNkf>Gt`5V8Da3^cijsWz_5tKB;PK47#j!L^ zssg>VRB!Sj2T}g3ga`Id1;fROO{n_dZ&RR%k;-`39VL`FalZB*Lgf#Wh}K)L7rvQe z);v};XrRPgu5Gip#LKlIL^wISxazdnG;4_SpEXXf6)8FM-ye#zz3TKcEb5mEw*$s- zz+4MIu18`VM;NJEN z5%^e!WV`>Fpf;+$cn!Wo~YV6)r4J5p+7W1bQ5EnMM4O< zzyRO<^~Q}8+NrooVPCdsapG@3K`YLq&TZ+&FIE-l>f|anY3#^*vHx?bx+@D;h7D*f zP%M_G)J!bGbvz0a&Z6czH^$D8c7CU4!ljs-E!ifkXUHr2n6}M_GL&d%aP?8;-pRmm z1b66P>OmcuyDh5x#kA>dky6{J65YvCy`ry|mq6O6+SVWZCsWIbMX#HE?CYUYj@uu( z?b(B5V3|!gRHEYeW(wa$7|Ky7RAe(f)oKC=(VF^7Ns3hu$G8jN!6}ZJYto-YUZm!m z{GSEs4EdzoOPO*{rY>8r<5{hiz1CSp`NVD7CP)7fgY%$eSHM2*UiaoVshJ3PyP5LF zKb$K@@nlL(kWJ{0$g-cZ72E(Md|{4gfJ*XmH-1$z`ot^~A`J*p*3!Nwn?TxO!crm? z3rm00#LN?eGVp)H$xPa&6c~6vV!sOxekRykf*OPj!)WRpmR@v8(qatGt!q?}h-2bHpS3{0 zmXn)QAk8Z*U{o12O3lPTXXsQl7mpBsjUWiLJH26?=`}Ngdl^}p2Gd)`hcz#`w{cH4 zZK32SYkSowMmhOFk(0PSMM_%aH{77C~-&)SnuFl~DitGVdD7E{`6lnZ_Q3iQry{a*&s%rZ( zHd9g-j!_w=*>n3;Dx`H0d@BJV%^DfX-!BiU^zZMWx`X?&D@tEX;bG|rVi_W8R_2x{ z?5lUL>M|#d(D-#ZEsuRG_`zRJ>1SsA)&6Bfm3kwZPKiogCv|83)t6;iXf#rh2JC^J z&rOL_eS+Q-rvxTy`3rv?Y&_2~+lp{1wd#KpJDoh(v4RXnVF=8U(M#=3^;B>&N6=FU zU%LVO64JZT#{L2Al>$Dk1pU6!@qx&9NU0M^m|ZUD*2eSA>(pyTYo@B+rUeNc0*9spo581Y=mZ%iE1^J^lJE&eU{NXRAHlWNm z+^6n3wVwP|zo*^G9bCbCFi9~arn>sEXO;8mGWsCcpM`nXCz83G(KXJEv z`efTBu2r#Rf6t6Xp{@2%wRnN;kW>5}sZXj4pd+E?g7qK<1)m7a4HziRFD549*XyX> zTA{3Gebu557vgk_Ey)rIRZ7b2jGC+M{+4l7!d zlpX;6QM>2UMLAv>0NW8ehP4Uj6OdFW$t4$+-<(>G+x8sZ(lj@o*u;NmK+eH5NgAUY z7=xhq0}k-(EmBf?@aIRyJ>?4qm%b` zHU>#cN>4K3_c4BTTlWExH7KxIIKwpw#PIuWl@LmsUee=<$ZQBIXxcXJ`_MLghOBvG zy)i>YO6v2z8JW5EzUrj%oPNpU_r|e%Bx%RR_TeVmc}KVXUEn-k!w<{nq^)NfBZIaM zmD>cDRdLmFY>}h;WThf&E;alZ6f{CO4`5jDh}M9NLoT2jnsp(IZCEl)@4^UTYndpT?AKKY!0|cNo_Y(SwL_wzsY{rGaQfo08?6)FnW+%c%z?^ zd$7hkEI1d3OuzOW0l5R?oH_LH*x-o=!tyap*N+8cRTlRA=qKMpvf@GRXOS1X# v^XED)8i{{z{Qt>~|KDNU{|B2#ij_K*Pl_HzQGb(?d@fzEI$wU)<>7w-CRlYT literal 10033 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 diff --git a/docs/developer-guide/img/grid-layout-autofit-portrait.png b/docs/developer-guide/img/grid-layout-autofit-portrait.png index 7e62c765a54bdf6ec48283bcef91d1ec283323bd..4404b3936a58ff839bec1e7b3a4241c0008d1c78 100644 GIT binary patch literal 11441 zcmeHtc{H2r*Eagoo>N6jNz~Y*Xlp)NLlMVO9gnH4sUfDK#)y_6F?6D>piYaL!s(f`E#c)iHL~)A^gnzvRnAeCsf^O5fPo3^QWz^#6TE@u`NfU;w!hb zmz!nO^++d|<2=Jb%dU4|xHxFPoT&J}_IVrz+Il#BJWaiQsO$ct)0s&IyVQBDQtee8 zq5TF1{bK!tblz2X>pkZyRwE@2@S^2mCUi5NZ=qU6DP10R_Jq1_m6pc#%d!je+(Q@! zn?R6v1-9dv#D}Zqbxk4_Sevr{x22|M5_GG#fL`UL*FRm)E9yVB0mge3IGZu&Phx}0 zv0Du}yQ6kL9SCLH^sZwhYqmlqdemPL3GbUI*!tU zG4|58n0>LQ#3pYh4 zTnGRVm+AGD5ojUD&1F6b7G=dXs|=(|tmGEuWqZbu^OCJKZ8vSTRQeOp~xg<=fU74Ee zGYJDr1lFl;ZG4YCF(cs2tbpIQg^eY2ti~|a&F&MCLThAk;5`B?V?n~$AHmrEBVwY| z!;~CN?{z>&G+FoIhsB?waT7Gn&>bHe~&N~^P!U}P6|VYlx8cA+VENfAQr5S%apU*;mACc3~Y5}HZa627KY@6rYOjQfFs0BYH4UkcHv7ad_=5`iiW$!pk6nX$)CV+i@$a( z)zhe`Rg;731;|(`MOILR0iU#Qjwi_8M!^jW^g4#Oc3M%!3^uW; zbmrSqUPgE3$7#5E>)LzwIgLZ_o@J5O)Sq)aoVncs}&EniapbUH{~8w{3~jE%;qo@=;Lihh&*4rWa_u86_AoJa9_Wt@paZZfav7^NaI5# z>^9~?HR%8~!8yE$yqWh$7JEANfBB)Z#0v``i#Ph*ptdnHwb;uB+2X)XceP8(UO_?! z&Tymd{3%L62hm?fx4&ubtJzdqWo*rKkPp2w+wSkelJ?^H&9;)m17H^c*=iHVt4#wh zE(IL%wQLob-v}W-za&=pUR&{@e#%(tL!%<+X%Dm7^K#P&%&6a39}!u`h|^)hkC2bI z1!#YkwaRnNuLS4Ic^eHbREhZAgAt+Y%btAGYuw)Dv@P>M-5z~PP(A#mV-oB=*q^s- zIqS8o_f0w;9-i>Nnc^@{1LQu2Cq7?|>r*XiEn9?GPQA% zqC|;dcp=|(ezeW(1~_CTb{RN~SmW7{%I>P1BCZQLs)5;%6(;9xaf~|y&rejmNj)dd zA(y!ZFgX(i{Iu?A$Eb+6Be##Y#BDYu2W2xM3nL-vd#V3&K*e8iI@$(&{AMUL^cV{? z8_YdE$(enWvoiFO#)NdYTzinxYp8j}zh^NF8`M6=d*JV>Aw?}4{#N?0QdY2cOKyoL zx$zxLiI=!_gX$B38cx4yH&aYO=#%{36Oqk29!?bFiSfz~`)R1QFw7i+nkvu-&Y4h1 zLmU`r{5FV{TtA`R#w^6WU`;xo1v?5DwMHR`M3}OAQOQaP&16~Q*g@}o_NtqGXX6Lo z4dBOTeTR<2pvEN+QZJMtH|lI9W0C8w4-6^6Dt(W|#}|*PvFyt_0e>Mg<+#Nci)H3d?Kq{f++3rf9_dHVEeM7a#x!{x^G?VI#BX^4EMHs^;%#mK_; z_ol2yW(F;Xt9G&YGIwsjt4u`RBaGEh;PppL9BIk$OJJ+#-^bcGyN|%Kvxn~;7Y8Ct zo%6E(bgt~o1hqWxp)J^og0_-^xF#^Auntzx3?(n0dm& zfeamLV0>I$M^a4aqt%zLg;vWqDk8UaLxM5ZvE(nXK#RDw9oW4g`GuZHmp8Qo`qeu7 z#&$>2Zr(vMagdC|R_m)={$`@?p^@kIZv;bq*U3>n%}n?SVSXM3-tx=1J$x6&fS}$u z<06BpZj&(wXV}Cbi(8JCw}$?zJe?)RA6uRS$u^R%ZmZB=+E|lvJDpISR z&oqImj$@S5WKC_2-^+aM1ZvMYUO-*E(PSWXhgvdIid;3>U|jnV68c1 z7Y0!4e&h?iJB&I)e3W)plmPV2Y6RvJowBr@{t!xA|?v^~p$d$PZN;gFbKKjJAF6r}~<5%s;gFtWK zQrRg-FQr8n)l{3$0c^NnMLG@f$*HX%IWoh@e)QnDFz=pzeC^76O4mQoWE;Njt=(TaTj{vl2I3xc^3w-2$AD}9z+DM60MKOc7zB~(}`?N3*| zg~G|%gMo?%F{e~B#P;bo#fNpAkY;RaA_lBJB{myWl1kBsC3kx!wRjw^`~+pa%ZO?x zR|)+x<-Hq_90o+#ytGgR<`}NrUNp#t=`0<0(i{o$g%*%TyWC`pw2h4+A5>0&<*NaX z_lj!mQ9dGQPAXX3%+o0LzTy=;a?jQ@;_Z)=MAt7>J!X@8)At&DN!<6!d%k@jRw9wt z-^Fc%6@(pHI1^GIh2Lu+MdpS9R2Ml_T?!wd=xWnueq|K)l60JN5(6UR=;mR3fLWA? zKxXp2hlW~|GPn#It~jwkbH=v+#5COK4DVLz*u~GuiUO;_y#!mb57NM02^LT{4*i3m z0X#wo_A~2*gdzLZ`)Z5be_a_Wal=%2Jt{!dM>8R#}}hjGBNs-MTeyBJvEAXp59ka zO1gYz}GiSKI8`z?RZ@;kymbFHBDCUy$1lVMa1Za9{!)bW z9V?v!De16_L7CE_x(*cc?)h;WkyL$Ptzy7@O|0kc^LLyiF&1Cu#MF$(gBa( z%2Yj_hI`(a`dh-wQiYU+_LjU#-^-pmVXs505v6hG>IJyy%CPQXUPk+bWFKogbEozmY3fp>?~ z<~86a(ydK+4i-|vaQp6r8zK&j-b`3{y7$AY5ahYimie!nYK>S#lV025Z*pe`gE?3R z=cBW|AH(3Qn9}dmh}@I_L;0?Sa%CZWY`pougrd3#o@z?p(#bPPuR zmC5XyDVUz{`6zDsukMWt@>_zQ6u)71kxf=*jp#j>C-+U=(3)sPey zKruG@dencv9PM72b@M|h$a^Fap8oSvr_IWIiCA8I_wC3dgN8#gfa1oV%b#)hSp@&n z!SMHsy(`MDt?J-vf7|-trBZr4sRfhGd>}JlZ?ZkVO?lGCv2?|iWM^plRDSs~_qY$g z&ZSx6vrTHf$kT2)h?2i=$<6Gk-1=jKdA;X68~ucMqn$3>+ijnVxWF)DpZ;|{8adL1 z=}j=B<%~~-EDsuoQXYj(SDS&We5|84`NN1!AN%p@@cVaT^|uIh(3QCfU(9*L+&cVn z($)lv&@^eDb;LOdil1eS&)TKd`se5P^E_}43^T-na@q1xFM$Hh;(2yP&Ry>=xe-uQZ4wI17ELq^;*e&ZX`M!5&>$*r8= zZ$&#CZHuoQ*CJziiPrq}SzAD$SMFvOeI1Sj@iyY|gT{=pDR9|6ip+ck$`F5>KO05CtI5X;S5b6KYMv@ zyN=tY>ho=Pj_qIHi3oo!5#rFB?|E7`(EqI@3&TR0P7i`ySPiGg67F9+3 z$&Cp;XBeg=)43afuoSQM>GpF#bG}SaK0$w7cUeYsw9X+7cXN2+c;cQ~Gv)a9yIN0d zL=3%jYPX=1R=mluqL8CqK-bd2%TrX8zaTf?>alXd(r3wxMCd%bH&(^uGi*FfJ6xx> zPu?qA*>TdKH{?rFZZ+8$_A7sk0F3D!?w z^d6OX-bXGvFe}{n-{~R4!-x*Q6V`a6-=HUT@NV!fi>YwL7DTwwBYUglvK-<)_a9J9AF2a!N{&O$Ayksj_uGS9QB(@|Wyz$W_qx14WS2pseCPk{wow z-3-J3UKZXql6C^MrgNY8=W0x7gt)8D+h?D#zBmU@OKgAh`2Jtl6Ubqrgr>@XJySOw za|?|Hb!)5P4Y&mTooezBHCB9|VR>Ke!ZJ0HAEOJMM_)?%oPy!4+)p|6ILB^qI$}Zb z&?`*3M5NA9RLx%BSb_=CB6|L|QD1CcAvOb-8j=lp3`Q+=xp|hw`o8~1jWwFu4VIk6 zuRRmSG&G`%O0&9|z~$`0@Vpt=*@^nw{~1q@1lYj!cXO%w`l`%m@)A3edF3~!q+u6_ zK6q-r`_#ptK#hZ>Q_g8N?`9((&D=_p{z3^)nM9sr0TMZ>6W=}yEB#(|CZCQj%0hIC z8zy<;)be7rAvab-)?y#(=N2FB`iR<4p-*CKjg5hXo;SCj*2lDr>{hao6L+fbqK?1_ zrcNECL*H8^86r1xt`9>F!%+Hgmmi!KWkv3*8o%(1fR&M$Kj3NAP*ABhxVsw?P_XZ{ zJzh)Rdj#LQiBXg?q@H$!$s8GMukQovAufU(3d)b(U;U#MVwCzhCB`z~o*@Cy>4R8x zGf`aGT4L&}LZgl2%D*GWS)yv^UOgWUdIPD_u-8$16m{JO?@QfVn&RfOD5U1DiP(r8^N&A`#4_QrN`-j~dX z&6qfN82ad!+tJ-3XD5<~2{ZJy)dZC7f%z>LtOyS$JP+ur;+#QkihBS|;g_QIp{|^4 zt{3E6&Kz|_<~8J~<+RMax`g$v$vhmz|<;ZA=;al>@*HQ}CNJ@(d75qJ)-)X#Y; zRCvPTopsxOlsZzB&}cKM=)NDG(D@+C#EUgg?}Nvi;iZn>msKAL87M`Zfh8O1HN;G5 zV9K`awz3VN{*!F*ex}iMH-O3ajs7~25a`kje#0p2BQ>k4KUDz-G`oYQR>&WHYhK)AGD!$a9>F<@6Z`yjPI ze6wf z19Yj7iOp#-7W9;7y5Yj2!gAB1waz{9-3WhduxuI>9a*Z@%k~GfmiwT?jb~Q2NUc_Q z&q@WDwwv{j2JS3jK&J_z_xnL{pgj9EfpH2pYIxzWG5;|QJsI&8yz!o#uEWekNyJd& zPT3C&dvi1@lJ~J(b&gFUWNlZQ0NMS72gUl6+?@c_# zE8)f$6@XB4N&qhaTddo5n52(yoy$2pStGCY$~Qv|;>W1RazhCJ#MG{mgg&+dCDJVi zIL)Q(7cSBxP2W3MnMaZjKKuLRRUGEfJ{f%ODOmD>grmpL<epJsV{N#zCS+RpTLI$080w((Krx{`Y{TZA8$#p|->*>?Vky!q& zkg#pqJqF+&-1N|{Y`O8$in1EE=X&c^6_uFbTjNjUF4t_3Nr8&>(D#EL5dmR&0aCu) zhO+aI(egj!l(*o>A)MC8yeoXaqMFaNL$iC4RzK(;B>lE_A~&Y?p9u z4#JRVJA*D43D9q9%uWgJ!+YB0eX9`BcfWaF*TEVq`N)7-f`b%|&=ePb`6Fy+OR~9Q z$W1c`VmfYVj6UcL57Gu;uG*K-T!li2FLTjYYsn7Z(kJsdtt zi;DB)sXwUc~6C;=|^`xOH7fKixJp)(L8L zs=VhDtF!$8KTmN?D`$lJo$DjF7k4+tlURI%Wh0YB%^hOxuia3oQ`-TxY+-?#vxI@2 zDklbrb2=Y5^yg4ZULi~S6HJ(JuHR=_O$+Pj@8#1f=dEpDaKqP(s1?pR&5b$u(T^Ax znroTRPE~vuj#p%B*H+8VC`b&xM@O1`3JWEGeQY$hm+${(~8yfGLNaiMOl>a(GrOdFFMr(jKsPoF3qR7&%UF>DElAYL`cS1pU{Ymf3t`54iRGCQu zVQW2vFdGW7o~$^K({*s&*`%&fV&)<|{+Rifd7By`$0+bpcli(`ipH*#N9J*IUp2m> zN9DBW5qDRM%FJ)oK%h5{^Gm`9N%6kx=+sr#wtG7oCMnVacQOT9&P+ zHp;No#qB#}nf@uZWZnu_7e=e6|C1&?XH{Ltjzt9K!$SuJ>Gl!^7HjqDeTctu!XbI_ zoF-{nhP3bZ9wAIuxj69ncTfxsi`C(N&IrPXZ9nIypR?uv_ksDCaFq8;mIM?V23&`U g9`Z}h7D)fbb)~xx)Vd2_MHV@4Yk#`(Pw(6R0cW9sL;wH) literal 10691 zcmeHtc{CgN+COGGZndRzTa2Q*%v4oTwa3<0m+7sg9VIk^HkXtLB_xQT?I^W&s&=8e z*ppaei9}n)jM$YRLT!mkA~Yn3#2d5R``&xb?|07o{_*~E=MU%P@O+==^K9Sm=XvDu zb;m3F6b>oK$jI!w`u)WpWMpK|Nq;{6uehNRSV7xOz+l(P!-MC_oopk2x=|NQtk=BN++>VP*~c*Vwye8Bf)jA1N0U!E zfBE3a{wF%$9^HNa+`A{|zB(J72WmU-v_7g1O&onXiKf|0a8E z=2eDN@G84e_s#yE4*%}3<9BQTIE7`0lG8eldBmD*ix}r%S{J;%xrda9B?%6y6FH}r zz+|$A#2~9uKh=U=F!NEVmz`^CZ)dDt(dH?vqQxJeZli|BZ}5KF&Tb;Y_DbGXKW8h@ zXl}7Q3y9x}$g<(fip8E(a(npOHFlC&VI-8c`RI0nFC=V~eOR!0ZzlXra6^Xr{-b%s zC4I%Ma})a#Rux4K}Ek+Mn4L zdRYYrU9}Ot+>;2z1P8Bt(wYS3qZ!S2_(aA_=BH)^YP1jYyBUS;jwMj-OFmCGkUsjm z9f)-nUT&-7l2S@!70-*1|scXgAvgWq{vJVnbpf?hu4Rt7 z4=cYhHk{5&zWLt{_IOFYXBpalHi$823afbxx;s)tP7Ce1DourG+^z4mb1X8TuR+4G z$HR-+A8+4U`-03Q@J>?J*e>(xe_wlqonMOOo?6YNT_Yv4I)Qk-rRaO;>M+sL9WfK! zJ|oi7aa!H#OV3L7V>l?HF-zO)?`CESd(l;m0)az&Ik{CEP39!e3}(=~Ak|t7QRnI_ zNDw<$^-uw0TjYi3bmeW)Yk{H6$wriQZoDK*sn>wAJS$4N7BqJKv=^B?S_4OwiRm`? zY`1yBhUU;y7i$4|%+-gznn{AgC{Fgq`R#}i;qwE`j8;`vSPbF{Z319tTv6-iXuIHH zGS8lRHKg;Vb*n)H*waTBU3qoj5j+7Kz99&5&4?=*t!a*Eb{rlNwUNJ5T^iBN95YEa zHN8kPNoez&vUDU>WY^#0m#&QjZ;xxXgD5v+bOz;HtwU5o+S@F<(r*EZyE-*Z8X8$e zTx=6%m-Bo{^u3^!<>G;?$eXu2lWlF*Ch;3ZM{|eAj7zjam)y2`+baNU@rH>~T32)g zw+-7pnGR^^-QTkqkUOLVFf(5J4eqB}TA0eXI~aQ=z^>SHJn9z*h84KPA7lp~U_ECa zdY{dPJ%p=`WIR_cP%ebTl|ss+rgBgy=BPRi4;?aO()7QoRGmEFSUM+Es-Sc4fuf!a@ zG+@fW9=e<4zBT{&o-Vz8*q40cJ^LE&ro;)Ye~4P3QPDpXZ8-rCxN$_YHGfgZ62vyFDp_T-yF9?he- z{pQ-*JXJAi^le4kXPlt(v>QGNzG1|iAz%B9rWT0<04ujQW(BDN)ZPnvy_9x!-#|B} zYlVMVe244SmJTD{4A^s-fHn@DI3g`zft8n_=@OXgqPy{(QUKcu$p~CLs^xjzss=K* z9;>N4Y*=I<>3(-33)Zr1pn^=Pt^qd%&XJ9U1-KNRw&;k0ZIo824reE)MkPJjxBcQX zHRu-xC$^Y`%f$TN!l9+>(*FDvU2?O5=XP}e+QKGa*Ef=*AGjl>@O}#y1e`rvZ32q& zPw)*4zue=QToPTn0k}+0R6sfG)ijcprk5>+t#uh$!dZUATylCKx{=qBgUlakS})!Q zZrYe8gN9SF*%1hw8?aM*ssdqG;SYPua$&8;J?y;$-B?rDocCv7alK_*#OCTxjPrK<^BRK9%>m*A zO_AK59tN<`IK*|3@^PlAur#`De3NtSj0VZcqcgj;(RU6N<4VOv8l9%q#+Yr+#j3q< z$HJL)YDRmxjm?N5a8JB?K*cY92rCw zXoBw&R`)V;o70%hbU7?&xc0z=Mj&ZPFJGGeLkrC2!+E%~0B(gmfEmgOByq0LzK-nS z9#@@?uJ@&J(x%869?B5|}097Jk6&j(Cx&RbgYm%^Wus{T=2)A{Ykp*%Fh``)0_ zW&LLqNoo(c>Co?(UouxW%|6{M`0^9$(5s#HIW&aK0++V3oJAJaDL(@`F4!Q6L%n$jV+b6J&vIR!4ITGq5+C$?p#{Fj(LWVVd4nZOB{^>disO|GqGbdE8{;>)AMO9Xt1nh|E8IV zd?Q^N7F$SpfKkw~K-qC+{!w5r-AyF}j-$JKSzcE4biGX~J=$!u79@fEy@4wD>fLFp zVt>?!g^B)rqRhB7)4r9Hno*5=A7IRfHABw)yKm#Zk>QW+2t7+D?2Oq^`wTcUu2W`e zIfkzJMcuV?7k+ikU}Cd^^y9G)_}6;}JnEGam+dDkokVSynu(UaBzP|j?QtBiV0eV& zO)mp{b#U^#555%?uKX>jlZIPO9Tyn8xW109d2WOl>HE2mym|IVuc=1L0S_egQHK-u zpLR)nfr}&;xS_E`~l-IL`#=y4O$VW_gx-`LR~uTEA&F%kKJ!lS6(^U~ z^jMJy{nfQ}q#ZGJcRj99o;Hus^lnrhVKam2$|JLJ(&uMe()5$T`zl;wRy1;;)PP-Q z=@**nkD{3i;x}4yss0zdmdoPib2!DF)j{6}bCM!VfVeky#wae;F#mRpCOMi*2KzmS z7+bsT%3EBGsHVF!q$2*b_DQJp}+16{80gQk#$y??xQd;0XHh{GUapH71Az^ zX2OSu=ZnGoyHhud78=iMFgM@LevfQ%M9>sZu(!uji)I)1@)CD%S8*mkG*8_wo!oto z%>Yq_Kc*t!Nj{S`KN)o+wa*Q!8f}S`VE{-V2@0F7FGtcdUO+rZ$v>;Hhn4)puVrgy z4z#39>%Yc1A&g3<94cwH7i-UlHY@ZK4|D8Y60k1y2Ilo5C+<6UQhj^$^&!Vkbc4<% zN|ohq&f?mBaI4MzVnY`q77DGgw|#SdudO|YB7IB0 zIsBk%%`cECAU$5$jK6D|;0Tn>b$zg{!AVzofSIBdiXm$Zx#6cN!2@!tht!aCPOM2rPUUD2mCB`ICScFBcK352MW=4;RQA-g6i zXNFoAs->(Xmjf-pY>Mylmd+2wwPm_*v`cK>obO*7TMLiutGVNK-zVO1lf3uD&DN`| z7nwACSsHX4J*d&x(j2J+;d&;6~G?NJ&0k9p0U} zoV0Pt&jGY4%2l5yg;O>sxdk8+anSKmoOXU>56)<798G^Z*rL@&-_H%tVFsqQ=G`Vs z#8$rQSl3+%>DMer*f+uHappH($y8H8nW_01wN61jUu!2GJd!%72r)-a1?BNx+G!Ae zh;{S7B#fa%3QPACwxUlji|Wwb>!DTREkoqO=( zx3p^ZQEqt@iAms^EgVTj{XZu^-G7dVX$tt5T{77>ugA)q@%wb}qn7w{+J0e9A~V4- z?BqH77cVUC*lQ~6PcOZj`i*nE-1~1&dTbmA4H^$!6PP1TK%S-zO8jVB%k*NIum}TrteML10?P|ySF-xxolBbS4ZL;a zN+Q+shDPY*`S$caOvuVil9xw|2*uNxo9p*Di&-Vhw%T-qUd1jO6%Nq_3 z@vxo~t@DyQq9txS-kJoMm8=fh>O~{_`V!~!va-h7=vw-LAQWgtY}xA7viKPoh9f9q zwjMu!5uq4JC*z_5ok$=3!0zf=sNUJczKN}znQ<4I3ao*khkC6wx_NFT$*1+CXT*js zse|O&sLhD{A(*kq?h+iNvZJR{e?J#Hy5!PZc|4yf!rivjqV#HjZ;GnVk*IPoG zN;EDz?sNFn*#bld7aA(zj>;m``6D?&+%4JRB6fwHR?M-|y9Eysv>v@eIy6WU z034x0!K;;@+wiGaG*U&YY5F*r?-{z1)CEa&SjeY!hdWgJ(@$xROcz}_d}!@H8-RRK zlKMI?Gqck=46od%?5R2Bwwlu08WyMsIOv_?z`uZxTrQtk)>Sf4N{)vFMz1r^wnnwj zx3hg)@Znt%PCA_}oWU&R!gaBBS4$wdIqF!s6p;X+=ITlumK5tw-n0_rcOp}qwGh1! z0HGBwCbM#d2m4wUa@r3R+ZKg?`p!U)g6KpgGSJ8@HfF=efY*(lS=Cm#W~#5l(wnSm zwAu{;6{ZzR)@Q!UYI(K3uun@b@D_Tgw6i9p2KTqw%=jRk$%r*es^0fQ#Ko5PJbH*% z@W%-G)LivDpul)=uv_r*hI|$Xqup&$cXlp{bBDboi`^!9nGDx;>Wt>p(<$wf(87U^{isZR| zyhX9*tPv;tPUA#hs+NhU6mPLqP1B^ixB6Nv*yqZ9m?sD1vK9h^N@H@>k=MtOaa`vq z;n#$_#X9kYRI2wukk4##=!OI>O?dLvK5|>-H(9l4%W%-yY_*(X=Qoi z&T1{qTl;EcPeeyt-^tF=&9?d8=pg|+_a)?=54?aiWDpfOKj9I2^39<jn%|TU@Gr$<9eQm769H7b3?$`_1!PKfl$rq;f|+Z5LXa8O&2S4|Gp8oYq<}{8WK;RA9=_AFas0}|kLi^=<|!1nC^z2C{P64I{|Mbuc=VgQ5@lrlUml6 z+PT2Jj=b|q0W7?DeZWed?hOrXZCs#!R9P@=fnzTF++%62=x@ohh!cr(lzaK)f?phkFgH?v6 zVqGlZ62Ez^)RZ8;`K-$&zDATJsKBe>7hC9t#XOt1_>;@L+I7oGD2Q#_$d=D&pBY!d zauw-@MwY?egffOvAV`9|`V8z}2o!Rk`PD$l~?b?2CVj{71zFEBB>LcEGQ*LXnKD_uvIt zxi_!k(vSRE2!A%n@3(?|f}F;)^00+wx_M@kxRG!e>LsO?FX00bvy8{<2#bTyEA42E zj_Pi1CuYrDbU}LC!IOHaW2SvgJ=rV8Mn@H@dZVL>(H-TG9D15)F<1~MJH~?pw+ERW>WoBBn8jw)LusYe@gAYyuaLi+(#?c>x-tdpMy|alC(&FqX~bmG z#kg;v+KQ&5>Zn7ZEU??T>>vYE-h@ZMAEX`rT%c1RE@l4D+Tg;{gYsCtG9Q ze!|A+UNh6vQv~pyk2f`2b@w)klY3jS*68io*_}CoYUc7giC#18c)8>10s_;MOgmUX z#3@9N4_K}KY}a0)ALBx^x{}qPHv56hi@Z^fKQA#287`9Xsk{vW|AVv^2K)OMfQt?pK>^y<&BkUH&aV_qA+T6YCC&r}T(-?8wOY;OF@=XD!wGvm}% zkRz`*!fy^(U7R_QNn1Cuat ziw?zSFs6<8T?y(BmGTjIrJ$I`{Gruxo7s2JXAll%zkU!uJnY}~2@HvW_KeS-IV411 zZ%DUfNWklw=*;J5yRr`%oRX5`BYnetjl>8z_YVb&nHBJkeK31RDdW<)s@e@0pVxoY7&_~?8puDgYRq1dO`h>M8C5>zBut#2fa`d>t zj(Gg`b($5QMUD0pBz`id(ndj3^wVaTL&;?DGuO1j;%uN?%X)FW`CbYBXt z#q`WYR@#-{wENSjxQXVPeAMi?I*hPV2ivs@E5Jefd(Qi8hSp(2MoHg-2SHk?Sw*q$kMdr-d^MBGaxi4d{?$JJf z=CO>$IVpFS4T+VmapmS@q=f#8fLdx>LJ|Zt&_#Qi_xWnsXHJ(dXyni0} z-$v=av^n8rc_mc4wEVEY2Xo6|N&75K5AG~KY3u!_?81ee1h|E6bHb>MmryOu?!!er z6GX^~W*Lh!Ittgbgf+AlHqFC}Ipwj{bEhlLInh=!uhmdMM|NLSm1gRV>_iRhTGQkg zeU??aFn%_?!#;E;vl?%T*GzrH$vM9nxXoy(zFvP=B>ew!ANGp&)16$qx|s!?zKLT= z_q6iIFV}_+4bD90D=tPV9=Nnq5V{-_f=*CZXtE(>K6$1}S5a5dX8U7E1@A`-?Sn8P zL8sP8wP4Hy^+H-u=`UpR`Yoodz>_DWC%XUr>32A|12!PLgi4>2j@uTiPwhx&`A?D* zbr6>H%CU>mVmxt4cJZ^PAeZ*c%m?7x>L&{G0bI^<`t@LC6|JSXMMqtby>fb|V3mIp zYddUIuuEFfRqs6cxu1&zMj;)wzxp)_^K{;M%g$PUocN--#*{Bo`|pw)Y*yCT4wcY* zTf8AoR_psUIkyQB4jW~BNABEFI7?{cYqdw(C*E;nrpdg>iQZ~1o!Q%;rd;bnqboXG z^_->u$d#UZ^P~Q`Zs4Eo^M8EF+;^0fld(5Fc}^y~ZY#$9lh3)uA2scyU(S@dddcx3 J{(|>|{{p1=v$FsI diff --git a/docs/developer-guide/img/gridbag-layout.png b/docs/developer-guide/img/gridbag-layout.png index e9c6b977d5f69b4673345a7b275ca1f413ce2d07..651217b3dedf9498f2b55a94b19eac113e34efab 100644 GIT binary patch literal 10780 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 b<=K=}MryJQe)*J?8 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 JLEdnB^dB2KaE$-} literal 10810 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 KXqVl76!C8p6&URR diff --git a/docs/developer-guide/img/group-layout.png b/docs/developer-guide/img/group-layout.png index 9a886156db265d90dc474a1dfa8a37b993583f55..c1f087123cab6d9ff88c65f686e770e15ef4ee8b 100644 GIT binary patch literal 11976 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 literal 11908 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 diff --git a/docs/developer-guide/img/guibuilder-2-insets-1.png b/docs/developer-guide/img/guibuilder-2-insets-1.png index 179a9cebcea5c28e4522e3d1863af1bfafd3748a..257fd9e0448e913e39215ec534be4a5a11bcd912 100644 GIT binary patch literal 6070 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 beH#chCw6icMyqA-@c>7A7rXjj0&o2X`j{i8 literal 6196 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 Q4bbp9n+a diff --git a/docs/developer-guide/img/guibuilder-2-insets-2.png b/docs/developer-guide/img/guibuilder-2-insets-2.png index e3051918c76d6afb877106018a83b70ff883b92c..939d38580afeeb0c5d55798a4842385c8eb01c05 100644 GIT binary patch literal 5955 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 literal 6057 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 diff --git a/docs/developer-guide/img/guibuilder-2-insets-3.png b/docs/developer-guide/img/guibuilder-2-insets-3.png index 3aa0bfbf4786b7d45602a6a857289bd7eb0b3a73..a200270d4b40f2a0bb6d73fc34c05883b086799b 100644 GIT binary patch literal 7092 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 literal 7263 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 DMD}`8 diff --git a/docs/developer-guide/img/layered-layout.png b/docs/developer-guide/img/layered-layout.png index af04164ae341dc115a4ed14f487a253dfd326565..2c8aa052ecd52d93870dc33a7b472f5f58ccadc0 100644 GIT binary patch literal 6627 zcmeHsX*e5LxPRzqr%c-^N-d?+g({+|v5c*YE?Sk+*3t+{HKW#8qLyGfEw!f8Dq4{! zN{d8ei4YM}B2(I=wG$Dfv4kXo5R_aq^Z(!HxgYLxpZno{n-Ay9Iqx~|@BH51dEfVW zPTDo+i@Ovx6#)RiF2_p_t^k1C>8&yL{r0Vy-po1&06?R{(c#RE``!X}%*c^w!*6|XsTU--x9MP9;K zfxBDC#my*xrsbh{Yo#(km&M2QO5#f9VI_Uu!bp$2QMo_m$&iCwXLG3+M)BI@;jM9$ zw{Rm_$;8J>Jd7XM%%E2bG+-kofBNepk{2pAzz$W@Fr@e421;3w!$AlD;vH+A`C$6ZmU*&Qx(% zgCw(uQG63Z?mz|RaZjzXP`EcO$hDMveIQn)z#8EWAqpyFqvsN9TGrN4)zcc(571@n z>L8s0qOeL=_AJH(mu(m1A1x?5AX(Zi9i5(nPCAMpw>Cruv;3KnaIWwkH@C2lnd|LC zS_jrA*S)Qa==5doft{aCP z_-YzPCI#79#|VTPty=TK&5%%^|1FcyI3fwUgwAU z_*GhWd$jb*;LN;24k)Vz(AF;?ccxafF{gp8E+5H`IULOXRC#T> zWTM)xrnzY|Wi-I@l98xfkmSgWQuURU8nq7A2eM4-A1yt4Ya#5hPjI9JEq(*zsu&(4 zWYAK%2s#WZ1Z%^i2j+e7gTq@8z`&6akoQNbtqmfK;W58zUZZtR#0ivL~Rvol~KFax`f7U(q}t z99T^Wy*Oa$5>DW)R+vEDD3i%u71f*b!)u^W2sIWav6e;M9;mx;GdU(nT+FwtCKWk* zrof%vX_!xMix_!Y1K{qz%ql1w{mQd+`C$q-2TYM!PQJv${RYZZ$shq-Xj^|WhvyXXK>=}`^L`b<0>)p!lRN-Er`{6og2gDlXXOQ z@l~9`%|6ieuu;ogH|N=E`=(~Qls@x+uxqn|AhqKi82F*26B12&5L=Bb7QnZV3M_X< zDBaC5jMH{XTvZQcgf*AS%KK9HKzl$;ZXz7Yw6yo>r*tjhWu9!1jon)o!#fcwz{x`8d&;HL*?4ZvN%C;=3eQwK1o~j%u$_5OXlVfSv|zCt`s^-5?vra6M&X zmJQj5Leih&$7jt2Z-mls!fmsHWfkcUvVI{A|CQPJF_sz8fOtFC{~hshjT?`Cx`@^-I&5rHAV2 z#-RTGu=CV`E@rifdSJWT=WX7R*Jnl~y6VvfTC<-68AKx12R~iAk6iev?k*&`1RWDR zUMGpi4IAW5S?(LNtWw7wCq6-~4Rv5*bJCtcLPXZm$!8{8m+V#>tKEu8i?+Y{8gBac zl63H*bO}Z0s*nWjkzv40J$QsK(9gZ{MSrkTc+TSHbW9WYU>&$_=}Myw{WX9dKzYn1 zhWv)#6Rhv-RZrWAzMC&Uhs{ygZ|EDFaMTXxZ^3)lW8O<|It2d&VHNG8c)bEs#>&JK zb1+CS{5ccJlreA*{ght+KL^?VSt0Q8C@U(WlV`Q166e|T=$Vl9?k5=oJ8boVj`vaw zwkUE>Cd6OIn6CGu1_offPB<*0N?)1YGy%-GPvM=^Mm0n<-B2ijBT9L^{EJ*xP} zPH;boJ?(!TVkg$SKYPZ#SDl#4eYoJ)cajI)mvx)dqMQaEA$3xt)+UT48^!C$yEi4n z+e|9m2N$F+>*iIq2CZ8;NSOn;-V!PfIVm2o+@@L0+>_Y&c68%-Rs}#mkn-5LuBL8c z%95<59&)kx;RGm@9LLR$Ys~G*xDt37US;l`I#`iq+_cb7zCe{XGC`*EG-+B%VcKm* zbY1!uVl<8u#6GKP_!;vUJhrfMPak2nMmf`2Je^0nY20%1p1E_QZ)Eh;M(F5+!DsT? zea!_qD}U^EZE-F+-a4eYBAL*&Ypj6<#pYXI%WB96BRsk+=DZe#=FFH zQv;{=1u1qXEAnmlX3-Dh#1XM^18lEUh)W#Y# zWO}dCMuUjMY3u$hzkuWP7eMh&9nQjDdbZyt{IoS={`?u5MTLXsb7tDd*MO;?MJK@t z%&R_+H6a(_h}gE?IzLSjW|*Dc1?v>O*GiQSKAFAs;l;4u90krqpH1g${wniJ!k?XTt} z2h3@I5LOU)`_DV{I8%&E@?ob0+Z*ewJZ=}L3x33>N}a2vU|HNA`b7+j@!76ShjfaM zxNprKP_RsG&qHo@y$a%2ZglEZs2 zM=D!8ez^68dy5p|^+9Ep_C8G>eQtR}Hd{LZi1C^fZ$#p?;;3a`A4~kk|Hn4B;kZfv zcYmIhlMjqmobOK^xz%CAtwH;`9&1&|fqOciFi;(n?<5)N=c_7)%LRDlsyHbskdjXV zyLRe5lJ`2Tk;nV)*;zSYQD#@f14n|p(mX10{$k%$ZUTPo+f!zYvOS&4Bb`Jp_eZ=8 z@pYZ+leh65k`u&6Yrk7c#=ryC9xf18zjsQf+)CERTM=xlvsL=hpUv=2*lTv?y1)K) zVmL4NInI+EOq<+i%XPko37=4@sJE!X^@sWR*h;>ZFaLnOdUn-=`b|inLPA)LxWzcx zC-7z&41Kp*3&H-ZA+oYhbY@y^$UpOAC`b)cH!n*{Did!UK+?YS)jA{HHWuwJ3a=wW zRtGBB*JVp8DBZe=BEH>4cDar{MxBY8X=n0mw)1|X+m^1qe`<0=J+%4VaEO;{=(rn9l|vevt&Uee7Ra8IDD z^_@$qpK7fAG&IW;IxR9djf+(&_L~ps?(U(Knx;5bUtf#9fVDU>bR-A0t5dLtjI599 z>1K!|o99I$&CR^>Zvn7DiFI|gPWZ=dab>2*P8dwyNM4Z&ZTW1nOZp5gsw=j>R`g*V zK?HI+betVNZmLmKHF|$pt8!c30gn)NW4###Y`l4cxdi_23_?#eZ^j zhs9@Aue`3j?=Zri^+-7lYfq8(@ZLb3 zDQmrad@83NhPgVNH;_Xoz8slh#Z(9rrR>?dhVWvNeq<#ju}Cu<$8N2UY!u1 zfjn?|*;7cmKN`rK&D5m>sEzyr$%mAP=9BQb${}b7!+|=sq<*7%V>O6;+0^-6yObb_ zl9h;j!VJuH;zrKR(kH6;QEmR3W(KW=6(wS}q^lEy_l@Z_M4a<<_f^+g|58Ta6Ya%)LiF2Uj=b+r^7vJ92NU zI&oFhk;OqCIcI7s_dn{_F=v~$+-`%pCW~*?VHbS5>?+x2Ld6i*06#om4L1jNgX*!85plA9Fe|ZlMW+vxxK0{F zqME{(OW9Clu&ohsw+JC+|BTvWNSaAumIC~*)NG)4=&p}3-YrATUZGcZZA5pN>g(M4Xgb(RAv5itQ+Zasy&Xi?^FTDBNI*5_BpP5>2 z;XS)J&*U?q(;Xk&3rAvYauzX;b`gJE{JAHH^HWWE!;$x;`Pbz-2u*{}=U`xzT!$%b zCR=WI*LCN(%L8=-!O$M7oyxET7~hnW?e*slK~=2)V*+ zLmeZ2kC}2(&sUB2N`@mMJ`Z(u6xFthr6<}L@^laqyf*%f|HJU33}{P0L2h)}K(K$1Z$Ijsf2!wi$XJnlut~{XrFEV?GIoj}P2RtBYmcH+x-GDE$ZN-b zavR*~#HQ^pUDY9j(a8b`DMj$U-UKiz%G}BU43GE=Q-ncRBdpo6f8cs1n^0c}d;dL?e~3TJG^ z?fU&F>g-5Nw2pNU+f$P3x7sZ2?yqSdro}Q33x~|8x7(&F0o<^(t#%at79212PnsWO zfPNK=q>bo~qSn6&Ry!Z;nc3|mRLEXW)FRYNaW^>?VWM;>d4tKJ&fcM~YB5C#ZBD9? zc#o0Tz3MwwN&#BskC&XIaOCSzh+pwJx%FhS9N#XG71aL zb`yCs?no0A+X_N(4TH zeS5>ENuLpeD{>w4@dsk7=29(c|n4dSBv~1nCMS{$0qgT`2h9bQFM+*MNZjUmd>~oK6l_J@_P7{=071Mt6ecT zeb89p`_k8dU+ex|{Fj7(mGJL#_%|o~UnEA^4(+t`=Pv*{;ai_K0LSyr4*0Xa5B>uK C?~&yI literal 6849 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 Pio?tZYFK&o#=U<5h}gtC diff --git a/docs/developer-guide/img/layered-layout.tolerance b/docs/developer-guide/img/layered-layout.tolerance new file mode 100644 index 00000000000..4f1e24ed098 --- /dev/null +++ b/docs/developer-guide/img/layered-layout.tolerance @@ -0,0 +1,15 @@ +# This figure contains a FontImage material glyph. Measured against the CI +# runner's own output, the glyph lands at exactly the same size and position -- +# a 55x49 bounding box at the same origin -- and differs only in antialiased +# edge coverage: 946 fully-white pixels against 916, 173 differing pixels in +# total, 0.113% of the image. Java2D rasterizes the same glyph from the same +# bundled font at the same size slightly differently on macOS and Linux. +# +# The two bounds are independent and both bind. maxMismatchPercent limits how +# much of the image may change AT ALL -- every differing pixel counts, not only +# those past the delta -- so a wholesale recolour cannot slip through by moving +# each channel a little at a time. maxChannelDelta then caps how far any single +# pixel may move: 160 clears the measured worst of 141 with room, while a solid +# overwrite still fails on it. +maxChannelDelta=160 +maxMismatchPercent=0.3 diff --git a/docs/developer-guide/img/mig-layout.png b/docs/developer-guide/img/mig-layout.png index 910e722133cfb6bdb5cc755add707ad22f0e5b74..4f57360b62f2a6b4d68cbd5f7dea82c5cc5c974c 100644 GIT binary patch literal 10699 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 Ou3t5{Qmknc^1lGvWj4M5 literal 10475 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 diff --git a/docs/developer-guide/img/table-layout-constraints.png b/docs/developer-guide/img/table-layout-constraints.png index c9afd65acc6eb590b9510eefab33232d1622d20f..8ef75925dd6e2ca3f2cc827380e0c937a122e9e2 100644 GIT binary patch literal 13573 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 literal 13418 zcmeHuXH-+$+Ag4gQZ4kl*=_}tj?&9kR8$ZID=jnuDS-ge37|BUWbu+#ig^NYm4mZ{m`(!1T;gH)xwA4g<(yiGR0Vgb@`Kl=Tj;F}S- z$>tw8-m%C5*IU2y+sWo8m$MWw839-RYpi#!$mSMBoNO|`BJ0F@gEk5>TWp@@>>pIhCu>8 z=Isqc{tb$J^yT1U*PG;L@ozXvxz2csJ~u~YnPY4CPRv*3-9#CxJUQ8<(q9X{bY(sG z%9%;?)VD+Fx7H=PWeS)u*Ji4vWCuvHKMeV6a`}#!ucv6?ceCb^pSd#1nr{^2-KtM} zs*)B&ut@%ltNG8W^03*08Bj0y7ZMEXfgoCeiK&fL8?c_Gr5CZ`{p;=?+Y!4_=pArx z_`O6giIE<)Ng2?3zYb-K>SStr!)vf;?`wb+Y9|1$gy=h=^dBl z5a0Kjb1Co9VMT(y54lJ$c*kz%ney8SyBVno!St1fxU%cYMsyzDu|&07f1B$>2bF@T z^-4F$E49-vy&hMZ+ znQsNMNOf&MI>(I=W9~K5vh>qE1d80c)=*2PaiL&%;|9s$dc|wyKD9>+OSX@e1Hom8 z#@mW;R^dTu$y$VQHe*9lJe0n%hFIH+24oR!w~9QezCy#1GeN9am@1VW*Q+jCLk7

4HuILtMB{Z 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 diff --git a/docs/developer-guide/img/table-layout-enclose.png b/docs/developer-guide/img/table-layout-enclose.png index 0bce1e15513c54a256425cb9e502a90654f6ac46..90eb64903a39db06616e671d4ddc08540b2f4e7e 100644 GIT binary patch literal 10008 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 literal 9718 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 Ix^e&i0RL!B&j0`b diff --git a/scripts/developer-guide/compare-screenshots.py b/scripts/developer-guide/compare-screenshots.py new file mode 100755 index 00000000000..a57efcaca40 --- /dev/null +++ b/scripts/developer-guide/compare-screenshots.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python3 +"""Compare generated guide figures against the committed ones. + +Byte equality is the default and is what nearly every figure achieves: with the +font loaded from the port's bundled Roboto and MigLayout's platform pinned, 23 of +the 24 render identically on macOS and on the Linux runner. + +The exception is a figure containing a `FontImage` material glyph. Measured +against the runner's own output, the glyph lands at exactly the same size and +position -- a 55x49 bounding box at the same origin -- and differs only in +antialiased edge coverage, 946 fully-white pixels against 916. That is Java2D +rasterizing the same glyph from the same font at the same size slightly +differently on the two platforms, and no amount of pinning on our side changes +it. Demanding byte equality there would mean either deleting legitimate content +from the figure or carrying a permanently red check. + +So a figure may carry a `.tolerance` sidecar, in the same key=value shape +the CN1SS screenshot suites already use, and only then is a bounded difference +accepted. Everything without a sidecar must still match exactly. + +The two bounds are applied independently, which is where this differs from the +CN1SS comparator: `maxMismatchPercent` limits how much of the image may change at +all, and `maxChannelDelta` caps how far any single pixel may move. Counting only +the pixels that exceed the delta would let an unlimited number of sub-threshold +changes through. +""" +from __future__ import annotations + +import argparse +import sys +from pathlib import Path + +try: + from PIL import Image +except ImportError: # pragma: no cover - the workflow installs Pillow + print("Pillow is required to compare screenshots", file=sys.stderr) + raise + + +def read_tolerance(path: Path) -> tuple[int, float] | None: + if not path.exists(): + return None + max_delta, max_percent = 0, 0.0 + for line in path.read_text(encoding="utf-8").split("\n"): + line = line.split("#", 1)[0].strip() + if not line or "=" not in line: + continue + key, _, value = line.partition("=") + if key.strip() == "maxChannelDelta": + max_delta = int(value) + elif key.strip() == "maxMismatchPercent": + max_percent = float(value) + return max_delta, max_percent + + +def compare(generated: Path, committed: Path, tolerance: tuple[int, float] | None) -> str | None: + """Return None when the pair is acceptable, else a description of the failure.""" + if generated.read_bytes() == committed.read_bytes(): + return None + if tolerance is None: + return "differs and has no tolerance sidecar" + max_delta, max_percent = tolerance + # RGBA, not RGB: these figures are saved with an alpha channel, and dropping + # it would make a change that touches only transparency invisible here -- + # including one that turned the whole figure see-through while leaving every + # colour channel intact. + a = Image.open(generated).convert("RGBA") + b = Image.open(committed).convert("RGBA") + if a.size != b.size: + return f"size changed: generated {a.size[0]}x{a.size[1]}, committed {b.size[0]}x{b.size[1]}" + pa, pb = a.load(), b.load() + width, height = a.size + changed = 0 + worst = 0 + for y in range(height): + for x in range(width): + first, second = pa[x, y], pb[x, y] + if first == second: + continue + # Every changed pixel counts toward the area budget, and the channel + # delta is a separate ceiling. Counting only the pixels that EXCEED + # the delta -- which is what the CN1SS comparator does -- leaves an + # unbounded hole: with maxChannelDelta=160, recolouring these figures' + # green #06a806 to #a608a6 moves every channel by exactly 160, so not + # one pixel would be counted and a completely different image would + # pass. + changed += 1 + worst = max(worst, max(abs(first[i] - second[i]) for i in range(4))) + percent = 100.0 * changed / (width * height) + if percent > max_percent: + return f"{percent:.3f}% of pixels changed (allowed {max_percent}%)" + if worst > max_delta: + return f"worst channel delta {worst} exceeds maxChannelDelta={max_delta}" + return None + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--generated", required=True, type=Path) + parser.add_argument("--committed", required=True, type=Path) + parser.add_argument("--expected-count", type=int, required=True) + args = parser.parse_args() + + produced = sorted(args.generated.glob("*.png")) + if len(produced) != args.expected_count: + print( + f"::error::Expected {args.expected_count} generated figures, found {len(produced)}", + file=sys.stderr, + ) + return 1 + + failures = 0 + tolerated = 0 + for image in produced: + committed = args.committed / image.name + if not committed.exists(): + print(f"::error::Generated figure has no committed counterpart: {image.name}", file=sys.stderr) + failures += 1 + continue + sidecar = args.committed / (image.stem + ".tolerance") + tolerance = read_tolerance(sidecar) + problem = compare(image, committed, tolerance) + if problem: + print(f"::error::{image.name}: {problem}", file=sys.stderr) + failures += 1 + elif tolerance is not None and image.read_bytes() != committed.read_bytes(): + tolerated += 1 + print(f"{image.name}: within its tolerance sidecar") + + if failures: + print(f"\n{failures} figure(s) do not match.", file=sys.stderr) + return 1 + print(f"All {len(produced)} figures match ({tolerated} within a tolerance sidecar).") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) From 94a3b452ef3c3d590de27906c99ba9dff86e20c2 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 18:26:09 +0300 Subject: [PATCH 15/51] A comment block is not content, and img/ really does ship beside the page Two findings, one of them a false positive I introduced last round. Comment blocks. Asciidoctor drops a //// block entirely, so an include inside one does not put its target in the book and prose inside one promises the reader nothing -- but both scanners read straight through. //// joins the fence set in each. A/B with each construct planted inside a comment block: a displayed include:: made the structure check fail, and a promising sentence made the missing-block check fail; both are clean now. Note this is deliberately NOT symmetric with check-guide-links.py, which still reads URLs inside comments. The reasons differ and the code says so: a dead link commented out is still dead debt in the source, and letting the ratchet shrink for it would make "comment the line out" a way to silence that gate. Reachability is the opposite -- calling a commented-out include reachable states something about the book that is simply untrue. Packaged assets. The relative-href rule added last round was too broad: the HTML packaging step copies every subdirectory of docs/developer-guide next to developer-guide.html, so link:img/example.png[] resolves for a reader who opens the zip, and the gate would have rejected it. A relative href that names an existing file under the guide directory is now allowed. sketch/ is not, because that is the one directory the packaging loop skips. Probed all four ways, since an exemption is only worth having if it still rejects: link:img/flow-layout.png[] exit 0 (real, packaged) link:img/does-not-exist.png[] exit 1 link:sketch/whatever.svg[] exit 1 (not packaged) link:Supported-Properties[] exit 1 (the wiki-era shape) Co-Authored-By: Claude Opus 5 (1M context) --- .../developer-guide/check-guide-structure.py | 23 ++++++++++++------ scripts/developer-guide/check-guide-xrefs.py | 24 +++++++++++++++++++ .../check-missing-code-blocks.py | 23 ++++++++++++------ 3 files changed, 56 insertions(+), 14 deletions(-) diff --git a/scripts/developer-guide/check-guide-structure.py b/scripts/developer-guide/check-guide-structure.py index e992d9c9d09..fcf92705d73 100755 --- a/scripts/developer-guide/check-guide-structure.py +++ b/scripts/developer-guide/check-guide-structure.py @@ -34,13 +34,22 @@ # Literal-content blocks only. The container delimiters -- ==== example, # **** sidebar, ____ quote -- hold ordinary AsciiDoc, so an include or a heading # inside one is real and must not be skipped. -# Literal blocks only -- an example (====) or sidebar (****) block contains live -# markup, so its headings and includes are real. A delimiter may be LONGER than -# four characters, and closes on one of the same character AND length, so a -# four-dash line inside a five-dash block is content rather than the close. -# Matching exactly four left every ----- block's contents live: the guide has 20 -# such lines, all [source] blocks wrapping an include::. -FENCE_RE = re.compile(r"^(-{4,}|\.{4,}|`{4,}|\+{4,})\s*$") +# Literal and comment blocks -- an example (====) or sidebar (****) block contains +# live markup, so its headings and includes are real and must keep counting. A +# delimiter may be LONGER than four characters, and closes on one of the same +# character AND length, so a four-dash line inside a five-dash block is content +# rather than the close. Matching exactly four left every ----- block's contents +# live: the guide has 20 such lines, all [source] blocks wrapping an include::. +# +# //// is here because asciidoctor drops a comment block entirely, so an include +# inside one does not put its target in the book and prose inside one promises +# the reader nothing. Note check-guide-links.py deliberately does NOT skip +# comments: a dead link commented out is still dead debt in the source, and +# letting the ratchet shrink for it would turn "comment the line out" into a way +# to silence that gate. Reachability is the opposite case -- treating a +# commented-out include as reachable states something about the book that is +# simply untrue. +FENCE_RE = re.compile(r"^(-{4,}|\.{4,}|`{4,}|\+{4,}|/{4,})\s*$") # Inline AsciiDoc markup that never survives into the rendered heading text. INLINE_MARKUP_RE = re.compile(r"[`*_#]|\[\[[^\]]*\]\]|\[[^\]]*\]") diff --git a/scripts/developer-guide/check-guide-xrefs.py b/scripts/developer-guide/check-guide-xrefs.py index fe260fb9be7..fff67354619 100755 --- a/scripts/developer-guide/check-guide-xrefs.py +++ b/scripts/developer-guide/check-guide-xrefs.py @@ -20,6 +20,7 @@ import tempfile from collections import defaultdict from pathlib import Path +from urllib.parse import unquote ID_RE = re.compile(r'\bid="([^"]+)"') HREF_RE = re.compile(r'href="#([^"]+)"') @@ -95,6 +96,27 @@ def render(root: Path, attributes: tuple[str, ...] = ()) -> str: return out.read_text(encoding="utf-8") +def packaged_asset(guide_dir: Path, target: str) -> bool: + """Whether a relative href names a file that ships beside the rendered page. + + The HTML package copies every subdirectory of docs/developer-guide next to + developer-guide.html, so `link:img/example.png[]` resolves for a reader who + opens the zip. `sketch` is the one directory the packaging step skips, so a + link into it does not. + """ + path = target.split("#", 1)[0].split("?", 1)[0] + if not path: + return False + candidate = (guide_dir / unquote(path)).resolve() + try: + relative_path = candidate.relative_to(guide_dir) + except ValueError: + return False # escapes the guide directory, so it is not packaged + if relative_path.parts and relative_path.parts[0] == "sketch": + return False + return candidate.exists() + + def source_locations(guide_dir: Path, target: str) -> list[str]: """Find where a dangling target is referenced, so the error is actionable.""" hits = [] @@ -134,6 +156,8 @@ def main() -> int: raw_id_links[target] += 1 branches[target].add(name) for target in RELATIVE_HREF_RE.findall(markup): + if packaged_asset(guide_dir, target): + continue relative[target] += 1 branches[target].add(name) diff --git a/scripts/developer-guide/check-missing-code-blocks.py b/scripts/developer-guide/check-missing-code-blocks.py index e15a1b7b189..694e3f46da8 100755 --- a/scripts/developer-guide/check-missing-code-blocks.py +++ b/scripts/developer-guide/check-missing-code-blocks.py @@ -35,13 +35,22 @@ # and validate-guide-snippets.py requires every listing to be [source,LANG] with a # bare include:: inside ---- delimiters, so a three-backtick block would fail that # gate before reaching this one. Add it here if that convention ever changes. -# Literal blocks only -- an example (====) or sidebar (****) block contains live -# markup, so its headings and includes are real. A delimiter may be LONGER than -# four characters, and closes on one of the same character AND length, so a -# four-dash line inside a five-dash block is content rather than the close. -# Matching exactly four left every ----- block's contents live: the guide has 20 -# such lines, all [source] blocks wrapping an include::. -FENCE_RE = re.compile(r"^(-{4,}|\.{4,}|`{4,}|\+{4,})\s*$") +# Literal and comment blocks -- an example (====) or sidebar (****) block contains +# live markup, so its headings and includes are real and must keep counting. A +# delimiter may be LONGER than four characters, and closes on one of the same +# character AND length, so a four-dash line inside a five-dash block is content +# rather than the close. Matching exactly four left every ----- block's contents +# live: the guide has 20 such lines, all [source] blocks wrapping an include::. +# +# //// is here because asciidoctor drops a comment block entirely, so an include +# inside one does not put its target in the book and prose inside one promises +# the reader nothing. Note check-guide-links.py deliberately does NOT skip +# comments: a dead link commented out is still dead debt in the source, and +# letting the ratchet shrink for it would turn "comment the line out" into a way +# to silence that gate. Reachability is the opposite case -- treating a +# commented-out include as reachable states something about the book that is +# simply untrue. +FENCE_RE = re.compile(r"^(-{4,}|\.{4,}|`{4,}|\+{4,}|/{4,})\s*$") # Lines that end in a colon without promising a listing: headings, attributes, # comments, block titles, list markers, table cells and block delimiters. NON_PROSE_PREFIX = ("//", "|", "=", ".", ":", "*", "-", "+", "[", "<") From 773297be0cd59125da729050e5a7260d1e4e40f2 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 18:35:02 +0300 Subject: [PATCH 16/51] The packaging exemption trusted the repository, not the published output Both findings are defects in the two rules added in the previous commit. packaged_asset() asked whether the file exists here, which is not the question. A link only works if the published output carries it, and the two outputs filter differently: * the HTML archive copies only the SUBDIRECTORIES of docs/developer-guide next to developer-guide.html and skips sketch, so a root-level file is never in the zip however much it exists in the tree; * the website rsync excludes sketch/, *.asciidoc and *.adoc, so a source file nested inside a packaged directory still does not reach the site. So link:Introduction.asciidoc[] was being exempted and readers would follow it to nothing. Both filters are now reproduced. The permissive direction is the expensive one here -- it suppresses a finding for a link nobody can follow -- so all four cases are probed: img/flow-layout.png exit 0 in both outputs Introduction.asciidoc exit 1 in neither img/does-not-exist.png exit 1 sketch/foo.svg exit 1 excluded by both The backend-conditional rejection scanned raw lines, so a source block DISPLAYING `ifdef::backend-html5[]` as example text aborted the whole gate. A displayed directive takes no part in preprocessing. It now tracks literal and comment block delimiters the way the other guide scanners do. A/B: displayed inside a source block went 1 -> 0, while a genuinely active conditional still exits 1. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-xrefs.py | 45 ++++++++++++++++---- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/scripts/developer-guide/check-guide-xrefs.py b/scripts/developer-guide/check-guide-xrefs.py index fff67354619..121dd34fb96 100755 --- a/scripts/developer-guide/check-guide-xrefs.py +++ b/scripts/developer-guide/check-guide-xrefs.py @@ -22,6 +22,11 @@ from pathlib import Path from urllib.parse import unquote +ASCIIDOC_SUFFIXES = {".adoc", ".asciidoc"} +# Literal and comment blocks, matching the other guide scanners: a delimiter may +# be longer than four characters and closes on one of the same character and +# length. +FENCE_RE = re.compile(r"^(-{4,}|\.{4,}|`{4,}|\+{4,}|/{4,})\s*$") ID_RE = re.compile(r'\bid="([^"]+)"') HREF_RE = re.compile(r'href="#([^"]+)"') # The guide renders as one page, so a RELATIVE href resolves against wherever that @@ -67,9 +72,22 @@ def reject_unmodelled_conditionals(guide_dir: Path) -> None: for path in sorted(guide_dir.rglob("*")): - if path.suffix not in {".adoc", ".asciidoc"} or not path.is_file(): + if path.suffix not in ASCIIDOC_SUFFIXES or not path.is_file(): continue + open_fence: str | None = None for number, line in enumerate(path.read_text(encoding="utf-8").split("\n"), 1): + # A directive DISPLAYED inside a source block or a comment block does + # not take part in preprocessing, so it must not abort the gate. + fence = FENCE_RE.match(line) + if fence: + token = fence.group(1) + if open_fence is None: + open_fence = token + elif token == open_fence: + open_fence = None + continue + if open_fence is not None: + continue if UNMODELLED_CONDITIONAL_RE.match(line): raise SystemExit( f"{path.name}:{number}: this file guards content on the HTML " @@ -99,10 +117,17 @@ def render(root: Path, attributes: tuple[str, ...] = ()) -> str: def packaged_asset(guide_dir: Path, target: str) -> bool: """Whether a relative href names a file that ships beside the rendered page. - The HTML package copies every subdirectory of docs/developer-guide next to - developer-guide.html, so `link:img/example.png[]` resolves for a reader who - opens the zip. `sketch` is the one directory the packaging step skips, so a - link into it does not. + A link only works if BOTH published outputs carry the file, so this reproduces + both filters rather than asking whether the path exists in the repository: + + * the HTML archive copies only the SUBDIRECTORIES of docs/developer-guide next + to developer-guide.html, and skips `sketch`, so a root-level file such as + Introduction.asciidoc is never in the zip however much it exists here; + * the website rsync excludes `sketch/`, `*.asciidoc` and `*.adoc`, so a source + file nested inside a packaged directory still does not reach the site. + + Getting this wrong in the permissive direction is the expensive one: it + suppresses a finding for a link readers cannot follow. """ path = target.split("#", 1)[0].split("?", 1)[0] if not path: @@ -111,10 +136,14 @@ def packaged_asset(guide_dir: Path, target: str) -> bool: try: relative_path = candidate.relative_to(guide_dir) except ValueError: - return False # escapes the guide directory, so it is not packaged - if relative_path.parts and relative_path.parts[0] == "sketch": + return False # escapes the guide directory, so neither output carries it + if len(relative_path.parts) < 2: + return False # a root-level file; the archive copies directories only + if relative_path.parts[0] == "sketch": return False - return candidate.exists() + if candidate.suffix in ASCIIDOC_SUFFIXES: + return False # excluded from the website copy at any depth + return candidate.is_file() def source_locations(guide_dir: Path, target: str) -> list[str]: From 93b05188a86560a75d3ca7b181630be853aa03cc Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 18:38:21 +0300 Subject: [PATCH 17/51] The Introduction taught a dead IDE menu, an iTunes walkthrough and 2018 statistics (#5671) * The Introduction taught a dead IDE menu, an iTunes walkthrough and 2018 statistics Six corrections to the chapter a new developer reads first: * The JavaScript target was described twice and contradicted itself: the overview said TeaVM did the translation, the port section said ParparVM with TeaVM as a fallback. The port section is right -- `javascript.port` is declared with `parparvm` as its default and `teavm` documented as "the original builder as a compatibility fallback". * `http://teavm.org:[TeaVM-based builder]` -- the stray colon made the macro a bare host, and the site serves TLS. Removed from the link ratchet, which now stands at 37. * Bitcode was cited as something ParparVM absorbed without modification. Apple has since withdrawn bitcode, which makes the point better than the arrival did, so the sentence now names both moves. * The device-fragmentation section rested on two 2018 Android share numbers, followed by a sentence conceding they would be stale on arrival. The structural claim survives without them. * The iOS developer fee was dated with "for 10 years at the time of this writing". * The UDID instructions walked the reader through iTunes, with a screenshot of iTunes on iOS 9.3.5 that also exposed a real device serial and UDID. iTunes has not existed on macOS since Catalina, and the signing chapter already gives the current answer, so this now points there. * The device build was "a right click away" via the IDE plugin, illustrated by a menu still offering Blackberry, J2ME and Windows Phone builds. Replaced with the `cn1:buildAndroid` and `cn1:buildIos` goals, taken from the mojo names. Both screenshots are deleted, so find_unused_images.py stays satisfied. Verified: asciidoctor at --failure-level WARN, Vale at suggestion level, LanguageTool (status ok, 0 matches, run under JDK 17 rather than the JDK 8 false green), paragraph capitalization, snippets, xrefs, structure, links and missing-code-blocks all clean. Co-Authored-By: Claude Opus 5 (1M context) * "-pl common" made a device build a no-op that reported success Review caught the command I had just written. AbstractBuildWrapperMojo.execute() opens with: if (!project.isExecutionRoot()) { getLog().info("Skipping execution for non-root project"); return; } and BuildAndroidMojo, BuildIosMojo and BuildWin32Mojo all inherit it unchanged. Under `-pl common` the selected module is not the execution root, so the goal logs that line and stops. The design is deliberate -- the wrapper re-invokes Maven on the root pom itself (`request.setPomFile(new File("pom.xml"))`) -- so naming a module both skips the wrapper and defeats its purpose. Measured rather than reasoned, against scripts/hellocodenameone: mvn -pl common ...:buildWin32 -> "Skipping execution for non-root project" BUILD SUCCESS, nothing built mvn ...:buildWin32 -> no skip line, proceeds into the reactor A silent success is the worst failure mode for a getting-started instruction, so the Introduction now says where to run it and warns about the module form explicitly. Working-With-Windows carried the same `-pl common` shape and is fixed with it -- it is where I copied the form from, so leaving it would reintroduce the defect the next time someone follows the pattern. Co-Authored-By: Claude Opus 5 (1M context) * The Windows build wrappers named a platform no profile answers to Review checked the command this PR documents and found it still builds nothing. The wrapper passes `codename1.platform` to its nested Maven run, and that property is what activates the module profile in a generated project's root pom. The profile is `win`, matching the value the win module itself declares: win codename1.platformwin win BuildWin32Mojo and BuildWindowsDeviceMojo both passed "windows", which matches no profile at all. Nothing else in the plugin reads the platform as "windows", so the value was simply inert: the win module never joined the reactor and the nested build reported success having produced no Windows binary. Every other wrapper already agrees with its profile -- android, ios, javascript, linux and javase all match -- so these two were the only ones out of step. Verified by A/B against scripts/hellocodenameone, reading the NESTED reactor rather than the outer one: before hellocodenameone, -common, -javase <- no win module after hellocodenameone, -common, -win The build TARGET is a separate namespace and stays "windows-device" (Executor.BUILD_TARGET_WINDOWS_NATIVE), which is correct. SpotBugs over codenameone-maven-plugin regenerated: 0 findings. Co-Authored-By: Claude Opus 5 (1M context) * The primary Win32 command had both defects the convenience goal just lost Fixing BuildWin32Mojo made the sentence beside this snippet false: the goal now submits a build, while the command the chapter leads with still could not. It carried both defects at once -- mvn -pl common package -Dcodename1.platform=windows ... -- `-pl common` builds that module instead of the reactor, so the win module is never reached, and `windows` matches no profile even when the reactor is whole. The two mistakes hid each other: with only the module selected, the platform value had nothing left to activate. Corrected to what the wrapper actually runs, read off AbstractBuildWrapperMojo: goal `package`, `codename1.platform=win`, `codename1.buildTarget=windows-device`, from the project root. A/B against scripts/hellocodenameone, reading the reactor, which Maven prints before it compiles: old no win module in the reactor at all new hellocodenameone, -common, -win Both invocations then fail identically on this machine with "invalid target release: 17", because tools/env.sh pins JDK 8 while the demo targets 17. That is environmental and equal on both sides, so it does not affect the comparison. Co-Authored-By: Claude Opus 5 (1M context) --------- Co-authored-by: Claude Opus 5 (1M context) --- .../developer-guide/working-with-windows.sh | 2 +- docs/developer-guide/Introduction.asciidoc | 26 +++++++----------- .../Working-With-Windows.asciidoc | 2 +- docs/developer-guide/img/get-device-udid.png | Bin 263938 -> 0 bytes .../img/getting-started-right-click-menu.png | Bin 141507 -> 0 bytes .../maven/buildWrappers/BuildWin32Mojo.java | 9 +++++- .../buildWrappers/BuildWindowsDeviceMojo.java | 9 +++++- .../developer-guide/guide-links-baseline.txt | 1 - 8 files changed, 28 insertions(+), 21 deletions(-) delete mode 100644 docs/developer-guide/img/get-device-udid.png delete mode 100644 docs/developer-guide/img/getting-started-right-click-menu.png diff --git a/docs/demos/common/src/main/snippets/developer-guide/working-with-windows.sh b/docs/demos/common/src/main/snippets/developer-guide/working-with-windows.sh index f1beb009283..1230d8383f6 100644 --- a/docs/demos/common/src/main/snippets/developer-guide/working-with-windows.sh +++ b/docs/demos/common/src/main/snippets/developer-guide/working-with-windows.sh @@ -1,5 +1,5 @@ // Generated from docs/developer-guide source blocks. Edit the guide snippets here, not inline. // tag::working-with-windows-bash-001[] -mvn -pl common package -Dcodename1.platform=windows -Dcodename1.buildTarget=windows-device +mvn package -Dcodename1.platform=win -Dcodename1.buildTarget=windows-device // end::working-with-windows-bash-001[] diff --git a/docs/developer-guide/Introduction.asciidoc b/docs/developer-guide/Introduction.asciidoc index 3ba32d08f6d..2f9172686f7 100644 --- a/docs/developer-guide/Introduction.asciidoc +++ b/docs/developer-guide/Introduction.asciidoc @@ -60,13 +60,13 @@ Codename One uses a SaaS-based approach so the information in this appendix migh Since Android is already based on Java, Codename One is already native to Android and works with the Android VM (ART/Dalvik). -On iOS, Codename One built and open-sourced ParparVM, which is a conservative VM. ParparVM features a concurrent, non-blocking GC and is written entirely in Java/C. ParparVM is a transpiler that generates C source code matching the given Java bytecode. This means that an Xcode project is generated and compiled on the build servers. It's as if you hand-coded a native app and is thus future-proof against changes that Apple introduces. For example, Apple migrated to 64-bit and later introduced bitcode support to iOS. ParparVM needed no modifications to meet those changes. +On iOS, Codename One built and open-sourced ParparVM, which is a conservative VM. ParparVM features a concurrent, non-blocking GC and is written entirely in Java/C. ParparVM is a transpiler that generates C source code matching the given Java bytecode. This means that an Xcode project is generated and compiled on the build servers. It's as if you hand-coded a native app and is thus future-proof against changes that Apple introduces. For example, Apple migrated to 64-bit, then introduced bitcode, then withdrew bitcode again. ParparVM needed no modifications for any of those changes. NOTE: Codename One translates the bytecode to C, which is faster than Swift/Objective-C. The port code that invokes iOS APIs is hand coded in Objective-C Codename One earlier offered a UWP (Universal Windows Platform) target based on iKVM. That target was discontinued in release 7.0.229 and is preserved as historical context in older documentation and blog posts. -JavaScript build targets use TeaVM to do the translation statically. TeaVM supports threading using JavaScript by breaking the app down in a rather elaborate way. To support the complex UI Codename One uses the HTML5 Canvas API which allows absolute flexibility for building applications. +JavaScript build targets translate the bytecode statically with ParparVM, the same translator that generates the C sources for iOS. Cloud builds keep the original TeaVM-based compiler as a compatibility fallback, which you select with the `javascript.port` build hint. To support the complex UI Codename One uses the HTML5 Canvas API which allows absolute flexibility for building applications. For desktop builds Codename One uses `javapackager`, since both Macs and Windows machines are available in the cloud, the platform-specific nature of `javapackager` isn't a problem. @@ -87,7 +87,7 @@ Lightweight components date back to Smalltalk frameworks, this notion was popula ===== Why ParparVM -On iOS, Codename One uses https://github.com/codenameone/CodenameOne/tree/master/vm[ParparVM] which translates Java bytecode to C code and boasts a non-blocking GC as well as 64 bit/bitcode support. This VM is fully open source in the https://github.com/codenameone/CodenameOne/[Codename One git repository]. In the past Codename One used http://www.xmlvm.org/[XMLVM] to generate native code similarly, but the XMLVM solution was too generic for the needs of Codename One. https://github.com/codenameone/CodenameOne/tree/master/vm[ParparVM] boasts a unique architecture of translating code to C (similarly to XMLVM), because of that Codename One is the only solution of its kind that can **guarantee** future iOS compatibility since the officially supported iOS toolchain is always used instead of undocumented behaviors. +On iOS, Codename One uses https://github.com/codenameone/CodenameOne/tree/master/vm[ParparVM] which translates Java bytecode to C code and boasts a non-blocking GC. This VM is fully open source in the https://github.com/codenameone/CodenameOne/[Codename One git repository]. In the past Codename One used http://www.xmlvm.org/[XMLVM] to generate native code similarly, but the XMLVM solution was too generic for the needs of Codename One. https://github.com/codenameone/CodenameOne/tree/master/vm[ParparVM] boasts a unique architecture of translating code to C (similarly to XMLVM), because of that Codename One is the only solution of its kind that can **guarantee** future iOS compatibility since the officially supported iOS toolchain is always used instead of undocumented behaviors. NOTE: XMLVM could guarantee that as well, but it's no longer maintained and lacked the API layer support @@ -107,7 +107,7 @@ NOTE: The UWP target was discontinued in release 7.0.229 and is no longer part o ===== JavaScript port -The JavaScript port of Codename One uses ParparVM to translate Java bytecode into JavaScript. Cloud builds retain the original http://teavm.org:[TeaVM-based builder] as a compatibility fallback, selected with the public `javascript.port=teavm` build hint. +The JavaScript port of Codename One uses ParparVM to translate Java bytecode into JavaScript. Cloud builds retain the original https://teavm.org/[TeaVM-based builder] as a compatibility fallback, selected with the public `javascript.port=teavm` build hint. The JavaScript port allows unmodified Codename One applications to run within a desktop or mobile browser. The port itself is based on the HTML5 Canvas API, which provides a pixel-perfect implementation of the Codename One API. @@ -175,9 +175,9 @@ Scrolling poses another challenge in touch-based interfaces. In desktop applicat Some developers single out this wide range of resolutions and densities as "`device fragmentation.`" While it does contribute to development complexity, it isn't a challenging problem to overcome. -Densities aren't the cause of device fragmentation. Device fragmentation is caused by many OS versions with different behaviors. This is clear on Android and relates to the slow rollout of Android vendor versions compared to Google rollout. For example, 7 months after the Android 8 (Oreo) release in 2018, it was still available on 1.1% of the devices. The damning statistic is that 12% of the devices in mid 2018 run Android 4.4 Kitkat released in 2013! (((Google))) +Densities aren't the cause of device fragmentation. Device fragmentation is caused by many OS versions with different behaviors. This is clear on Android and relates to the slow rollout of Android vendor versions compared to Google rollout. A new release reaches only a small fraction of devices in its first year, and handsets several major versions behind stay in circulation long after their vendor stops shipping updates for them. (((Google))) -This makes QA difficult as the disparity between these versions is pretty big. These numbers will be out of date by the time you read this, but the core problem remains. It's hard to get all device manufacturers aligned, so this problem will probably remain in the foreseeable future despite everything. +This makes QA difficult as the disparity between these versions is pretty big. It's hard to get all device manufacturers aligned, so this problem will probably remain in the foreseeable future despite everything. ==== Performance @@ -414,7 +414,7 @@ First, the good news: In iOS Apple issues the certificates for your applications. That way the certificate is trusted by Apple and is assigned to your Apple iOS developer account. One important caveat applies: You need an iOS Developer Account and Apple charges a 99USD Annual fee for that. -TIP: The 99USD price and need have been around since the introduction of the iOS developer program for 10 years at the time of this writing. It might change at some point though +TIP: The fee and the requirement have been part of the iOS developer program since it was introduced. Check Apple's developer site for the current price. Apple also requires a "`provisioning profile`" which is a special file bound to your certificate and app. This file describes some details about the app to the iOS installation process. One of the details it includes during development is the list of permitted devices. @@ -453,12 +453,7 @@ One important aspect of provisioning on iOS is the device list in the provisioni WARNING: Many apps and tools offer the UDID of the device, but they aren't necessarily reliable and might give a fake number! -.Get the UDID of a Device -image::img/get-device-udid.png[Get the UDID of a Device] - -TIP: You can right-click the UDID and select #copy# to copy it - -The simplest and most reliable process for getting a UDID is through iTunes. Other approaches have worked in the past but this approach is guaranteed. +The <<_whats_udid,UDID section of the signing chapter>> covers the reliable ways to read that value. NOTE: Ad hoc provisioning allows 1000 beta testers for your application but it's a more complex process that you won't discuss here although it's supported by Codename One @@ -466,10 +461,9 @@ NOTE: Ad hoc provisioning allows 1000 beta testers for your application but it's Before you continue with the build you should sign up at https://www.codenameone.com/build-server.html where you can soon follow the progress of your builds. You need a Codename One account to build for the device. -Now that you have certificates, the process of device builds is a right click away for both OSes. You can right-click the project and select #Codename One# -> #Send iOS Debug Build# or #Codename One# -> #Send Android Build#. +Now that you have certificates, a device build is a single Maven goal. From the project's root directory run `mvn cn1:buildAndroid` for Android, or `mvn cn1:buildIos` for an iOS debug build. Each one packages the app, sends it to the Codename One build servers and reports where the result lands. -.Right click menu options for sending device builds -image::img/getting-started-right-click-menu.png[Right click menu options for sending device builds,scaledwidth=50%] +WARNING: Run these from the root, not from a module. The build goals skip any project that isn't the execution root, so `mvn -pl common cn1:buildAndroid` prints "`Skipping execution for non-root project`" and then reports success without building anything. NOTE: The first time you send a build you will be prompted for the email and password you provided when signing up for Codename One diff --git a/docs/developer-guide/Working-With-Windows.asciidoc b/docs/developer-guide/Working-With-Windows.asciidoc index 33aa88bc93e..d9f97a2b141 100644 --- a/docs/developer-guide/Working-With-Windows.asciidoc +++ b/docs/developer-guide/Working-With-Windows.asciidoc @@ -84,7 +84,7 @@ above. Trigger it like any other cloud target: include::../demos/common/src/main/snippets/developer-guide/working-with-windows.sh[tag=working-with-windows-bash-001,indent=0] ---- -The convenience goal `mvn -pl common cn1:buildWin32` does the same thing. A regular +The convenience goal `mvn cn1:buildWin32`, run from the project root, does the same thing. A regular (release) build returns **two** binaries -- x64 and arm64, both stripped release exes. Setting the `windows.debug` build hint instead returns a **single** x64 exe with symbols, for diagnosis. (To build locally on a Windows box, use diff --git a/docs/developer-guide/img/get-device-udid.png b/docs/developer-guide/img/get-device-udid.png deleted file mode 100644 index 1ce13e38367170f032e7018a2cbd726db1dbf82c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 263938 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 Fn?qi`&w^8Q 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

=WCSU?FJLx&TJ*-
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

QG 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 z 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 diff --git a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/buildWrappers/BuildWin32Mojo.java b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/buildWrappers/BuildWin32Mojo.java index 0e30ea08ac6..f0c0efaf554 100644 --- a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/buildWrappers/BuildWin32Mojo.java +++ b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/buildWrappers/BuildWin32Mojo.java @@ -23,7 +23,14 @@ public class BuildWin32Mojo extends AbstractBuildWrapperMojo { @Override protected String getPlatform() { - return "windows"; + // "win", not "windows". This value activates the module profile in the + // generated project's root pom, and that profile matches the value the + // win module itself declares -- which is "win". Passing "windows" + // matched no profile, so the win module never entered the reactor and + // the wrapper's nested build reported success having produced nothing. + // Nothing else reads the platform as "windows"; the build TARGET stays + // "windows-device", which is a separate namespace. + return "win"; } @Override diff --git a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/buildWrappers/BuildWindowsDeviceMojo.java b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/buildWrappers/BuildWindowsDeviceMojo.java index 4b098dd4861..24189ffc4dc 100644 --- a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/buildWrappers/BuildWindowsDeviceMojo.java +++ b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/buildWrappers/BuildWindowsDeviceMojo.java @@ -15,7 +15,14 @@ public class BuildWindowsDeviceMojo extends AbstractBuildWrapperMojo { @Override protected String getPlatform() { - return "windows"; + // "win", not "windows". This value activates the module profile in the + // generated project's root pom, and that profile matches the value the + // win module itself declares -- which is "win". Passing "windows" + // matched no profile, so the win module never entered the reactor and + // the wrapper's nested build reported success having produced nothing. + // Nothing else reads the platform as "windows"; the build TARGET stays + // "windows-device", which is a separate namespace. + return "win"; } @Override diff --git a/scripts/developer-guide/guide-links-baseline.txt b/scripts/developer-guide/guide-links-baseline.txt index 990e6d1c4d0..56648f6ac60 100644 --- a/scripts/developer-guide/guide-links-baseline.txt +++ b/scripts/developer-guide/guide-links-baseline.txt @@ -21,7 +21,6 @@ Advanced-Topics-Under-The-Hood.asciidoc http://jruby.org/ Advanced-Topics-Under-The-Hood.asciidoc http://shannah.github.io/cn1-freshdesk/ Advanced-Topics-Under-The-Hood.asciidoc http://stackoverflow.com/questions/11421048/android-ios-custom-uri-protocol-handling Advanced-Topics-Under-The-Hood.asciidoc http://www.mirah.org/ -Introduction.asciidoc http://teavm.org Introduction.asciidoc http://www.xmlvm.org/ Miscellaneous-Features.asciidoc http://wiki.akosma.com/IPhone_URL_Schemes The-Components-Of-Codename-One.asciidoc http://awoiaf.westeros.org/index.php/A_Game_of_Thrones From b1f80df6444084136f66e78971313fddfd531339 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 21:10:52 +0300 Subject: [PATCH 18/51] Copyright headers for the two Windows wrappers, and duplicate includes per parent check-copyright-headers went red once #5671 merged in: BuildWin32Mojo and BuildWindowsDeviceMojo have carried no header since they were added in #5144, and editing them brought them into the diff the gate examines. Both take the Codename One GPL + Classpath header, copied from BuildMacNativeMojo in the same package. I had run that gate locally and read "8 file(s) passed", which was worthless: I ran it BEFORE `git add`, and it diffs committed refs, so the two files it needed to see were still sitting unstaged in the working tree. A gate run against HEAD while the change is uncommitted answers a question about the previous commit. Separately, review is right that duplicate detection only covered the manifest. The counter was keyed by target and incremented for root edges alone, so a nested include repeated in the SAME parent was invisible -- and _visit() returns early on a revisit, so the second edge left no trace at all. The outcome check then saw one declaration against two rendered titles and passed, because it only asks whether a title appears AT LEAST as often as it is declared. Now keyed by (parent, target) and counted for every unconditional edge at any depth. That keeps the distinction that matters: one parent including one file twice renders it twice and is a defect; two different parents including the same fragment is what a fragment is for. Conditional edges stay excluded, at the root and nested, since two mutually exclusive branches are one rendering. Probed all three: nested duplicate, same parent old 0 -> new 1 root duplicate old 1 -> new 1 (regression intact) same fragment from a 2nd parent new 0 (still allowed) Co-Authored-By: Claude Opus 5 (1M context) --- .../maven/buildWrappers/BuildWin32Mojo.java | 22 +++++++++++++++++ .../buildWrappers/BuildWindowsDeviceMojo.java | 22 +++++++++++++++++ .../developer-guide/check-guide-structure.py | 24 +++++++++++++++---- 3 files changed, 63 insertions(+), 5 deletions(-) diff --git a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/buildWrappers/BuildWin32Mojo.java b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/buildWrappers/BuildWin32Mojo.java index f0c0efaf554..3dcc73ad09e 100644 --- a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/buildWrappers/BuildWin32Mojo.java +++ b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/buildWrappers/BuildWin32Mojo.java @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ package com.codename1.maven.buildWrappers; diff --git a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/buildWrappers/BuildWindowsDeviceMojo.java b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/buildWrappers/BuildWindowsDeviceMojo.java index 24189ffc4dc..cf1ec7e44dd 100644 --- a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/buildWrappers/BuildWindowsDeviceMojo.java +++ b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/buildWrappers/BuildWindowsDeviceMojo.java @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ package com.codename1.maven.buildWrappers; diff --git a/scripts/developer-guide/check-guide-structure.py b/scripts/developer-guide/check-guide-structure.py index fcf92705d73..539349ffa3e 100755 --- a/scripts/developer-guide/check-guide-structure.py +++ b/scripts/developer-guide/check-guide-structure.py @@ -102,7 +102,15 @@ def __init__(self, root: Path, guide_dir: Path) -> None: # reused from two parents on purpose, and a file included under # mutually exclusive ifdef/ifndef branches appears twice in the source # while rendering once -- neither is a duplicated chapter. - self.direct_include_count: collections.Counter = collections.Counter() + # Keyed by (parent, target) rather than by target alone. A fragment reused + # from two different parents is deliberate -- that is what a fragment is + # for -- but the SAME parent including the SAME file twice renders it + # twice, at the root or nested. Keying only by target missed the nested + # case entirely, and _visit() returns early on a revisit, so the second + # edge left no trace at all: the outcome check then saw one declaration + # and two rendered titles and passed, because it only asks whether a + # title appears AT LEAST as often as it is declared. + self.include_edges: collections.Counter = collections.Counter() self.errors: list[str] = [] self._visit(root, "") @@ -161,7 +169,11 @@ def _visit(self, path: Path, attrs_from_parent: str) -> None: f"which branches are mutually exclusive before adding one." ) else: - self.direct_include_count[target] += 1 + self.include_edges[(path, target)] += 1 + if path != self.root and not self._inside_conditional(lines, index): + # A conditional edge is excluded for the same reason as at the + # root: two mutually exclusive branches are one rendering. + self.include_edges[(path, target)] += 1 self._visit(target, attrs) @staticmethod @@ -321,11 +333,13 @@ def main() -> int: # A chapter included twice by the manifest is rendered twice. The title check # below cannot see it, because it only asks whether a title appears AT LEAST # as often as it is declared. - for path, count in sorted(walker.direct_include_count.items()): + for (parent, target), count in sorted( + walker.include_edges.items(), key=lambda item: (item[0][0].name, item[0][1].name) + ): if count > 1: errors.append( - f"{path.name}: is included {count} times, so the book renders it " - f"{count} times. Remove the duplicate include." + f"{parent.name}: includes {target.name} {count} times, so the book " + f"renders it {count} times. Remove the duplicate include." ) # 1. Every chapter in the tree is either in the book or declared out of it. From cce44543994760c676f387e110b43cac0cc9808c Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 22:00:43 +0300 Subject: [PATCH 19/51] Refuse a conditional include at every depth, not only in the manifest The previous commit refused conditional includes under `path == self.root` and left exactly that hole one level down: a nested parent including the same file twice inside one ACTIVE ifdef recorded neither edge, _visit() deduplicated the second target, and the rendered-title check only requires the title once. Two copies render and nothing objects. The refusal now applies wherever the include sits. Nothing in the guide is conditional -- still measured at zero include:: lines inside a conditional anywhere -- and neither check that matters can validate one: the edge count has to skip a conditional edge because the same file under two exclusive branches is one rendering, and the rendered-title check has to skip it for the same reason. Skipping both silently is what let the duplicate through, so the construct is refused while nothing uses it. The message also stops hardcoding "developer-guide.asciidoc" as the filename, which was wrong for every nested parent. nested duplicate inside one conditional old 0 -> new 1 root conditional old 1 -> new 1 (regression intact) Co-Authored-By: Claude Opus 5 (1M context) --- .../developer-guide/check-guide-structure.py | 45 +++++++++---------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/scripts/developer-guide/check-guide-structure.py b/scripts/developer-guide/check-guide-structure.py index 539349ffa3e..496239647e4 100755 --- a/scripts/developer-guide/check-guide-structure.py +++ b/scripts/developer-guide/check-guide-structure.py @@ -150,29 +150,28 @@ def _visit(self, path: Path, attrs_from_parent: str) -> None: # it, because the same chapter under two exclusive branches # appears twice in the source and once in the output. self.direct.add(target) - if self._inside_conditional(lines, index): - # Nothing in the manifest is conditional today (measured: zero - # include:: lines sit inside a conditional anywhere in the guide), - # and the two checks that matter cannot see one. The duplicate - # count has to skip it, because the same chapter under two - # exclusive branches is one chapter in the output; the - # rendered-title check has to skip it too, because only one - # branch renders. Skipping BOTH silently means a chapter - # included twice inside a single active branch would pass. - # So refuse the construct instead of quietly not validating it. - self.conditional.add(target) - self.errors.append( - f"developer-guide.asciidoc:{index + 1}: {target_raw} is included " - f"inside a conditional. Neither the duplicate check nor the " - f"rendered-title check can validate a conditional entry, so this " - f"refuses it rather than skipping it silently. Teach the checker " - f"which branches are mutually exclusive before adding one." - ) - else: - self.include_edges[(path, target)] += 1 - if path != self.root and not self._inside_conditional(lines, index): - # A conditional edge is excluded for the same reason as at the - # root: two mutually exclusive branches are one rendering. + # Conditional includes are refused at EVERY depth, not just in the + # manifest. Nothing in the guide is conditional today (measured: zero + # include:: lines sit inside a conditional anywhere), and neither + # check that matters can validate one. The edge count has to skip it, + # because the same file under two exclusive branches is one rendering; + # the rendered-title check has to skip it too, for the same reason. + # Skipping BOTH silently means a file included twice inside a single + # ACTIVE branch passes -- _visit() deduplicates the second target and + # the title check only requires the title once. Refusing the construct + # is the honest answer while nothing uses it; an earlier version + # refused it only under path == self.root and left exactly that hole + # one level down. + if self._inside_conditional(lines, index): + self.conditional.add(target) + self.errors.append( + f"{path.name}:{index + 1}: {target_raw} is included inside a " + f"conditional. Neither the duplicate check nor the rendered-title " + f"check can validate a conditional include, so this refuses it " + f"rather than skipping it silently. Teach the checker which " + f"branches are mutually exclusive before adding one." + ) + else: self.include_edges[(path, target)] += 1 self._visit(target, attrs) From aa6af63126d3e439486b5bc8fa05a5054eaa53fa Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 22:08:56 +0300 Subject: [PATCH 20/51] A typo in the authority hid behind a correct hostname urlsplit().hostname drops the port whether or not it is a number, so https://www.codenameone.com:notaport/getting-started/ presented itself as an ordinary same-site URL and every check below passed on something no browser can open. Reading .port is what surfaces it: urlsplit defers that parse until the attribute is read, and then raises. A numeric nonstandard port is the quieter version of the same problem. The route model here is derived from _redirects, the Hugo content tree and the static tree, and all of that describes the site on its default port; :8443 is a different endpoint the model says nothing about, so validating the path against it would be accepting an unchecked URL. Local services keep their ports. The guide documents http://localhost:11434 deliberately -- it is the Ollama endpoint in the AI chapter, and the one URL in the guide with a port at all -- so the rule is scoped to SITE_HOSTS and leaves LOCAL_HOSTS alone. https://www.codenameone.com:notaport/getting-started/ old 0 -> new 1 https://www.codenameone.com:8443/getting-started/ old 0 -> new 1 https://www.codenameone.com/getting-started/ new 0 http://localhost:11434/api/tags new 0 Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index 16b2d74f907..47b101829e2 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -356,11 +356,28 @@ def findings_for(path: Path, known: set[str], patterns: list, declared: set[str] url = url.rstrip(".,;:") split = urlsplit(url) host = split.hostname or "" + # hostname strips the port whether or not it is a number, so a typo in + # the authority hides behind an otherwise correct host and every check + # below passes on a URL no browser can open. Reading .port is what + # surfaces it: urlsplit defers the parse until then and raises. + try: + port = split.port + except ValueError: + out.append((url, "the port is not a number, so this cannot be opened at all")) + continue if "." not in host and host not in LOCAL_HOSTS: out.append((url, f"host '{host}' has no dot in it and resolves nowhere")) continue if split.scheme == "http" and host not in TLS_EXEMPT_HOSTS | LOCAL_HOSTS: out.append((url, "plain http, not https")) + if host in SITE_HOSTS and port is not None: + # The route model below describes the site on its default port. A + # nonstandard port is a different endpoint that model says nothing + # about, so accepting the path would be accepting an unchecked URL. + # Local services keep their ports: http://localhost:11434 is the + # Ollama endpoint the AI chapter documents on purpose. + out.append((url, f"port {port} is not where the site is served")) + continue if host in SITE_HOSTS: target = split.path.rstrip("/") or "/" if split.fragment and target in SELF_PATHS: From 41c31337fc3a77e81e8a79f213295f27f51ec751 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 22:21:11 +0300 Subject: [PATCH 21/51] A listing hides content from the reader, not directives from the preprocessor Three findings, and chasing the middle one turned up that I had been patching on a false premise for several commits. I had been treating a literal block as a place where an include:: or an ifdef:: is merely DISPLAYED. It is not. Measured against asciidoctor rather than assumed: inside ---- / ----- / .... inside //// include:: PROCESSED dropped ifdef:: / ifeval:: ACTIVE dropped heading / prose literal text dropped Preprocessor directives are resolved before block parsing, so one written inside a listing fires exactly as it would outside it; only a comment block removes it. A literal block hides CONTENT, which is a different question. So the scanners now split the two. first_heading() and the missing-block scan keep the full fence set -- a heading or a promising sentence inside a listing really is only text. The include walk, the conditional test and the backend-conditional rejection use a comment-block fence only. Two earlier commits had extended literal-block skipping to those three, which made them disagree with the renderer; verified against the real book: include inside ---- 3 renders (a duplicate) gate now objects include inside //// 2 renders (dropped) gate now quiet That also means the review premise here -- that a displayed conditional inside a source block misclassifies a later include -- does not hold, and the code says so where the next reader will look. The other two findings stand and are fixed. An explicit default port reaches the identical endpoint, so https://www.codenameone.com:443/ is accepted while :8443 is still rejected. And ifeval::["{backend}" == "html5"] is as unmodellable as the boolean attribute: the surrogate sets backend-pdf on an HTML render, so backend-html5 stays defined AND {backend} still reads "html5". Both spellings are now refused. One crash caught by probing rather than by the clean run: COMMENT_FENCE_RE had no capture group while the caller reads group(1). The guide has no //// block, so that branch never executed and every gate stayed green over a latent IndexError. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 16 +++++++--- .../developer-guide/check-guide-structure.py | 31 ++++++++++++++++++- scripts/developer-guide/check-guide-xrefs.py | 20 +++++++----- 3 files changed, 55 insertions(+), 12 deletions(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index 47b101829e2..7141ca228d6 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -38,6 +38,8 @@ TLS_EXEMPT_HOSTS = {"timestamp.digicert.com", "example.com", "www.example.com"} # Hosts with no dot that are still real destinations. LOCAL_HOSTS = {"localhost", "127.0.0.1", "0.0.0.0"} +# Writing a scheme's own default port changes nothing about where the request goes. +DEFAULT_PORTS = {"http": 80, "https": 443} # Only the marketing site is served from the redirect table and the Hugo content # tree. cloud.codenameone.com and friends are separate services. SITE_HOSTS = {"codenameone.com", "www.codenameone.com"} @@ -370,12 +372,18 @@ def findings_for(path: Path, known: set[str], patterns: list, declared: set[str] continue if split.scheme == "http" and host not in TLS_EXEMPT_HOSTS | LOCAL_HOSTS: out.append((url, "plain http, not https")) - if host in SITE_HOSTS and port is not None: + if ( + host in SITE_HOSTS + and port is not None + and port != DEFAULT_PORTS.get(split.scheme) + ): # The route model below describes the site on its default port. A - # nonstandard port is a different endpoint that model says nothing + # NONSTANDARD port is a different endpoint that model says nothing # about, so accepting the path would be accepting an unchecked URL. - # Local services keep their ports: http://localhost:11434 is the - # Ollama endpoint the AI chapter documents on purpose. + # Spelling out the scheme's own default (":443" under https) is + # redundant but reaches the identical endpoint, so it is allowed. + # Local services keep their ports either way: http://localhost:11434 + # is the Ollama endpoint the AI chapter documents on purpose. out.append((url, f"port {port} is not where the site is served")) continue if host in SITE_HOSTS: diff --git a/scripts/developer-guide/check-guide-structure.py b/scripts/developer-guide/check-guide-structure.py index 496239647e4..47e1d48ee04 100755 --- a/scripts/developer-guide/check-guide-structure.py +++ b/scripts/developer-guide/check-guide-structure.py @@ -50,6 +50,20 @@ # commented-out include as reachable states something about the book that is # simply untrue. FENCE_RE = re.compile(r"^(-{4,}|\.{4,}|`{4,}|\+{4,}|/{4,})\s*$") +# Directives are a different question from content, and asciidoctor answers them +# differently. Measured: +# +# inside ---- / ----- / .... inside //// +# include:: PROCESSED dropped +# ifdef:: / ifeval:: ACTIVE dropped +# heading / prose literal text dropped +# +# A literal block hides CONTENT but not DIRECTIVES: include:: and ifdef:: are +# resolved before block parsing and fire from inside a listing exactly as they +# would outside it. Only a comment block removes them. So first_heading() keeps +# FENCE_RE -- a heading in a listing really is only text -- while the include walk +# and the conditional test use this narrower one. +COMMENT_FENCE_RE = re.compile(r"^(/{4,})\s*$") # Inline AsciiDoc markup that never survives into the rendered heading text. INLINE_MARKUP_RE = re.compile(r"[`*_#]|\[\[[^\]]*\]\]|\[[^\]]*\]") @@ -121,7 +135,7 @@ def _visit(self, path: Path, attrs_from_parent: str) -> None: lines = parse_lines(path) open_fence: str | None = None for index, line in enumerate(lines): - fence = FENCE_RE.match(line) + fence = COMMENT_FENCE_RE.match(line) if fence: token = fence.group(1) if open_fence is None: @@ -184,7 +198,22 @@ def _inside_conditional(lines: list[str], index: int) -> bool: valid markup. """ depth = 0 + open_fence: str | None = None for line in lines[:index]: + # Only a comment block, for the reason given at COMMENT_FENCE_RE: a + # conditional written inside a listing is not "displayed", it is + # active, so treating the listing as a hiding place would make this + # disagree with the renderer. + fence = COMMENT_FENCE_RE.match(line) + if fence: + token = fence.group(1) + if open_fence is None: + open_fence = token + elif token == open_fence: + open_fence = None + continue + if open_fence is not None: + continue # ifdef/ifndef open a block only with EMPTY brackets -- with content # they are the single-line form and guard just that line. ifeval has # no single-line form and always carries its expression in the diff --git a/scripts/developer-guide/check-guide-xrefs.py b/scripts/developer-guide/check-guide-xrefs.py index 121dd34fb96..730cb9c4dd4 100755 --- a/scripts/developer-guide/check-guide-xrefs.py +++ b/scripts/developer-guide/check-guide-xrefs.py @@ -23,10 +23,11 @@ from urllib.parse import unquote ASCIIDOC_SUFFIXES = {".adoc", ".asciidoc"} -# Literal and comment blocks, matching the other guide scanners: a delimiter may -# be longer than four characters and closes on one of the same character and -# length. -FENCE_RE = re.compile(r"^(-{4,}|\.{4,}|`{4,}|\+{4,}|/{4,})\s*$") +# Only a comment block. A conditional written inside a listing is not displayed +# text -- asciidoctor resolves ifdef/ifeval before block parsing, so it fires from +# in there exactly as it would outside. Measured; an earlier version treated a +# listing as a hiding place and would have skipped a genuinely active directive. +FENCE_RE = re.compile(r"^(/{4,})\s*$") ID_RE = re.compile(r'\bid="([^"]+)"') HREF_RE = re.compile(r'href="#([^"]+)"') # The guide renders as one page, so a RELATIVE href resolves against wherever that @@ -65,8 +66,13 @@ # leaves dangling. The guide has no such conditional, so rather than model a # construct that is not there -- or shell out to asciidoctor-pdf and try to read # anchors back out of a PDF -- notice if one appears. +# Both spellings of the same thing: the boolean attribute the converter defines, +# and an ifeval comparing the {backend} value. The surrogate can model neither -- +# it sets backend-pdf on an HTML render, so backend-html5 stays defined AND +# {backend} still reads "html5". UNMODELLED_CONDITIONAL_RE = re.compile( - r"^\s*if(n?def|eval)::.*\b(backend-html5|basebackend-html)\b" + r"^\s*if(n?def|eval)::.*" + r"(\bbackend-html5\b|\bbasebackend-html\b|\{backend\}|\{basebackend\})" ) @@ -76,8 +82,8 @@ def reject_unmodelled_conditionals(guide_dir: Path) -> None: continue open_fence: str | None = None for number, line in enumerate(path.read_text(encoding="utf-8").split("\n"), 1): - # A directive DISPLAYED inside a source block or a comment block does - # not take part in preprocessing, so it must not abort the gate. + # A directive inside a comment block is dropped by asciidoctor, so it + # cannot affect the render and must not abort the gate. fence = FENCE_RE.match(line) if fence: token = fence.group(1) From 5e79881bd01a8c7c277af49d4fad96114b990a62 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 22:28:37 +0300 Subject: [PATCH 22/51] The DNS root dot walked straight past the same-site checks urlsplit lowercases a host but keeps the root label's trailing dot, so "https://www.codenameone.com./does-not-exist" carried the hostname "www.codenameone.com." -- which is not in SITE_HOSTS. It therefore skipped the route model, the self-link rule, the slash rule and the port rule in one go, and was accepted, while the identical path without the dot is reported. DNS treats the two spellings as the same name, so the dot is stripped before the host is classified. The guide contains no such URL today; this closes the bypass rather than fixing an instance. https://www.codenameone.com./does-not-exist old 0 -> new 1 https://www.codenameone.com/does-not-exist old 1 -> new 1 https://www.codenameone.com./getting-started/ new 0 (still fine) Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index 7141ca228d6..cb47bb01492 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -357,7 +357,12 @@ def findings_for(path: Path, known: set[str], patterns: list, declared: set[str] for url in URL_RE.findall(line): url = url.rstrip(".,;:") split = urlsplit(url) - host = split.hostname or "" + # urlsplit lowercases the host but keeps the root label's trailing dot, + # so the fully qualified spelling "www.codenameone.com." misses + # SITE_HOSTS and skips route validation entirely -- the same path that + # is rejected without the dot sails through with it. DNS treats the two + # as the same name, so strip it before classifying. + host = (split.hostname or "").rstrip(".") # hostname strips the port whether or not it is a number, so a typo in # the authority hides behind an otherwise correct host and every check # below passes on a URL no browser can open. Reading .port is what From b50b7952962d9133def0192ef0a448245893b79a Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 22:38:38 +0300 Subject: [PATCH 23/51] Read the fallback routes from the Function, and close the authority family Two findings, plus the structural change the last several implied. The /files and /demos fallbacks were restated here as a literal pair, so deleting one from docs/website/functions/[[path]].js would have left this accepting links to a route that no longer exists. They are now read out of the Function itself. Verified the derivation tracks the file rather than merely looking as though it does: a /demos/ link passes today, and renaming that startsWith in the Function makes the same link fail. If the Function is ever rewritten in a shape this cannot read, the derivation yields nothing and links under those prefixes start failing -- loudly, which is the safe direction. asciidoctor-pdf defines basebackend-pdf alongside backend-pdf, and the surrogate defined only the latter, so ifdef::basebackend-pdf[] content vanished from the very render meant to inspect it. Both attributes are now set: a dangling reference inside such a branch is reported. And the reason for the third change: the last several findings here were all one shape -- a spelling urlsplit tolerates that SITE_HOSTS membership does not see. Malformed port, default port, DNS root dot, each fixed individually. That family has no natural end (userinfo, IPv6 literals, mixed case, IDN), so it is now one rule instead: a same-site classification requires the authority to be the bare host and, at most, its own port. Anything else is reported rather than quietly routed around the model. https://user@www.codenameone.com/getting-started/ reported https://www.codenameone.com:8443/getting-started/ reported https://www.codenameone.com/getting-started/ fine https://www.codenameone.com:443/getting-started/ fine https://www.codenameone.com./getting-started/ fine Measured before adding it: the guide has no URL with userinfo, a non-ASCII host, an IPv6 literal or mixed case in the authority, so this rejects nothing that exists and forecloses the ones that do not. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 49 +++++++++++++++++--- scripts/developer-guide/check-guide-xrefs.py | 6 ++- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index cb47bb01492..f11e3a3e830 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -227,14 +227,28 @@ def site_paths(repo_root: Path) -> tuple[set[str], list, set[str]]: # off-site redirect: reachable, and not verifiable from this repository. # Appended AFTER the _redirects rules because the function is a fallback and # the first matching rule wins, mirroring the order the host evaluates. - for prefix in ("files", "demos"): - patterns.append( - ( - re.compile(rf"^/{prefix}(/.*)?$"), - [], - "https://download.codenameone.com/", + function = repo_root / "docs/website/functions/[[path]].js" + if function.exists(): + # Read the prefixes out of the Function rather than restating them here, + # so removing a fallback removes it from the model too. If it is ever + # rewritten in a shape this cannot read, the derivation yields nothing and + # links under those prefixes start failing -- loudly, which is the safe + # direction; a hardcoded pair would have gone on accepting them. + for prefix in sorted( + set( + re.findall( + r'path\.startsWith\("/([^/"]+)/"\)', + function.read_text(encoding="utf-8"), + ) + ) + ): + patterns.append( + ( + re.compile(rf"^/{re.escape(prefix)}(/.*)?$"), + [], + "https://download.codenameone.com/", + ) ) - ) # Hugo's published route is the section path plus the page's slug, which # 1055 of the content pages override; deriving it from the filename instead @@ -329,6 +343,16 @@ def site_paths(repo_root: Path) -> tuple[set[str], list, set[str]]: return paths, patterns, declared +def bare_authority(split, host: str, port: int | None) -> bool: + """Whether the authority carries nothing but the host and, at most, its port.""" + netloc = split.netloc.lower() + if netloc.endswith("."): + netloc = netloc[:-1] # the DNS root dot, already stripped from host + elif ":" in netloc and netloc.rsplit(":", 1)[0].endswith("."): + netloc = netloc.replace(".:", ":", 1) + return netloc == (host if port is None else f"{host}:{port}") + + def findings_for(path: Path, known: set[str], patterns: list, declared: set[str]) -> list[tuple[str, str]]: # Only http:// and https:// are extracted. Protocol-relative links were raised # as a gap; measured, the guide contains no `link://` macro at all, and its one @@ -377,6 +401,17 @@ def findings_for(path: Path, known: set[str], patterns: list, declared: set[str] continue if split.scheme == "http" and host not in TLS_EXEMPT_HOSTS | LOCAL_HOSTS: out.append((url, "plain http, not https")) + if host in SITE_HOSTS and not bare_authority(split, host, port): + # Everything below identifies the site by hostname alone, and + # urlsplit is forgiving about what else the authority may carry: + # userinfo, a bracketed literal, mixed case. Each is a different + # way of writing something this route model has not been shown to + # describe, so classify on the bare form only and report the rest, + # rather than growing one rule per spelling. Measured: the guide + # has no URL with userinfo, a non-ASCII host, an IPv6 literal or + # mixed case in the authority. + out.append((url, f"authority '{split.netloc}' is not a bare hostname")) + continue if ( host in SITE_HOSTS and port is not None diff --git a/scripts/developer-guide/check-guide-xrefs.py b/scripts/developer-guide/check-guide-xrefs.py index 730cb9c4dd4..a5418f6bfa3 100755 --- a/scripts/developer-guide/check-guide-xrefs.py +++ b/scripts/developer-guide/check-guide-xrefs.py @@ -54,7 +54,11 @@ # the PDF build includes, without needing asciidoctor-pdf here. The two runs are # checked SEPARATELY, never pooled: an anchor that exists only in the HTML branch # must not be allowed to satisfy a reference made in the PDF branch. -BACKENDS = (("html", ()), ("pdf", ("backend-pdf",))) +# asciidoctor-pdf defines basebackend-pdf alongside backend-pdf, and the guide may +# legitimately test either, so the surrogate defines both. Missing the second one +# meant ifdef::basebackend-pdf[] content vanished from the render that was meant +# to be inspecting it. +BACKENDS = (("html", ()), ("pdf", ("backend-pdf", "basebackend-pdf"))) # The surrogate has one blind spot, and it cannot be closed from the command line. # Setting backend-pdf makes `ifndef::backend-pdf[]` content disappear and # `ifdef::backend-pdf[]` content appear, which is exactly right -- verified -- and From 2a25ea86c76ec39849c76a7f55c07d984b4b02c8 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 22:46:50 +0300 Subject: [PATCH 24/51] An inline directive is content, and an attribute-built URL is unreadable The spacing scan stepped over every preprocessor directive on its way to the next surviving line. Only the BLOCK forms vanish, though: ifdef/ifndef with empty brackets open a region and leave nothing behind, and endif closes one, but the single-line form carries its content in the brackets and EXPANDS to it. Measured -- `ifdef::feature[== Inline Chapter]` renders as a real chapter when the attribute is set. So the scan was walking past a heading that the preceding paragraph was about to swallow. It now steps over block forms only, and treats a single-line directive as the content it becomes. inline ifdef right after an include old 0 -> new 1 A URL assembled from an attribute is invisible to the link scan: the declaration holds a valid site root and the use site holds only "{name}", so the path that actually ships is never checked. Expanding attributes properly means reimplementing asciidoctor's resolution, inheritance through includes included, which is a great deal of machinery for a construct the guide does not use -- measured, zero URL-valued attribute declarations and zero link:{...} targets. So both spellings are refused instead, which stops the gap opening quietly later. :site: https://www.codenameone.com old 0 -> new 1 link:{site}/missing[label] old 0 -> new 1 an ordinary URL new 0 Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 13 +++++++++++++ scripts/developer-guide/check-guide-structure.py | 11 ++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index f11e3a3e830..d85168af724 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -28,6 +28,15 @@ ASCIIDOC_EXTENSIONS = {".adoc", ".asciidoc"} URL_RE = re.compile(r"\bhttps?://[^\s\[\]<>\"'`)]+") +# A URL assembled from an attribute is invisible to the scan above: the +# declaration holds a valid site root and the use site holds only "{name}", so the +# path that actually ships is never checked. Expanding attributes properly means +# reimplementing asciidoctor's attribute resolution, including inheritance through +# includes, which is a lot of machinery for a construct the guide does not use -- +# measured: zero URL-valued attribute declarations and zero link:{...} targets. +# So both spellings are refused instead, which keeps the gap from opening quietly. +ATTRIBUTE_URL_DECL_RE = re.compile(r"^:[A-Za-z0-9_-]+:\s*https?://") +ATTRIBUTE_LINK_RE = re.compile(r"\blink:\{[^}]+\}") # The one tree that genuinely cannot be enumerated from this repository: the # Javadoc is produced from the framework sources at build time. Everything else, # /developer-guide/ included, is derived below -- whitelisting a prefix silently @@ -378,6 +387,10 @@ def findings_for(path: Path, known: set[str], patterns: list, declared: set[str] # comments do exist here, for editorial notes; none carries a URL.) out: list[tuple[str, str]] = [] for number, line in enumerate(path.read_text(encoding="utf-8").split("\n"), 1): + if ATTRIBUTE_URL_DECL_RE.match(line.strip()): + out.append((line.strip().split()[0], "an attribute holding a URL: any link built from it is unchecked, because this does not expand attributes")) + if ATTRIBUTE_LINK_RE.search(line): + out.append((ATTRIBUTE_LINK_RE.search(line).group(0), "a link target built from an attribute, which this cannot expand or check")) for url in URL_RE.findall(line): url = url.rstrip(".,;:") split = urlsplit(url) diff --git a/scripts/developer-guide/check-guide-structure.py b/scripts/developer-guide/check-guide-structure.py index 47e1d48ee04..2c82fadd1fb 100755 --- a/scripts/developer-guide/check-guide-structure.py +++ b/scripts/developer-guide/check-guide-structure.py @@ -64,6 +64,13 @@ # FENCE_RE -- a heading in a listing really is only text -- while the include walk # and the conditional test use this narrower one. COMMENT_FENCE_RE = re.compile(r"^(/{4,})\s*$") +# Only the BLOCK forms vanish. ifdef/ifndef with empty brackets open a region and +# leave nothing behind, and endif closes one; but the single-line form carries its +# content in the brackets and EXPANDS to it -- measured, `ifdef::feature[== Inline +# Chapter]` renders as a real chapter when the attribute is set. So the spacing +# scan may step over the first kind and must treat the second as content, or it +# would walk past a heading that the preceding paragraph is about to swallow. +BLOCK_DIRECTIVE_RE = re.compile(r"^(ifdef|ifndef)::[^\[]*\[\s*\]\s*$|^ifeval::\[|^endif::") # Inline AsciiDoc markup that never survives into the rendered heading text. INLINE_MARKUP_RE = re.compile(r"[`*_#]|\[\[[^\]]*\]\]|\[[^\]]*\]") @@ -273,9 +280,7 @@ def _check_include_spacing( # there. An earlier version of this rule returned here and would have # passed that. cursor = index + 1 - while cursor < len(lines) and re.match( - r"^(ifdef|ifndef|ifeval|endif)::", lines[cursor].strip() - ): + while cursor < len(lines) and BLOCK_DIRECTIVE_RE.match(lines[cursor].strip()): cursor += 1 following = lines[cursor] if cursor < len(lines) else "" if not following.strip(): From 2cc2941dc066a22a00ab6a3f51e26d7f6afb91b9 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 23:00:04 +0300 Subject: [PATCH 25/51] Three Javadoc links pointed at a package that is spelt lowercase The /javadoc/ prefix was accepted wholesale, on the stated grounds that the tree is generated at build time and cannot be enumerated from the repository. It can: build_javadocs.sh runs over two fixed source roots, so a package is a directory and a class page is a .java file. Behind that exemption sat three live 404s -- the guide linked to /javadoc/com/codename1/JavaScript/ three times, and the only tracked package is lowercase com/codename1/javascript, so a case-sensitive host served nothing while the gate reported success. macOS hides this: the checkout answers to both spellings, and only `git ls-files` tells the truth. All three links are corrected. The exemption is replaced by a derivation over CodenameOne/src and Ports/CLDC11/src, which rejects an unknown package or class and still accepts what javadoc emits beyond that model -- top-level index pages, class-use/ trees, package-summary and nested Outer.Inner.html. Measured against every javadoc link in the guide: 423 checked, 0 false positives. /javadoc/com/codename1/JavaScript/JSObject.html reported /javadoc/com/codename1/ui/NoSuchClass.html reported /javadoc/com/codename1/javascript/JSObject.html fine /javadoc/com/codename1/ui/Form.Inner.html fine /javadoc/com/codename1/ui/class-use/Form.html fine /javadoc/index.html fine An early draft let the wrong-case package through: the guard meant to admit top-level index pages also admitted any unrecognised package. Probing is what caught it -- the guide's own links all passed either way, because they had already been fixed. Root-relative targets are scanned too. `link:/does-not-exist[]` and `href="/does-not-exist"` name a website route exactly as an absolute URL does, but carry no scheme, so URL_RE never saw them, and check-guide-xrefs.py skips hrefs starting with "/" because they are not same-page anchors. They now go through the same route model. The guide has none today. The link text says `com.codename1.javascript` in backticks: the package really is lowercase, and unmarked it reads to LanguageTool as a misspelling of JavaScript. Co-Authored-By: Claude Opus 5 (1M context) --- .../The-Components-Of-Codename-One.asciidoc | 6 +- scripts/developer-guide/check-guide-links.py | 92 ++++++++++++++++++- 2 files changed, 92 insertions(+), 6 deletions(-) diff --git a/docs/developer-guide/The-Components-Of-Codename-One.asciidoc b/docs/developer-guide/The-Components-Of-Codename-One.asciidoc index 13c8c180b98..4b853b82611 100644 --- a/docs/developer-guide/The-Components-Of-Codename-One.asciidoc +++ b/docs/developer-guide/The-Components-Of-Codename-One.asciidoc @@ -1755,7 +1755,7 @@ NOTE: The JavaScript Bridge is implemented on top of the `BrowserNavigationCallb TIP: The JavaScript bridge is sometimes confused with the JavaScript Port. The JavaScript bridge allows you to communicate with JavaScript from Java (and vice versa). The JavaScript port allows you to compile the Codename One application into a JavaScript application that runs in a standard web browser without code changes (think GWT without source changes and with thread support).+ You discuss the JavaScript port further later in the guide. -Use the `BrowserComponent` API to interact with JavaScript. It replaces the deprecated https://www.codenameone.com/javadoc/com/codename1/JavaScript/package-summary.html[com.codename1.JavaScript package]. +Use the `BrowserComponent` API to interact with JavaScript. It replaces the deprecated https://www.codenameone.com/javadoc/com/codename1/javascript/package-summary.html[`com.codename1.javascript` package]. ===== What was wrong with the old API @@ -1859,7 +1859,7 @@ Coupled with `shouldNavigate` you can effectively do everything which is what th While it's possible to build everything on top of `execute` and `shouldNavigate`, both of these methods have their limits. That's why Codename One introduced the JavaScript package, it allows you to communicate with JavaScript using intuitive code/syntax. -The https://www.codenameone.com/javadoc/com/codename1/JavaScript/JavascriptContext.html[JavascriptContext] class lays the foundation by enabling you to call JavaScript code directly from Java. It provides automatic type conversion between Java and JavaScript types as follows: +The https://www.codenameone.com/javadoc/com/codename1/javascript/JavascriptContext.html[JavascriptContext] class lays the foundation by enabling you to call JavaScript code directly from Java. It provides automatic type conversion between Java and JavaScript types as follows: .Java to JavaScript [cols="2*",options="header"] @@ -1888,7 +1888,7 @@ The https://www.codenameone.com/javadoc/com/codename1/JavaScript/JavascriptConte | `undefined` | `null` |==== -NOTE: This conversion table is more verbose than necessary, since JavaScript functions and arrays are, in fact Objects themselves, so those rows are redundant. All JavaScript objects are converted to https://www.codenameone.com/javadoc/com/codename1/JavaScript/JSObject.html[JSObject]. +NOTE: This conversion table is more verbose than necessary, since JavaScript functions and arrays are, in fact Objects themselves, so those rows are redundant. All JavaScript objects are converted to https://www.codenameone.com/javadoc/com/codename1/javascript/JSObject.html[JSObject]. You can access JavaScript variables from the context by using code like this: diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index d85168af724..a3f3bac4eb5 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -23,7 +23,7 @@ import datetime import re import sys -from pathlib import Path +from pathlib import Path, PurePosixPath from urllib.parse import urlsplit ASCIIDOC_EXTENSIONS = {".adoc", ".asciidoc"} @@ -37,11 +37,17 @@ # So both spellings are refused instead, which keeps the gap from opening quietly. ATTRIBUTE_URL_DECL_RE = re.compile(r"^:[A-Za-z0-9_-]+:\s*https?://") ATTRIBUTE_LINK_RE = re.compile(r"\blink:\{[^}]+\}") +# A root-relative target names a website route just as an absolute URL does, but +# it carries no scheme, so URL_RE never sees it -- and check-guide-xrefs.py skips +# hrefs beginning with "/" because they are not same-page anchors. Between the two +# gates the route went unchecked, so it is run through the same route model here. +ROOT_RELATIVE_RE = re.compile(r"""(?:\blink:|\bhref=["'])(/[^\s\[\]"'`>]*)""") # The one tree that genuinely cannot be enumerated from this repository: the # Javadoc is produced from the framework sources at build time. Everything else, # /developer-guide/ included, is derived below -- whitelisting a prefix silently # exempts every path under it from the check. GENERATED_PREFIXES = ("/javadoc/",) +_JAVADOC_ROOT: Path | None = None # http:// is correct for these: RFC 3161 timestamping servers reject TLS, and # example.com URLs are illustrative rather than fetched. TLS_EXEMPT_HOSTS = {"timestamp.digicert.com", "example.com", "www.example.com"} @@ -154,6 +160,77 @@ def redirect_pattern(source: str) -> tuple[re.Pattern[str], list[str]] | None: return re.compile("^" + pattern + "/?$"), names +# build_javadocs.sh generates the API docs from these two roots, so the published +# tree is derivable from the repository without building it. +JAVADOC_SOURCE_ROOTS = ("CodenameOne/src", "Ports/CLDC11/src") +# Pages javadoc emits for a package rather than for a type. +JAVADOC_PACKAGE_PAGES = { + "package-summary.html", + "package-frame.html", + "package-use.html", + "package-tree.html", +} +_javadoc_index: tuple[set[str], set[str]] | None = None + + +def javadoc_index(repo_root: Path) -> tuple[set[str], set[str]]: + """Package directories and class names the generated Javadoc will contain.""" + global _javadoc_index + if _javadoc_index is not None: + return _javadoc_index + packages: set[str] = set() + classes: set[str] = set() + for root_name in JAVADOC_SOURCE_ROOTS: + root = repo_root / root_name + if not root.exists(): + continue + for source in root.rglob("*.java"): + relative = source.relative_to(root) + package = relative.parent.as_posix() + packages.add(package) + classes.add(f"{package}/{relative.stem}") + _javadoc_index = (packages, classes) + return _javadoc_index + + +def javadoc_path_exists(target: str) -> bool: + """Whether a /javadoc/ path names something the generated tree will hold. + + The prefix used to be accepted wholesale, on the grounds that the tree is + generated at build time and cannot be enumerated here. It can: the generator + runs over two fixed source roots, so a package is a directory and a class page + is a .java file. That distinction matters -- the guide linked three times to + /javadoc/com/codename1/JavaScript/, and the package is lowercase, so a + case-sensitive host served 404s while this reported success. + + Anything that is not a recognisable package or class page is still accepted: + javadoc emits index pages, class-use trees and frames this does not model, and + reporting those would be a false alarm rather than a finding. + """ + if _JAVADOC_ROOT is None: + return True + path = target[len("/javadoc/"):] if target.startswith("/javadoc/") else target + if not path.endswith(".html"): + return True # a directory or an asset, not a documented type + packages, classes = javadoc_index(_JAVADOC_ROOT) + package = str(PurePosixPath(path).parent) + page = PurePosixPath(path).name + if package == ".": + return True # a top-level index or overview page, outside the model + # class-use/ holds one page per type, alongside the package it belongs to. + if package.endswith("/class-use"): + package = package[: -len("/class-use")] + if package not in packages: + # The package itself will not exist in the generated tree. This is the + # case that mattered: com/codename1/JavaScript is spelt lowercase in the + # sources, so the published path 404s on a case-sensitive host. + return False + if page in JAVADOC_PACKAGE_PAGES: + return True + # A nested type is documented as Outer.Inner.html, generated from Outer.java. + return f"{package}/{page[:-5].split('.')[0]}" in classes + + def resolves(target: str, known: set[str], rules: list, depth: int = 0) -> bool: """Whether a path is served, following wildcard redirects to their destination. @@ -167,8 +244,10 @@ def resolves(target: str, known: set[str], rules: list, depth: int = 0) -> bool: return True if target.startswith(GENERATED_PREFIXES) or target + "/" in GENERATED_PREFIXES: # Reachable both directly and by following a redirect into it, so the - # test belongs here rather than only at the call site. - return True + # test belongs here rather than only at the call site. The javadoc tree is + # not accepted wholesale -- javadoc_path_exists() checks the package and + # class against the sources it is generated from. + return javadoc_path_exists(target) if depth > 4: # a redirect loop in the table should not hang the check return False for compiled, names, destination in rules: @@ -391,6 +470,11 @@ def findings_for(path: Path, known: set[str], patterns: list, declared: set[str] out.append((line.strip().split()[0], "an attribute holding a URL: any link built from it is unchecked, because this does not expand attributes")) if ATTRIBUTE_LINK_RE.search(line): out.append((ATTRIBUTE_LINK_RE.search(line).group(0), "a link target built from an attribute, which this cannot expand or check")) + for target in ROOT_RELATIVE_RE.findall(line): + path = target.split("#", 1)[0].split("?", 1)[0] + normalized = normalize_path(path) + if not resolves(normalized, known, patterns): + out.append((target, "the website serves no such path (checked _redirects and the content tree)")) for url in URL_RE.findall(line): url = url.rstrip(".,;:") split = urlsplit(url) @@ -497,6 +581,8 @@ def main() -> int: args = parser.parse_args() guide_dir = args.guide_dir.resolve() + global _JAVADOC_ROOT + _JAVADOC_ROOT = args.repo_root.resolve() known, patterns, declared = site_paths(args.repo_root.resolve()) if not known: raise SystemExit("could not derive any site paths; is --repo-root correct?") From 50cf047e421cedd5398c807e546f2ff47c635f3c Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 23:06:30 +0300 Subject: [PATCH 26/51] The Javadoc index documented a package the build deliberately removes Two gaps between what the model claims and what the generators produce. build_javadocs.sh filters /com/codename1/impl/ out of its source list, passes -exclude for the package, and then guards that it never reached the output -- three separate refusals. The index built here recorded every .java under the source roots, so a link to /javadoc/com/codename1/impl/ARImpl.html was accepted against a page the build goes out of its way not to produce. The exclusion is now mirrored, subpackages included. /javadoc/com/codename1/impl/ARImpl.html old 0 -> new 1 /javadoc/com/codename1/ui/Form.html new 0 Note the first probe of this proved nothing: ImplementationFactory is written into tempJavaSources by the generator itself, so it was absent from the old index too and both versions reported it. A class that really is in CodenameOne/src was needed to tell them apart. The publication test read only `date`, so Hugo's publishDate and expiryDate were invisible: scheduling a page forward or expiring it removes the route from the built site while a guide link to it went on passing. Both are honoured now. A date-only expiry lapses at midnight, so the day itself is already too late. no dates / past date / past publishDate / expires later published future date / future publishDate / expired / draft not published Neither construct appears in the repository today -- no guide link into impl, no page carrying either field -- so both close a gap rather than fix an instance. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 25 ++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index a3f3bac4eb5..b7ceda92fa9 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -120,8 +120,20 @@ def is_published(meta: dict[str, object], today: str) -> bool: """ if str(meta.get("draft", "")).strip().strip("\"'").lower() in {"true", "yes"}: return False - date = str(meta.get("date", "")).strip().strip("\"'") - return not (re.match(r"^\d{4}-\d{2}-\d{2}", date) and date[:10] > today) + + def day(key: str) -> str | None: + value = str(meta.get(key, "")).strip().strip("\"'") + return value[:10] if re.match(r"^\d{4}-\d{2}-\d{2}", value) else None + + # Hugo builds neither a future page nor an expired one. publishDate overrides + # date for scheduling, and expiryDate withdraws a page that was published; a + # date-only expiry lapses at midnight, so the day itself is already too late. + for key in ("date", "publishDate"): + scheduled = day(key) + if scheduled and scheduled > today: + return False + expiry = day("expiryDate") + return not (expiry and expiry <= today) def normalize_path(value: str) -> str: @@ -164,6 +176,10 @@ def redirect_pattern(source: str) -> tuple[re.Pattern[str], list[str]] | None: # tree is derivable from the repository without building it. JAVADOC_SOURCE_ROOTS = ("CodenameOne/src", "Ports/CLDC11/src") # Pages javadoc emits for a package rather than for a type. +# build_javadocs.sh filters these out of its source list, passes -exclude for them +# and then guards that they never reached the output. Recording them here would +# accept a link to a page the published tree deliberately does not contain. +JAVADOC_EXCLUDED_PACKAGES = ("com/codename1/impl",) JAVADOC_PACKAGE_PAGES = { "package-summary.html", "package-frame.html", @@ -187,6 +203,11 @@ def javadoc_index(repo_root: Path) -> tuple[set[str], set[str]]: for source in root.rglob("*.java"): relative = source.relative_to(root) package = relative.parent.as_posix() + if any( + package == excluded or package.startswith(excluded + "/") + for excluded in JAVADOC_EXCLUDED_PACKAGES + ): + continue packages.add(package) classes.add(f"{package}/{relative.stem}") _javadoc_index = (packages, classes) From 21e5d5cbf047a092363c83447ea780724b6261d8 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 23:15:26 +0300 Subject: [PATCH 27/51] Javadoc documents public types, and the index was recording every source file The generator runs javadoc with -protected, which documents public and protected types only; a top-level type cannot be protected, so in practice it is public or it gets no page. The index recorded a class for every .java under the source roots, so a link to a package-private type was accepted against a page that is never generated -- com.codename1.io.JSONSanitizer is declared `final class`, and /javadoc/com/codename1/io/JSONSanitizer.html passed. Only public top-level types are indexed now. Comments are stripped first, because a sample inside a javadoc block can easily put the word "public" next to a class name. package-info is dropped by name: it declares no type, and javadoc folds its content into package-summary.html, which the package check already covers. Validated against every javadoc link in the guide before trusting it -- 423 checked, 0 rejected -- so this narrows the index by 366 of 2211 sources without touching a single real link. /javadoc/com/codename1/io/JSONSanitizer.html old 0 -> new 1 /javadoc/com/codename1/io/Log.html new 0 /javadoc/com/codename1/ui/Form.Inner.html new 0 /javadoc/com/codename1/io/package-summary.html new 0 Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 28 +++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index b7ceda92fa9..c98feea8180 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -180,6 +180,15 @@ def redirect_pattern(source: str) -> tuple[re.Pattern[str], list[str]] | None: # and then guards that they never reached the output. Recording them here would # accept a link to a page the published tree deliberately does not contain. JAVADOC_EXCLUDED_PACKAGES = ("com/codename1/impl",) +# The generator runs javadoc with -protected, which documents public and protected +# types only. A top-level type cannot be protected, so in practice: public or it +# gets no page. Comments are stripped before this is applied, because a sample in +# a javadoc block can easily contain the word "public" next to a class name. +JAVA_BLOCK_COMMENT_RE = re.compile(r"/\*.*?\*/", re.S) +JAVA_LINE_COMMENT_RE = re.compile(r"//[^\n]*") +PUBLIC_TYPE_RE = ( + r"\bpublic\b[^;{{]*?\b(?:class|interface|enum|record|@interface)\s+{stem}\b" +) JAVADOC_PACKAGE_PAGES = { "package-summary.html", "package-frame.html", @@ -189,6 +198,22 @@ def redirect_pattern(source: str) -> tuple[re.Pattern[str], list[str]] | None: _javadoc_index: tuple[set[str], set[str]] | None = None +def is_public_type(source: Path, stem: str) -> bool: + """Whether the file declares its top-level type public, so javadoc documents it. + + package-info carries no type and is excluded by name; javadoc emits its content + into package-summary.html, which the package check already covers. + """ + if stem == "package-info": + return False + try: + text = source.read_text(encoding="utf-8", errors="ignore") + except OSError: + return False + text = JAVA_LINE_COMMENT_RE.sub("", JAVA_BLOCK_COMMENT_RE.sub("", text)) + return re.search(PUBLIC_TYPE_RE.format(stem=re.escape(stem)), text) is not None + + def javadoc_index(repo_root: Path) -> tuple[set[str], set[str]]: """Package directories and class names the generated Javadoc will contain.""" global _javadoc_index @@ -209,7 +234,8 @@ def javadoc_index(repo_root: Path) -> tuple[set[str], set[str]]: ): continue packages.add(package) - classes.add(f"{package}/{relative.stem}") + if is_public_type(source, relative.stem): + classes.add(f"{package}/{relative.stem}") _javadoc_index = (packages, classes) return _javadoc_index From 4c34787fabc4d3fc0417466b8abcfb1341719a4d Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 23:23:13 +0300 Subject: [PATCH 28/51] An uppercase scheme was invisible, and the two slash rules had drifted apart URL_RE required a lowercase scheme, so link:HTTPS://www.codenameone.com/... was extracted by nothing and skipped every check behind it. Schemes are case-insensitive; the extraction is now too, and urlsplit already lowercases what it returns, so nothing downstream changes. link:HTTPS://... /does-not-exist old 0 -> new 1 link:HTTPS://... /getting-started/ new 0 lowercase, bad route unchanged The trailing-slash rule existed only on the absolute-URL path, so a root-relative link to a static file with a slash appended -- link:/favicon.ico/ -- was normalised down to the existing asset and accepted, while the identical absolute URL was reported. That is the sort of split that happens when the same rule is written twice, so it is now written once and called from both. link:/favicon.ico/ old 0 -> new 1 link:/videos.html/ new 0 (declared in _redirects) link:/developer-guide/ new 0 (a directory route) Neither spelling appears in the guide today. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 41 ++++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index c98feea8180..0a7e16d68a7 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -27,7 +27,7 @@ from urllib.parse import urlsplit ASCIIDOC_EXTENSIONS = {".adoc", ".asciidoc"} -URL_RE = re.compile(r"\bhttps?://[^\s\[\]<>\"'`)]+") +URL_RE = re.compile(r"\bhttps?://[^\s\[\]<>\"'`)]+", re.IGNORECASE) # A URL assembled from an attribute is invisible to the scan above: the # declaration holds a valid site root and the use site holds only "{name}", so the # path that actually ships is never checked. Expanding attributes properly means @@ -41,7 +41,7 @@ # it carries no scheme, so URL_RE never sees it -- and check-guide-xrefs.py skips # hrefs beginning with "/" because they are not same-page anchors. Between the two # gates the route went unchecked, so it is run through the same route model here. -ROOT_RELATIVE_RE = re.compile(r"""(?:\blink:|\bhref=["'])(/[^\s\[\]"'`>]*)""") +ROOT_RELATIVE_RE = re.compile(r"""(?:\blink:|\bhref=["'])(/[^\s\[\]"'`>]*)""", re.IGNORECASE) # The one tree that genuinely cannot be enumerated from this repository: the # Javadoc is produced from the framework sources at build time. Everything else, # /developer-guide/ included, is derived below -- whitelisting a prefix silently @@ -488,6 +488,22 @@ def bare_authority(split, host: str, port: int | None) -> bool: return netloc == (host if port is None else f"{host}:{port}") +def undeclared_file_slash(path: str, declared: set[str]) -> bool: + """A file-like path wearing a trailing slash the redirect table does not spell out. + + The site treats "/x.html" and "/x.html/" as separate routes and declares both + where both work -- 32 such pairs in _redirects. Every rule compiled here is + slash-insensitive, so normalising would silently validate the variant that was + not asked for. Directory routes such as /blog/ and /javadoc/com/codename1/io/ + have no dot in the last segment and never match. + """ + return ( + path.endswith("/") + and "." in path.rstrip("/").rsplit("/", 1)[-1] + and path not in declared + ) + + def findings_for(path: Path, known: set[str], patterns: list, declared: set[str]) -> list[tuple[str, str]]: # Only http:// and https:// are extracted. Protocol-relative links were raised # as a gap; measured, the guide contains no `link://` macro at all, and its one @@ -519,6 +535,11 @@ def findings_for(path: Path, known: set[str], patterns: list, declared: set[str] out.append((ATTRIBUTE_LINK_RE.search(line).group(0), "a link target built from an attribute, which this cannot expand or check")) for target in ROOT_RELATIVE_RE.findall(line): path = target.split("#", 1)[0].split("?", 1)[0] + if undeclared_file_slash(path, declared): + # Same rule as for an absolute URL: normalize_path would drop the + # slash and validate the variant that was not asked for. + out.append((target, "a file path with a trailing slash that _redirects does not declare")) + continue normalized = normalize_path(path) if not resolves(normalized, known, patterns): out.append((target, "the website serves no such path (checked _redirects and the content tree)")) @@ -574,21 +595,7 @@ def findings_for(path: Path, known: set[str], patterns: list, declared: set[str] target = split.path.rstrip("/") or "/" if split.fragment and target in SELF_PATHS: out.append((url, "links into this book's own body; use an xref so the anchor is checked")) - elif ( - split.path.endswith("/") - and "." in split.path.rstrip("/").rsplit("/", 1)[-1] - and split.path not in declared - ): - # The site treats "/x.html" and "/x.html/" as separate routes and - # spells both out where both work -- 32 such pairs in _redirects. - # Every rule here compiles slash-insensitively, so the normalised - # lookup below would silently validate the variant that was NOT - # asked for. Hence: a file path wearing a trailing slash is - # reported, UNLESS _redirects declares that exact spelling, which - # is the site saying it serves it -- "/videos.html/" is declared - # and must not be reported. Directory routes such as /blog/ and - # /javadoc/com/codename1/io/ have no dot in the last segment and - # never reach this branch. + elif undeclared_file_slash(split.path, declared): out.append((url, "a file path with a trailing slash that _redirects does not declare")) elif not resolves(target, known, patterns): out.append((url, "the website serves no such path (checked _redirects and the content tree)")) From 6c1c94573244f73a8f9392c95ec59ce1e8262832 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 23:31:17 +0300 Subject: [PATCH 29/51] A nested type was taken on trust, and an include hid inside an inline conditional The nested-type branch split Outer.Inner.html at the first dot and checked only that Outer.java exists, so any invented page was accepted -- /javadoc/com/codename1/ui/Component.DoesNotExist.html passed against a page javadoc cannot generate. The innermost name is now required to be declared in the outer type's own file, which is the only place javadoc could find it. Nested declarations may be protected as well as public, and -protected documents both, so the visibility test differs from the top-level one. Validated against the guide before trusting it: 423 javadoc links checked, 0 rejected, including all six distinct nested pages -- ActionEvent.Type, URLImage.ImageAdapter, TableLayout.Constraint, BrowserComponent.JSRef, BrowserComponent.JSProxy and the doubly nested LayeredLayout.LayeredLayoutConstraint.Inset. Component.DoesNotExist.html old 0 -> new 1 ActionEvent.Type.html new 0 LayeredLayout.LayeredLayoutConstraint.Inset.html new 0 Separately, `ifdef::feature[include::chapter.adoc[]]` is expanded and processed by asciidoctor, but INCLUDE_RE is anchored at the start of the line, so the walker saw nothing there and the edge went uncounted -- a chapter included both this way and normally would render twice with the counter still reading one. Refused, for the same reason every other conditional include is: neither the duplicate count nor the rendered-title check can model one. The guide contains none. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 30 ++++++++++++++++++- .../developer-guide/check-guide-structure.py | 14 +++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index 0a7e16d68a7..08be6737231 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -189,6 +189,12 @@ def redirect_pattern(source: str) -> tuple[re.Pattern[str], list[str]] | None: PUBLIC_TYPE_RE = ( r"\bpublic\b[^;{{]*?\b(?:class|interface|enum|record|@interface)\s+{stem}\b" ) +# A NESTED type may be protected as well as public, and javadoc -protected +# documents both. It is declared inside the outer type's own file, so that is +# where to look. +NESTED_TYPE_RE = ( + r"\b(?:public|protected)\b[^;{{]*?\b(?:class|interface|enum|record|@interface)\s+{stem}\b" +) JAVADOC_PACKAGE_PAGES = { "package-summary.html", "package-frame.html", @@ -240,6 +246,20 @@ def javadoc_index(repo_root: Path) -> tuple[set[str], set[str]]: return _javadoc_index +def declares_nested_type(package: str, outer: str, nested: str) -> bool: + """Whether the outer type's source declares a documented nested type.""" + if _JAVADOC_ROOT is None: + return True + for root_name in JAVADOC_SOURCE_ROOTS: + source = _JAVADOC_ROOT / root_name / package / f"{outer}.java" + if not source.exists(): + continue + text = source.read_text(encoding="utf-8", errors="ignore") + text = JAVA_LINE_COMMENT_RE.sub("", JAVA_BLOCK_COMMENT_RE.sub("", text)) + return re.search(NESTED_TYPE_RE.format(stem=re.escape(nested)), text) is not None + return True # the outer source moved; the class check above already spoke + + def javadoc_path_exists(target: str) -> bool: """Whether a /javadoc/ path names something the generated tree will hold. @@ -275,7 +295,15 @@ def javadoc_path_exists(target: str) -> bool: if page in JAVADOC_PACKAGE_PAGES: return True # A nested type is documented as Outer.Inner.html, generated from Outer.java. - return f"{package}/{page[:-5].split('.')[0]}" in classes + parts = page[:-5].split(".") + if f"{package}/{parts[0]}" not in classes: + return False + if len(parts) == 1: + return True + # javadoc emits a page for a nested type only where one is declared, so the + # innermost name has to appear in the outer type's file. Checking the outer + # name alone accepted Component.DoesNotExist.html. + return declares_nested_type(package, parts[0], parts[-1]) def resolves(target: str, known: set[str], rules: list, depth: int = 0) -> bool: diff --git a/scripts/developer-guide/check-guide-structure.py b/scripts/developer-guide/check-guide-structure.py index 2c82fadd1fb..dd529d43260 100755 --- a/scripts/developer-guide/check-guide-structure.py +++ b/scripts/developer-guide/check-guide-structure.py @@ -30,6 +30,7 @@ ASCIIDOC_EXTENSIONS = {".adoc", ".asciidoc"} INCLUDE_RE = re.compile(r"^include::([^\[]+)\[([^\]]*)\]\s*$") +INLINE_CONDITIONAL_INCLUDE_RE = re.compile(r"^(ifdef|ifndef|ifeval)::[^\[]*\[.*include::") HEADING_RE = re.compile(r"^(=+) +(\S.*)$") # Literal-content blocks only. The container delimiters -- ==== example, # **** sidebar, ____ quote -- hold ordinary AsciiDoc, so an include or a heading @@ -152,6 +153,19 @@ def _visit(self, path: Path, attrs_from_parent: str) -> None: continue if open_fence is not None: continue + if INLINE_CONDITIONAL_INCLUDE_RE.match(line): + # asciidoctor expands the bracket content and processes the include + # inside it; INCLUDE_RE is anchored, so the line looked like nothing + # at all and the edge went uncounted. Refused for the same reason as + # any other conditional include: neither the duplicate count nor the + # rendered-title check can model one. + self.errors.append( + f"{path.name}:{index + 1}: an include inside an inline conditional. " + f"asciidoctor expands and processes it, but neither the duplicate " + f"check nor the rendered-title check can model a conditional " + f"include, so this refuses it rather than skipping it silently." + ) + continue match = INCLUDE_RE.match(line) if not match: continue From db15d73140b30c81a47db13f3181dacc7445603a Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 23:38:36 +0300 Subject: [PATCH 30/51] An invented middle level passed, and xref: was a third spelling nobody read The nested-type check verified the ends of the chain and discarded everything between, so an invented middle level was accepted: /javadoc/com/codename1/ui/CommonProgressAnimations.Fake.CircleProgress.html passed because both CommonProgressAnimations and CircleProgress are real, while Fake is not declared anywhere. Every component is checked now. What this deliberately does not verify is that the names nest in the ORDER given. That needs brace-depth parsing of the outer source, and a page naming two real siblings the wrong way round is a much less likely mistake than naming a level that does not exist. The limit is written down rather than left to be rediscovered. CommonProgressAnimations.Fake.CircleProgress.html old 0 -> new 1 CommonProgressAnimations.CircleProgress.html new 0 Component.DoesNotExist.html unchanged And xref: is a third way to write a root-relative target, alongside link: and a raw href=. Asciidoctor renders it as a root-relative href, which check-guide-xrefs.py skips because it is not a same-page anchor, so the route went unchecked by both gates. Added to the same extraction. xref:/does-not-exist[label] old 0 -> new 1 xref:/developer-guide/[label] new 0 Re-validated against the guide: 423 javadoc links, 0 rejected. The guide has no xref: macro at all. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index 08be6737231..0913f8ef739 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -41,7 +41,9 @@ # it carries no scheme, so URL_RE never sees it -- and check-guide-xrefs.py skips # hrefs beginning with "/" because they are not same-page anchors. Between the two # gates the route went unchecked, so it is run through the same route model here. -ROOT_RELATIVE_RE = re.compile(r"""(?:\blink:|\bhref=["'])(/[^\s\[\]"'`>]*)""", re.IGNORECASE) +ROOT_RELATIVE_RE = re.compile( + r"""(?:\blink:|\bxref:|\bhref=["'])(/[^\s\[\]"'`>]*)""", re.IGNORECASE +) # The one tree that genuinely cannot be enumerated from this repository: the # Javadoc is produced from the framework sources at build time. Everything else, # /developer-guide/ included, is derived below -- whitelisting a prefix silently @@ -300,10 +302,17 @@ def javadoc_path_exists(target: str) -> bool: return False if len(parts) == 1: return True - # javadoc emits a page for a nested type only where one is declared, so the - # innermost name has to appear in the outer type's file. Checking the outer - # name alone accepted Component.DoesNotExist.html. - return declares_nested_type(package, parts[0], parts[-1]) + # javadoc emits a page for a nested type only where one is declared, and every + # level of the chain is declared inside the outermost type's file. Checking the + # ends alone let an invented middle through: + # CommonProgressAnimations.Fake.CircleProgress.html passed because both + # CommonProgressAnimations and CircleProgress are real. Each name is checked + # now. What this still does not verify is that they nest in the ORDER given -- + # that needs brace-depth parsing, and a page naming two real siblings the wrong + # way round is a far less likely mistake than naming one that does not exist. + return all( + declares_nested_type(package, parts[0], nested) for nested in parts[1:] + ) def resolves(target: str, known: set[str], rules: list, depth: int = 0) -> bool: From c3ebc41dfd8ac318f23482d42e76831742e74675 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 23:43:15 +0300 Subject: [PATCH 31/51] The publication-date fix was inert: the parser never stored the keys Two rounds ago is_published() learned to honour Hugo's publishDate and expiryDate. It could not: front_matter() matches an ALLOWLIST -- url|slug|aliases|draft|date -- so neither key was ever stored and both lookups read empty on every page. The check ran and decided nothing. I verified that change by calling is_published() with a dict I wrote by hand, which is exactly the half that already worked. The parser feeding it was never exercised. Proven now by running both versions over a real file: with the fix parsed ['publishdate'] -> published False without it parsed [] -> published True The keys are in the allowlist now, matched case-insensitively and stored lowercased, because Hugo treats front-matter keys case-insensitively and this tree mixes YAML and TOML. Eight cases pass end to end THROUGH front_matter -- YAML and TOML spellings, future and past publishDate, expired and not-yet-expired expiryDate, a lowercase key, and draft. The site path count is unchanged at 4739, so widening the allowlist moved nothing else. The docstring now says the list is an allowlist, since that is the property that made a whole check silently do nothing. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index 0913f8ef739..b3786173682 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -73,7 +73,9 @@ def front_matter(page: Path) -> dict[str, object]: """Pull the few front-matter keys that decide a page's published route. Deliberately not a YAML parse: the tree mixes YAML and TOML front matter and - only three keys matter here. + only a few keys matter here. Note the list is an allowlist -- a key absent from + it reads as empty downstream, which is how publishDate and expiryDate came to + be queried by is_published() while never being stored. """ text = page.read_text(encoding="utf-8", errors="ignore") lines = text.split("\n") @@ -97,10 +99,16 @@ def front_matter(page: Path) -> dict[str, object]: aliases.append(stripped.lstrip("- ").strip().rstrip(",").strip("\"'")) continue in_aliases = False - match = re.match(r'^(url|slug|aliases|draft|date)\s*[:=]\s*(.*)$', line) + # Hugo treats front-matter keys case-insensitively, and this tree mixes + # YAML and TOML, so match either spelling and store one canonical form. + match = re.match( + r'^(url|slug|aliases|draft|date|publishdate|expirydate)\s*[:=]\s*(.*)$', + line, + re.IGNORECASE, + ) if not match: continue - key, raw = match.group(1), match.group(2).strip() + key, raw = match.group(1).lower(), match.group(2).strip() if key == "aliases": if raw in {"", "[", "[]"}: in_aliases = raw != "[]" @@ -130,11 +138,11 @@ def day(key: str) -> str | None: # Hugo builds neither a future page nor an expired one. publishDate overrides # date for scheduling, and expiryDate withdraws a page that was published; a # date-only expiry lapses at midnight, so the day itself is already too late. - for key in ("date", "publishDate"): + for key in ("date", "publishdate"): scheduled = day(key) if scheduled and scheduled > today: return False - expiry = day("expiryDate") + expiry = day("expirydate") return not (expiry and expiry <= today) From a1fa03ddfbf6ad2d4a319c0e8bd834ac2c20ac6c Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 2 Sep 2026 23:55:18 +0300 Subject: [PATCH 32/51] Real nesting, real timestamps, and a comment stripper that ate braces Four findings, and implementing the first one exposed a bug of my own that the other checks had been quietly relying on not hitting. Nesting is parsed now rather than approximated. Asking only whether each name is declared SOMEWHERE in the outer file accepted two siblings written as if one contained the other -- CommonProgressAnimations.CircleProgress.EmptyAnimation names two real types, neither inside the other. The chain is walked with brace depth and an enclosing stack, and recorded only when every level is public or protected. I had deferred exactly this last round on the grounds that a wrong ORDER was unlikely; the reviewer produced a concrete instance, so the argument does not hold. Doing it needed the sources parsed properly, which is where my comment stripping turned out to be wrong: it blanked line comments BEFORE string literals, so the "//" inside "https://..." ate the rest of that line -- opening braces included. Brace depth went negative at URLImage.java:650 and the file's own class appeared to close early, which is why three real nested types were rejected on the first attempt. Blanking is now a single scan with no ordering to get wrong, and is shared with is_public_type(), which had the same hazard. Checked across all 2211 sources: braces balance in every one. CircleProgress.EmptyAnimation (siblings) reported Fake.CircleProgress (invented middle) reported Component.DoesNotExist reported CircleProgress / ImageAdapter / JSRef fine LayeredLayoutConstraint.Inset fine Publication now follows Hugo. publishDate DECIDES availability when set and date is only the fallback, where before a future `date` alongside a past `publishDate` was rejected -- a page Hugo publishes. And the comparison keeps the time of day: the site rebuilds once daily, so a page scheduled for later today is genuinely absent until then, and truncating to the calendar day called it live. Nine cases pass end to end through front_matter, both fence styles included. An attributed admonition is an admonition. [NOTE,caption="Aside"] fell out of the lookahead, which required the bracket immediately after the name, so it read as the listing the preceding colon promised. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 169 ++++++++++++++---- .../check-missing-code-blocks.py | 5 +- 2 files changed, 143 insertions(+), 31 deletions(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index b3786173682..8e6dbd6b703 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -121,29 +121,50 @@ def front_matter(page: Path) -> dict[str, object]: return out -def is_published(meta: dict[str, object], today: str) -> bool: +def parse_moment(value: str) -> datetime.datetime | None: + """Parse a Hugo front-matter timestamp, with or without a time of day.""" + text = value.strip().strip("\"'") + if not text: + return None + text = text.replace("Z", "+00:00") + if " " in text and "T" not in text: + text = text.replace(" ", "T", 1) + try: + moment = datetime.datetime.fromisoformat(text) + except ValueError: + try: + moment = datetime.datetime.fromisoformat(text[:10]) + except ValueError: + return None + if moment.tzinfo is None: + moment = moment.replace(tzinfo=datetime.timezone.utc) + return moment + + +def is_published(meta: dict[str, object], now: datetime.datetime) -> bool: """Hugo defaults buildDrafts and buildFuture to false, so neither reaches the site. - The date test makes the result depend on the day it runs, which is not ideal in - a gate. It is kept because it mirrors what the site actually serves: a link to a + The date test makes the result depend on when it runs, which is not ideal in a + gate. It is kept because it mirrors what the site actually serves: a link to a post that has not been published yet is genuinely broken until it is. + + publishDate DECIDES availability when it is set; date is only the fallback. + Treating either as disqualifying rejected a page that carries a future `date` + and a past `publishDate`, which Hugo publishes. And the comparison keeps the + time of day: the site rebuilds once a day, so a page scheduled for later today + is genuinely absent until the next build, and truncating to the calendar day + called it live. """ if str(meta.get("draft", "")).strip().strip("\"'").lower() in {"true", "yes"}: return False - def day(key: str) -> str | None: - value = str(meta.get(key, "")).strip().strip("\"'") - return value[:10] if re.match(r"^\d{4}-\d{2}-\d{2}", value) else None - - # Hugo builds neither a future page nor an expired one. publishDate overrides - # date for scheduling, and expiryDate withdraws a page that was published; a - # date-only expiry lapses at midnight, so the day itself is already too late. - for key in ("date", "publishdate"): - scheduled = day(key) - if scheduled and scheduled > today: - return False - expiry = day("expirydate") - return not (expiry and expiry <= today) + published_at = parse_moment(str(meta.get("publishdate", ""))) or parse_moment( + str(meta.get("date", "")) + ) + if published_at and published_at > now: + return False + expires_at = parse_moment(str(meta.get("expirydate", ""))) + return not (expires_at and expires_at <= now) def normalize_path(value: str) -> str: @@ -226,7 +247,7 @@ def is_public_type(source: Path, stem: str) -> bool: text = source.read_text(encoding="utf-8", errors="ignore") except OSError: return False - text = JAVA_LINE_COMMENT_RE.sub("", JAVA_BLOCK_COMMENT_RE.sub("", text)) + text = blank_java_noise(text) return re.search(PUBLIC_TYPE_RE.format(stem=re.escape(stem)), text) is not None @@ -256,17 +277,107 @@ def javadoc_index(repo_root: Path) -> tuple[set[str], set[str]]: return _javadoc_index -def declares_nested_type(package: str, outer: str, nested: str) -> bool: - """Whether the outer type's source declares a documented nested type.""" +JAVA_TOKEN_RE = re.compile( + r"(?P\b(?:class|interface|enum|record)\s+(?P[A-Za-z_$][\w$]*))" + r"|(?P\{)|(?P\})" +) + + +def blank_java_noise(text: str) -> str: + """Blank comments and literals in one pass, preserving every offset. + + Order matters and separate regexes get it wrong in both directions: running the + line-comment pattern first eats from the "//" inside "https://..." to the end of + that line, which silently swallowed an opening brace and sent the depth count + negative; running the literal pattern first lets an apostrophe inside a comment + open a char literal that runs to the next one, somewhere else entirely. A single + scan has no ordering to get wrong. + """ + out = list(text) + i, n = 0, len(text) + while i < n: + ch = text[i] + if ch == "/" and i + 1 < n and text[i + 1] in "/*": + block = text[i + 1] == "*" + end = text.find("*/", i + 2) if block else text.find("\n", i) + end = (end + 2) if (block and end != -1) else (n if end == -1 else end) + for j in range(i, end): + if out[j] != "\n": + out[j] = " " + i = end + continue + if ch in "\"'": + quote, j = ch, i + 1 + while j < n: + if text[j] == "\\": + j += 2 + continue + if text[j] == quote or text[j] == "\n": + break + j += 1 + for k in range(i, min(j + 1, n)): + if out[k] != "\n": + out[k] = " " + i = j + 1 + continue + i += 1 + return "".join(out) + + +def documented_type_chains(source: Path) -> set[str]: + """Every dotted type chain javadoc will emit a page for, from one source file. + + The earlier version asked only whether each name was declared SOMEWHERE in the + file, which accepts two siblings written as if one contained the other -- + CommonProgressAnimations.CircleProgress.EmptyAnimation named two types that are + both real and neither nested in the other. Getting that right needs the actual + nesting, so this walks braces and keeps the enclosing stack. + + Comments and string literals are blanked first, or a brace inside either would + shift the depth for the rest of the file. A chain is recorded only when every + level of it is public or protected, which is what javadoc -protected emits. + """ + text = blank_java_noise(source.read_text(encoding="utf-8", errors="ignore")) + + chains: set[str] = set() + stack: list[tuple[str, bool, int]] = [] + pending: tuple[str, bool] | None = None + depth = 0 + for match in JAVA_TOKEN_RE.finditer(text): + if match.group("decl"): + # Modifiers sit between the previous statement boundary and the keyword. + boundary = max( + text.rfind(";", 0, match.start()), + text.rfind("{", 0, match.start()), + text.rfind("}", 0, match.start()), + ) + modifiers = text[boundary + 1 : match.start()] + documented = re.search(r"\b(?:public|protected)\b", modifiers) is not None + pending = (match.group("name"), documented) + elif match.group("open"): + depth += 1 + if pending is not None: + name, documented = pending + stack.append((name, documented, depth)) + if all(level[1] for level in stack): + chains.add(".".join(level[0] for level in stack)) + pending = None + else: + if stack and stack[-1][2] == depth: + stack.pop() + depth -= 1 + pending = None + return chains + + +def documented_chain_exists(package: str, chain: list[str]) -> bool: + """Whether javadoc emits a page for this dotted chain in this package.""" if _JAVADOC_ROOT is None: return True for root_name in JAVADOC_SOURCE_ROOTS: - source = _JAVADOC_ROOT / root_name / package / f"{outer}.java" - if not source.exists(): - continue - text = source.read_text(encoding="utf-8", errors="ignore") - text = JAVA_LINE_COMMENT_RE.sub("", JAVA_BLOCK_COMMENT_RE.sub("", text)) - return re.search(NESTED_TYPE_RE.format(stem=re.escape(nested)), text) is not None + source = _JAVADOC_ROOT / root_name / package / f"{chain[0]}.java" + if source.exists(): + return ".".join(chain) in documented_type_chains(source) return True # the outer source moved; the class check above already spoke @@ -318,9 +429,7 @@ def javadoc_path_exists(target: str) -> bool: # now. What this still does not verify is that they nest in the ORDER given -- # that needs brace-depth parsing, and a page naming two real siblings the wrong # way round is a far less likely mistake than naming one that does not exist. - return all( - declares_nested_type(package, parts[0], nested) for nested in parts[1:] - ) + return documented_chain_exists(package, parts) def resolves(target: str, known: set[str], rules: list, depth: int = 0) -> bool: @@ -477,13 +586,13 @@ def site_paths(repo_root: Path) -> tuple[set[str], list, set[str]]: f"until then every link it accepts is unverified." ) - today = datetime.date.today().isoformat() + now = datetime.datetime.now(datetime.timezone.utc) content = repo_root / "docs/website/content" if content.exists(): for page in content.rglob("*.md"): relative = page.relative_to(content).with_suffix("") meta = front_matter(page) - if not is_published(meta, today): + if not is_published(meta, now): continue for alias in meta.get("aliases", []) or []: if isinstance(alias, str): diff --git a/scripts/developer-guide/check-missing-code-blocks.py b/scripts/developer-guide/check-missing-code-blocks.py index 694e3f46da8..988fa35d455 100755 --- a/scripts/developer-guide/check-missing-code-blocks.py +++ b/scripts/developer-guide/check-missing-code-blocks.py @@ -69,7 +69,10 @@ # anchored image, and a whitelist would report the next kind nobody thought of. ADMONITION = "NOTE|TIP|IMPORTANT|WARNING|CAUTION" BLOCK_START_RE = re.compile( - r'^(\[(?!(?:' + ADMONITION + r')\])[a-zA-Z%.#"]' + # The name may be followed by "]" or by further attributes, as in + # [NOTE,caption="Aside"] -- requiring the bracket immediately made an + # attributed admonition look like the listing the sentence promised. + r'^(\[(?!(?:' + ADMONITION + r')[,\]])[a-zA-Z%.#"]' r'|image::|include::|\|===|(----|\.\.\.\.|````|\+\+\+\+|====|\*\*\*\*|____)\s*$)' ) From a70680116d1b8f42be549616544c44295d4416f4 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Thu, 3 Sep 2026 00:01:29 +0300 Subject: [PATCH 33/51] The self-link rule existed on one branch and not the other link:/developer-guide/#missing named an anchor in this book and reached neither gate: this scan dropped the fragment and validated only the route, while check-guide-xrefs.py skips hrefs beginning with "/" because they are not same-page anchors. The absolute-URL branch has had that check since the four wiki-era links were converted; the root-relative branch, added later, did not. That is the second time the same rule written twice has drifted -- the trailing-slash test did it first -- so this one is a shared function from the start, called from both branches and from every spelling the extractor knows. link:/developer-guide/#missing old 0 -> new 1 xref:/developer-guide.html#missing old 0 -> new 1 link:/developer-guide/ (no fragment) new 0 link:/blog/ new 0 the absolute URL form unchanged The guide has no root-relative link at all, so this closes the gap rather than fixing an instance. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 26 +++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index 8e6dbd6b703..2ce09a0d40a 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -642,6 +642,22 @@ def bare_authority(split, host: str, port: int | None) -> bool: return netloc == (host if port is None else f"{host}:{port}") +SELF_LINK_REASON = ( + "links into this book's own body; use an xref so the anchor is checked" +) + + +def links_into_this_book(path: str, fragment: str) -> bool: + """A link to one of this book's own routes that names an anchor inside it. + + Applied to root-relative targets as well as absolute URLs. The absolute branch + had this and the root-relative one did not, so link:/developer-guide/#missing + reached neither gate -- check-guide-xrefs.py skips hrefs starting with "/" + because they are not same-page anchors. + """ + return bool(fragment) and (path.rstrip("/") or "/") in SELF_PATHS + + def undeclared_file_slash(path: str, declared: set[str]) -> bool: """A file-like path wearing a trailing slash the redirect table does not spell out. @@ -688,7 +704,11 @@ def findings_for(path: Path, known: set[str], patterns: list, declared: set[str] if ATTRIBUTE_LINK_RE.search(line): out.append((ATTRIBUTE_LINK_RE.search(line).group(0), "a link target built from an attribute, which this cannot expand or check")) for target in ROOT_RELATIVE_RE.findall(line): - path = target.split("#", 1)[0].split("?", 1)[0] + path, _, fragment = target.partition("#") + path = path.split("?", 1)[0] + if links_into_this_book(path, fragment): + out.append((target, SELF_LINK_REASON)) + continue if undeclared_file_slash(path, declared): # Same rule as for an absolute URL: normalize_path would drop the # slash and validate the variant that was not asked for. @@ -747,8 +767,8 @@ def findings_for(path: Path, known: set[str], patterns: list, declared: set[str] continue if host in SITE_HOSTS: target = split.path.rstrip("/") or "/" - if split.fragment and target in SELF_PATHS: - out.append((url, "links into this book's own body; use an xref so the anchor is checked")) + if links_into_this_book(target, split.fragment): + out.append((url, SELF_LINK_REASON)) elif undeclared_file_slash(split.path, declared): out.append((url, "a file path with a trailing slash that _redirects does not declare")) elif not resolves(target, known, patterns): From 3e7b4a53593f8593604127a5c13b5f264b906227 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Thu, 3 Sep 2026 00:07:49 +0300 Subject: [PATCH 34/51] An inline comment became part of the value, and href tolerated no spaces `draft: true # not ready` is valid YAML, and the parser stored the whole tail, so the draft test compared against "true # not ready", decided the page was not a draft, and added its route to the known set -- a link to a page Hugo omits would have passed. Trailing comments are dropped now, in both front-matter dialects. A quoted value keeps everything inside its quotes, because a url may legitimately contain "#"; that case is in the tests rather than left to trust. Verified through front_matter() rather than by handing is_published() a dict -- that shortcut is what let the publishDate change sit inert for two rounds: draft: true # not ready -> {'draft': 'true'} not published draft: false # shipped -> {'draft': 'false'} published url: "/a#b" -> {'url': '/a#b'} published publishDate: 2099-01-01 # later-> {'publishdate': '2099-01-01'} not published And `` is ordinary HTML. The extractor required the equals sign to touch the attribute name, so that spelling produced nothing and the route reached neither gate. old 0 -> new 1 unchanged new 0 Neither construct appears in the repository today. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 22 ++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index 2ce09a0d40a..bc2fc3d4d79 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -42,7 +42,7 @@ # hrefs beginning with "/" because they are not same-page anchors. Between the two # gates the route went unchecked, so it is run through the same route model here. ROOT_RELATIVE_RE = re.compile( - r"""(?:\blink:|\bxref:|\bhref=["'])(/[^\s\[\]"'`>]*)""", re.IGNORECASE + r"""(?:\blink:|\bxref:|\bhref\s*=\s*["'])(/[^\s\[\]"'`>]*)""", re.IGNORECASE ) # The one tree that genuinely cannot be enumerated from this repository: the # Javadoc is produced from the framework sources at build time. Everything else, @@ -69,6 +69,24 @@ SELF_PATHS = {"/developer-guide", "/developer-guide.html", "/manual", "/manual.html"} +def strip_inline_comment(raw: str) -> str: + """Drop a YAML/TOML trailing comment, leaving a quoted value untouched. + + `draft: true # not ready` stored the whole tail, so the draft test compared + against "true # not ready" and the page counted as published. A quoted value + keeps everything inside the quotes -- a url may legitimately contain "#". + """ + text = raw.strip() + if text[:1] in {'"', "'"}: + quote = text[0] + end = text.find(quote, 1) + return text[1:end] if end != -1 else text[1:] + if text.startswith("#"): + return "" + cut = re.search(r"\s#", text) + return (text[: cut.start()] if cut else text).strip().strip("\"'") + + def front_matter(page: Path) -> dict[str, object]: """Pull the few front-matter keys that decide a page's published route. @@ -115,7 +133,7 @@ def front_matter(page: Path) -> dict[str, object]: else: aliases.extend(v.strip().strip("\"'") for v in raw.strip("[]").split(",") if v.strip()) continue - out[key] = raw.strip("\"'") + out[key] = strip_inline_comment(raw) if aliases: out["aliases"] = aliases return out From 6655675838a01ca929e27f06dc1d2ce7f8d9b0ba Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Thu, 3 Sep 2026 00:15:00 +0300 Subject: [PATCH 35/51] A nested annotation was rejected, and an attributed include was invisible The nesting parser required an explicit public or protected modifier at every level, but a member of an interface or annotation type is implicitly public and javadoc documents it regardless. Route.Routes is declared as a bare `@interface Routes` inside `public @interface Route`, so /javadoc/com/codename1/annotations/Route.Routes.html was REJECTED -- a false positive against a page that really is generated, and the first one this derivation has produced. The enclosing kind is tracked now, and a member of an interface counts as documented. Route.Routes.html old 1 -> new 0 (the false positive) Route.NotReal.html unchanged (still caught) Re-validated across every javadoc link in the guide: 423 checked, 0 rejected. Separately, `include::{chapter}[]` resolved to a literal "{chapter}" with no .adoc suffix, so the walker filed it as a snippet and ignored it. asciidoctor expands the attribute and includes the chapter, so a second copy rendered with no edge counted and no extra title expected -- the same duplicate that every other conditional and inline form was already refused for. Refused too. Expanding attributes means reimplementing asciidoctor's resolution, inheritance through includes included, and the guide contains no attributed include. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 18 ++++++++++++------ .../developer-guide/check-guide-structure.py | 13 +++++++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index bc2fc3d4d79..797a0cc4347 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -296,7 +296,7 @@ def javadoc_index(repo_root: Path) -> tuple[set[str], set[str]]: JAVA_TOKEN_RE = re.compile( - r"(?P\b(?:class|interface|enum|record)\s+(?P[A-Za-z_$][\w$]*))" + r"(?P\b(?Pclass|interface|enum|record)\s+(?P[A-Za-z_$][\w$]*))" r"|(?P\{)|(?P\})" ) @@ -358,8 +358,8 @@ def documented_type_chains(source: Path) -> set[str]: text = blank_java_noise(source.read_text(encoding="utf-8", errors="ignore")) chains: set[str] = set() - stack: list[tuple[str, bool, int]] = [] - pending: tuple[str, bool] | None = None + stack: list[tuple[str, bool, int, str]] = [] + pending: tuple[str, bool, str] | None = None depth = 0 for match in JAVA_TOKEN_RE.finditer(text): if match.group("decl"): @@ -371,12 +371,18 @@ def documented_type_chains(source: Path) -> set[str]: ) modifiers = text[boundary + 1 : match.start()] documented = re.search(r"\b(?:public|protected)\b", modifiers) is not None - pending = (match.group("name"), documented) + # A member of an interface or annotation type is implicitly public, so + # javadoc documents it whether or not the modifier is written. Route.Routes + # is declared as a bare `@interface Routes` inside `public @interface Route` + # and was being rejected. + if not documented and stack and stack[-1][3] == "interface": + documented = True + pending = (match.group("name"), documented, match.group("kind")) elif match.group("open"): depth += 1 if pending is not None: - name, documented = pending - stack.append((name, documented, depth)) + name, documented, kind = pending + stack.append((name, documented, depth, kind)) if all(level[1] for level in stack): chains.add(".".join(level[0] for level in stack)) pending = None diff --git a/scripts/developer-guide/check-guide-structure.py b/scripts/developer-guide/check-guide-structure.py index dd529d43260..a6b0a4f1b6b 100755 --- a/scripts/developer-guide/check-guide-structure.py +++ b/scripts/developer-guide/check-guide-structure.py @@ -170,6 +170,19 @@ def _visit(self, path: Path, attrs_from_parent: str) -> None: if not match: continue target_raw, attrs = match.group(1), match.group(2) + if "{" in target_raw: + # An attribute-built target resolves to a literal "{name}" here, which + # has no .adoc suffix and was therefore filed as a snippet and ignored. + # asciidoctor expands it and includes the chapter, so a second copy + # rendered with no edge counted and no extra title expected. Expanding + # attributes means reimplementing asciidoctor's resolution, inheritance + # through includes included; the guide uses none, so refuse instead. + self.errors.append( + f"{path.name}:{index + 1}: include target {target_raw} is built from " + f"an attribute. This does not expand attributes, so the target " + f"cannot be identified or counted; write the path literally." + ) + continue target = (path.parent / target_raw).resolve() if target.suffix not in ASCIIDOC_EXTENSIONS: continue # a snippet include, validated by validate-guide-snippets.py From ab628e162c597ac28e5cc9745c8fb71fe03219ce Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Thu, 3 Sep 2026 00:33:24 +0300 Subject: [PATCH 36/51] Thirty-five Javadoc anchors used a form javadoc stopped emitting years ago The guide's Javadoc fragments were written in the JDK 9 dashed style -- #createImage-java.lang.String-, #refreshTheme--, #shadowSpread-int-boolean-. The API docs are generated with JDK 25, which emits none of it. Confirmed by generating javadoc and reading the ids back rather than trusting memory: id="createImage(byte[],int,int)" an array is [] and there are no spaces id="refreshTheme()" a no-arg method keeps its parentheses id="Swipe" an enum constant is a bare name So thirty-five links opened the right page and landed nowhere on it. Three other shapes were wrong too: two fragments carried %20 between parameters, where an id has no spaces at all, and Display.html#callSerially had a literal space in place of a dash -- which also broke the AsciiDoc macro, since the URL ended at the space and " java.lang.Runnable-[callSerially]" rendered as prose. All 38 fragments are now in the modern form, and every one was checked against its class: 0 whose member name is absent from the source. check-guide-links.py rejects the retired spellings, so they cannot come back: #createImage-java.lang.String- reported #refreshTheme-- reported #quadTo(float,%20float) reported #createImage(java.lang.String) fine #refreshTheme() fine #Swipe fine The missing-code-blocks baseline moves by one line: it stores whole sentences, and one of them contains a rewritten URL. Same hole, same count, 402 before and after -- --allow-new was needed only because the ratchet cannot tell an edited sentence from a new one. Co-Authored-By: Claude Opus 5 (1M context) --- .../developer-guide/Advanced-Theming.asciidoc | 2 +- docs/developer-guide/Events.asciidoc | 12 +++++----- .../developer-guide/Game-Development.asciidoc | 2 +- .../The-Components-Of-Codename-One.asciidoc | 20 ++++++++--------- docs/developer-guide/css.asciidoc | 8 +++---- docs/developer-guide/graphics.asciidoc | 14 ++++++------ docs/developer-guide/io.asciidoc | 4 ++-- scripts/developer-guide/check-guide-links.py | 22 +++++++++++++++++++ .../missing-code-blocks-baseline.txt | 2 +- 9 files changed, 54 insertions(+), 32 deletions(-) diff --git a/docs/developer-guide/Advanced-Theming.asciidoc b/docs/developer-guide/Advanced-Theming.asciidoc index 2ebb5ab324a..29dfe0f9713 100644 --- a/docs/developer-guide/Advanced-Theming.asciidoc +++ b/docs/developer-guide/Advanced-Theming.asciidoc @@ -728,7 +728,7 @@ Will set the foreground color of the https://www.codenameone.com/javadoc/com/cod When a Codename One https://www.codenameone.com/javadoc/com/codename1/ui/Component.html[Component] is instantiated it requests a https://www.codenameone.com/javadoc/com/codename1/ui/plaf/Style.html[Style] object from the https://www.codenameone.com/javadoc/com/codename1/ui/plaf/UIManager.html[UIManager] class. The `Style` object is based on the settings within the theme and can be modified through code or by using the theme. -You can replace the theme dynamically in runtime and refresh the styles assigned to the various components using the https://www.codenameone.com/javadoc/com/codename1/ui/Component.html#refreshTheme--[refreshTheme()] method. +You can replace the theme dynamically in runtime and refresh the styles assigned to the various components using the https://www.codenameone.com/javadoc/com/codename1/ui/Component.html#refreshTheme()[refreshTheme()] method. NOTE: It's a common mistake to invoke `refreshTheme()` without actually changing the theme. You see developers doing it when all they need is a `repaint()` or `revalidate()`. Since `refreshTheme()` is **** expensive recommend that you don't use it unless you need to... diff --git a/docs/developer-guide/Events.asciidoc b/docs/developer-guide/Events.asciidoc index 3f9ec37d048..33e0ad643b1 100644 --- a/docs/developer-guide/Events.asciidoc +++ b/docs/developer-guide/Events.asciidoc @@ -55,9 +55,9 @@ Quite a few high-level event types exist that are more specific to requirements. When an action event is fired it's given a type, but this type might change as the event evolves for example, a command triggered by a pointer event won't include details of the original pointer event. -You can get the event type from https://www.codenameone.com/javadoc/com/codename1/ui/events/ActionEvent.html#getEventType--[getEventType()], this also gives you a rather exhaustive list of the possible event types for the action event. +You can get the event type from https://www.codenameone.com/javadoc/com/codename1/ui/events/ActionEvent.html#getEventType()[getEventType()], this also gives you a rather exhaustive list of the possible event types for the action event. -Modern gesture components also publish custom action types. For example, https://www.codenameone.com/javadoc/com/codename1/ui/SwipeableContainer.html[SwipeableContainer] dispatches https://www.codenameone.com/javadoc/com/codename1/ui/events/ActionEvent.Type.html#Swipe-[ActionEvent.Type.Swipe] when the top component is fully opened, allowing code to react to swipe gestures without monitoring low-level drags. Listening for these higher level events keeps gesture handling portable across touch and desktop targets. +Modern gesture components also publish custom action types. For example, https://www.codenameone.com/javadoc/com/codename1/ui/SwipeableContainer.html[SwipeableContainer] dispatches https://www.codenameone.com/javadoc/com/codename1/ui/events/ActionEvent.Type.html#Swipe[ActionEvent.Type.Swipe] when the top component is fully opened, allowing code to react to swipe gestures without monitoring low-level drags. Listening for these higher level events keeps gesture handling portable across touch and desktop targets. ===== Source of event @@ -123,7 +123,7 @@ These seem similar but they have one important distinction. The latter code is i ===== MessageEvent and the Cross-Platform message bus -Bridging to native code often means passing messages between Codename One Java and platform specific code. The cross-platform message bus provides a high-level abstraction for that by letting you post messages to the native layer and subscribe for messages that originate there. Use https://www.codenameone.com/javadoc/com/codename1/ui/Display.html#postMessage-com.codename1.ui.events.MessageEvent-[Display.postMessage()] to send an https://www.codenameone.com/javadoc/com/codename1/ui/events/MessageEvent.html[MessageEvent] to the platform, and https://www.codenameone.com/javadoc/com/codename1/ui/Display.html#addMessageListener-com.codename1.ui.events.ActionListener-[Display.addMessageListener()] to receive events that arrive from native code, JavaScript bridges, or background services. Message events include helpers like `isPromptForAudioRecorder()`, `isPromptForAudioPlayer()`, and `getPromptPromise()` that allow you to hook into permission prompts emitted by the JavaScript port so custom UI can respond to platform requests while keeping the event dispatch on the EDT. This API complements `NetworkEvent` by covering native-to-Java messaging without requiring direct low-level callbacks. +Bridging to native code often means passing messages between Codename One Java and platform specific code. The cross-platform message bus provides a high-level abstraction for that by letting you post messages to the native layer and subscribe for messages that originate there. Use https://www.codenameone.com/javadoc/com/codename1/ui/Display.html#postMessage(com.codename1.ui.events.MessageEvent)[Display.postMessage()] to send an https://www.codenameone.com/javadoc/com/codename1/ui/events/MessageEvent.html[MessageEvent] to the platform, and https://www.codenameone.com/javadoc/com/codename1/ui/Display.html#addMessageListener(com.codename1.ui.events.ActionListener)[Display.addMessageListener()] to receive events that arrive from native code, JavaScript bridges, or background services. Message events include helpers like `isPromptForAudioRecorder()`, `isPromptForAudioPlayer()`, and `getPromptPromise()` that allow you to hook into permission prompts emitted by the JavaScript port so custom UI can respond to platform requests while keeping the event dispatch on the EDT. This API complements `NetworkEvent` by covering native-to-Java messaging without requiring direct low-level callbacks. ==== DataChangeListener @@ -175,7 +175,7 @@ for the component class but not an important event for general user code. It's r ==== Component state change events -Component instances now publish lifecycle hooks that fire when they become initialized on a form and when they're removed. You can subscribe with https://www.codenameone.com/javadoc/com/codename1/ui/Component.html#addStateChangeListener-com.codename1.ui.events.ActionListener-[Component.addStateChangeListener()] to receive https://www.codenameone.com/javadoc/com/codename1/ui/events/ComponentStateChangeEvent.html[ComponentStateChangeEvent] instances that show whether the component is transitioning to the initialized state. This is useful for running setup or teardown logic alongside focus, scroll, and selection listeners. +Component instances now publish lifecycle hooks that fire when they become initialized on a form and when they're removed. You can subscribe with https://www.codenameone.com/javadoc/com/codename1/ui/Component.html#addStateChangeListener(com.codename1.ui.events.ActionListener)[Component.addStateChangeListener()] to receive https://www.codenameone.com/javadoc/com/codename1/ui/events/ComponentStateChangeEvent.html[ComponentStateChangeEvent] instances that show whether the component is transitioning to the initialized state. This is useful for running setup or teardown logic alongside focus, scroll, and selection listeners. ==== Event dispatcher @@ -243,9 +243,9 @@ The pointer events (touch events) can be intercepted by overriding one or more o Notice that most pointer events have a version that accepts an array as an argument, this allows for multi-touch event handling by sending all the touched coordinates. Desktop and pen-enabled devices can also trigger hover events without a press. To respond to those you can override the `pointerHover*` callbacks on `Form` or `Component`, which are invoked before a button receives focus or a drag begins on those platforms. -While you can override `longPointerPress`, there is no need. The dedicated https://www.codenameone.com/javadoc/com/codename1/ui/Component.html#addLongPressListener-com.codename1.ui.events.ActionListener-[Component.addLongPressListener()] helper wires long press detection into an action listener so you can keep gesture logic in the high-level API. +While you can override `longPointerPress`, there is no need. The dedicated https://www.codenameone.com/javadoc/com/codename1/ui/Component.html#addLongPressListener(com.codename1.ui.events.ActionListener)[Component.addLongPressListener()] helper wires long press detection into an action listener so you can keep gesture logic in the high-level API. -Drag lifecycles also expose a completion hook. When `Component.addDragFinishedListener()` is registered it receives https://www.codenameone.com/javadoc/com/codename1/ui/events/ActionEvent.Type.html#DragFinished-[ActionEvent.Type.DragFinished] once the framework has completed its cleanup, allowing you to reset state or trigger follow-up actions that should occur after the drag image is hidden. +Drag lifecycles also expose a completion hook. When `Component.addDragFinishedListener()` is registered it receives https://www.codenameone.com/javadoc/com/codename1/ui/events/ActionEvent.Type.html#DragFinished[ActionEvent.Type.DragFinished] once the framework has completed its cleanup, allowing you to reset state or trigger follow-up actions that should occur after the drag image is hidden. ==== Drag event sanitation diff --git a/docs/developer-guide/Game-Development.asciidoc b/docs/developer-guide/Game-Development.asciidoc index 10772acf784..f5bdc9bcce2 100644 --- a/docs/developer-guide/Game-Development.asciidoc +++ b/docs/developer-guide/Game-Development.asciidoc @@ -102,7 +102,7 @@ rendered positions between physics states: `update(double)` runs on the render thread, together with drawing. Keep it non-blocking -- offload asset loading, networking or other long work to a background thread and hand the result back with -https://www.codenameone.com/javadoc/com/codename1/ui/CN.html#callSerially-java.lang.Runnable-[`CN.callSerially`]. +https://www.codenameone.com/javadoc/com/codename1/ui/CN.html#callSerially(java.lang.Runnable)[`CN.callSerially`]. === Input: `GameInput` diff --git a/docs/developer-guide/The-Components-Of-Codename-One.asciidoc b/docs/developer-guide/The-Components-Of-Codename-One.asciidoc index 4b853b82611..a034a900512 100644 --- a/docs/developer-guide/The-Components-Of-Codename-One.asciidoc +++ b/docs/developer-guide/The-Components-Of-Codename-One.asciidoc @@ -25,7 +25,7 @@ Some components are composites and derive from the https://www.codenameone.com/j - You can't cast it to the type it relates to. For example, you can't cast `MultiButton` to `Button`. -- Events can be more nuanced. For example, if you rely on https://www.codenameone.com/javadoc/com/codename1/ui/events/ActionEvent.html#getSource--[ActionEvent.getSource()] or https://www.codenameone.com/javadoc/com/codename1/ui/events/ActionEvent.html#getComponent--[ActionEvent.getComponent()], they may not behave as expected. For a `MultiButton`, they return the underlying `Button`. To work around that, use https://www.codenameone.com/javadoc/com/codename1/ui/events/ActionEvent.html#getActualComponent--[ActionEvent.getActualComponent()]. +- Events can be more nuanced. For example, if you rely on https://www.codenameone.com/javadoc/com/codename1/ui/events/ActionEvent.html#getSource()[ActionEvent.getSource()] or https://www.codenameone.com/javadoc/com/codename1/ui/events/ActionEvent.html#getComponent()[ActionEvent.getComponent()], they may not behave as expected. For a `MultiButton`, they return the underlying `Button`. To work around that, use https://www.codenameone.com/javadoc/com/codename1/ui/events/ActionEvent.html#getActualComponent()[ActionEvent.getActualComponent()]. [[lead-component-sidebar]] .Lead Component @@ -34,7 +34,7 @@ Codename One includes a feature for creating composite components called "lead c Lead components work by assigning one component as the "leader." That leader determines the style state for every component in the hierarchy. If a `Container` is led by a `Button`, the button determines whether the selected or pressed state applies to the entire hierarchy. -This means a single `Component` can contain multiple nested `UIID`s. For example, `MultiButton` has `UIID`s such as `MultiLine1`, which you can customize with APIs such as https://www.codenameone.com/javadoc/com/codename1/components/MultiButton.html#setUIIDLine1-java.lang.String-[setUIIDLine1]. +This means a single `Component` can contain multiple nested `UIID`s. For example, `MultiButton` has `UIID`s such as `MultiLine1`, which you can customize with APIs such as https://www.codenameone.com/javadoc/com/codename1/components/MultiButton.html#setUIIDLine1(java.lang.String)[setUIIDLine1]. The lead component also handles events from a single source. Clicking another component in the hierarchy sends the event to the leading `Button`, which can make action events route to a different target than the apparent click target. That's why `getActualComponent()` exists. @@ -188,8 +188,8 @@ NOTE: `hi` is the name of the parent `Form` in the sample above. ==== Styling dialogs -It's important to style a `Dialog` using https://www.codenameone.com/javadoc/com/codename1/ui/Dialog.html#getDialogStyle--[getDialogStyle()] or -https://www.codenameone.com/javadoc/com/codename1/ui/Dialog.html#setDialogUIID-java.lang.String-[setDialogUIID] methods rather than styling the dialog object directly. +It's important to style a `Dialog` using https://www.codenameone.com/javadoc/com/codename1/ui/Dialog.html#getDialogStyle()[getDialogStyle()] or +https://www.codenameone.com/javadoc/com/codename1/ui/Dialog.html#setDialogUIID(java.lang.String)[setDialogUIID] methods rather than styling the dialog object directly. The reason for this is that the `Dialog` is a `Form` that takes up the whole screen. The `Form` that's visible behind the `Dialog` is rendered as a screenshot. Customizing the actual `UIID` of the `Dialog` won't produce the desired results. @@ -367,7 +367,7 @@ Codename One. - Blinking cursor is rendered on `TextField` - https://www.codenameone.com/javadoc/com/codename1/ui/events/DataChangedListener.html[DataChangeListener] is available in `TextField`. This is crucial for character by character input event tracking -- https://www.codenameone.com/javadoc/com/codename1/ui/TextField.html#setDoneListener-com.codename1.ui.events.ActionListener-[Done listener] is available in the `TextField` +- https://www.codenameone.com/javadoc/com/codename1/ui/TextField.html#setDoneListener(com.codename1.ui.events.ActionListener)[Done listener] is available in the `TextField` - Different `UIID` NOTE: The semantic difference between `TextField` & `TextArea` dates back to the ancestor of Codename One: LWUIT. Feature phones don’t have "proper" in-place editing capabilities & thus `TextField` was introduced to allow such input. @@ -375,7 +375,7 @@ NOTE: The semantic difference between `TextField` & `TextArea` dates back to the Because it lacks the blinking cursor capability `TextArea` is often used as a multi-line label and is used internally in `SpanLabel`, `SpanButton` etc. -TIP: A common use case is to have an important text component in edit mode as you enter a `Form`. Codename One forms support this exact use case through the https://www.codenameone.com/javadoc/com/codename1/ui/Form.html#setEditOnShow-com.codename1.ui.TextArea-[Form.setEditOnShow(TextArea)] method. +TIP: A common use case is to have an important text component in edit mode as you enter a `Form`. Codename One forms support this exact use case through the https://www.codenameone.com/javadoc/com/codename1/ui/Form.html#setEditOnShow(com.codename1.ui.TextArea)[Form.setEditOnShow(TextArea)] method. `TextField` & `TextArea` support constraints for various types of input such as `NUMERIC`, `EMAIL`, `URL`, etc. Those usually @@ -820,7 +820,7 @@ include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/g .Infinite progress image::img/infinite-progress.png[Infinite progress,scaledwidth=10%] -The image used in the `InfiniteProgress` animation is defined by the native theme. You can override that definition either by defining the theme constant `infiniteImage` or by invoking the https://www.codenameone.com/javadoc/com/codename1/components/InfiniteProgress.html#setAnimation-com.codename1.ui.Image-[setAnimation] method. +The image used in the `InfiniteProgress` animation is defined by the native theme. You can override that definition either by defining the theme constant `infiniteImage` or by invoking the https://www.codenameone.com/javadoc/com/codename1/components/InfiniteProgress.html#setAnimation(com.codename1.ui.Image)[setAnimation] method. NOTE: Despite the name of the method `setAnimation` expects a static image that will be rotated internally. Don't use an animated image. @@ -1734,7 +1734,7 @@ You can bind a `BrowserNavigationCallback` by invoking `setBrowserNavigationCall IMPORTANT: The `shouldNavigate` method from the `BrowserNavigationCallback` is invoked in a native thread and **NOT ON THE EDT**! + it's crucial that this method returns and that it won't do any changes on the UI. -The `shouldNavigate` indicates to the native code whether navigation should proceed or not. For example: if a user clicks a specific link you might choose to do something in the Java code so you can return false and block the navigation. You can invoke https://www.codenameone.com/javadoc/com/codename1/ui/Display.html#callSerially java.lang.Runnable-[callSerially] to do the actual task in the Java side: +The `shouldNavigate` indicates to the native code whether navigation should proceed or not. For example: if a user clicks a specific link you might choose to do something in the Java code so you can return false and block the navigation. You can invoke https://www.codenameone.com/javadoc/com/codename1/ui/Display.html#callSerially(java.lang.Runnable)[callSerially] to do the actual task in the Java side: [source,java] ---- @@ -1773,7 +1773,7 @@ The new API fully embraces the asynchronous nature of JavaScript. It uses callba NOTE: In all the sample code below, you can assume that variables named `bc` represent an instance of https://www.codenameone.com/javadoc/com/codename1/ui/BrowserComponent.html[BrowserComponent]: -This code should output "The result was 7" to the console. It's fully asynchronous, so you can include this code anywhere without worrying about it "bogging down" your code. The full signature of this form of the https://www.codenameone.com/javadoc/com/codename1/ui/BrowserComponent.html#execute-java.lang.String-com.codename1.util.SuccessCallback-[execute()] method is: +This code should output "The result was 7" to the console. It's fully asynchronous, so you can include this code anywhere without worrying about it "bogging down" your code. The full signature of this form of the https://www.codenameone.com/javadoc/com/codename1/ui/BrowserComponent.html#execute(java.lang.String,com.codename1.util.SuccessCallback)[execute()] method is: The first parameter is a JavaScript expression. This JavaScript *MUST* call either `callback.onSuccess(result)` or `callback.onError(message, errCode)` at some point in order for your callback to be called. @@ -1809,7 +1809,7 @@ Now it will work no matter how many times the button is clicked. ===== Passing parameters to JavaScript -Often, the JavaScript expressions that you execute will include parameters from your Java code. Escaping these parameters is tricky at worst, and annoying at best. For example: If you’re passing a string, you need to make sure that it escapes quotes and new lines or it will cause the JavaScript to have a syntax error. You provide variants of `execute()` and https://www.codenameone.com/javadoc/com/codename1/ui/BrowserComponent.html#addJSCallback-java.lang.String-com.codename1.util.SuccessCallback-[addJSCallback()] that allow you to pass your parameters and have them automatically escaped. +Often, the JavaScript expressions that you execute will include parameters from your Java code. Escaping these parameters is tricky at worst, and annoying at best. For example: If you’re passing a string, you need to make sure that it escapes quotes and new lines or it will cause the JavaScript to have a syntax error. You provide variants of `execute()` and https://www.codenameone.com/javadoc/com/codename1/ui/BrowserComponent.html#addJSCallback(java.lang.String,com.codename1.util.SuccessCallback)[addJSCallback()] that allow you to pass your parameters and have them automatically escaped. For example, suppose you want to pass a string with text to set in a textarea within the webpage. You can do something like: diff --git a/docs/developer-guide/css.asciidoc b/docs/developer-guide/css.asciidoc index 50773702d66..06bc04d4d4b 100644 --- a/docs/developer-guide/css.asciidoc +++ b/docs/developer-guide/css.asciidoc @@ -241,10 +241,10 @@ include::../demos/common/src/main/css/guide-snippets-theme.css[tag=css-css-011,i `cn1-pill-border` and `cn1-round-border` don't support the standard CSS `box-shadow` property. This is because the `box-shadow` property parameters don't map onto the shadow parameters for the Codename One `RoundBorder` class. To get shadows on the `cn1-pill-border`, you should use one or more of the following CSS properties: -* `cn1-box-shadow-spread`: Accepts values in any scalar unit (for example, px, mm, cm, etc.). This maps directly to the border's https://www.codenameone.com/javadoc/com/codename1/ui/plaf/RoundBorder.html#shadowSpread-int-boolean-[shadowSpread] property. -* `cn1-box-shadow-h`: Accepts values in real values or integers (not a scalar unit). This maps directly to the border's https://www.codenameone.com/javadoc/com/codename1/ui/plaf/RoundBorder.html#shadowX-float-[shadowX] property. -* `cn1-box-shadow-v`: Accepts values in real values or integers (not a scalar unit). This maps directly to the border's https://www.codenameone.com/javadoc/com/codename1/ui/plaf/RoundBorder.html#shadowY-float-[shadowY] property. -* `cn1-box-shadow-blur`: Scalar value. Maps to the border's https://www.codenameone.com/javadoc/com/codename1/ui/plaf/RoundBorder.html#shadowBlur-float-[shadowBlur] property. +* `cn1-box-shadow-spread`: Accepts values in any scalar unit (for example, px, mm, cm, etc.). This maps directly to the border's https://www.codenameone.com/javadoc/com/codename1/ui/plaf/RoundBorder.html#shadowSpread(int,boolean)[shadowSpread] property. +* `cn1-box-shadow-h`: Accepts values in real values or integers (not a scalar unit). This maps directly to the border's https://www.codenameone.com/javadoc/com/codename1/ui/plaf/RoundBorder.html#shadowX(float)[shadowX] property. +* `cn1-box-shadow-v`: Accepts values in real values or integers (not a scalar unit). This maps directly to the border's https://www.codenameone.com/javadoc/com/codename1/ui/plaf/RoundBorder.html#shadowY(float)[shadowY] property. +* `cn1-box-shadow-blur`: Scalar value. Maps to the border's https://www.codenameone.com/javadoc/com/codename1/ui/plaf/RoundBorder.html#shadowBlur(float)[shadowBlur] property. * `cn1-box-shadow-color`: The shadow color * `cn1-box-shadow-inset`: Set to `inset` to render an inner shadow instead of the default outer shadow spread. diff --git a/docs/developer-guide/graphics.asciidoc b/docs/developer-guide/graphics.asciidoc index 968fd224f1e..d48004e45b6 100644 --- a/docs/developer-guide/graphics.asciidoc +++ b/docs/developer-guide/graphics.asciidoc @@ -198,14 +198,14 @@ to allow for smoother edges by using quadratic curves instead of lines. Codename One's `GeneralPath` class includes two methods for drawing curves: -1. https://www.codenameone.com/javadoc/com/codename1/ui/geom/GeneralPath.html#quadTo(float,%20float,%20float,%20float)[`quadTo()`] : +1. https://www.codenameone.com/javadoc/com/codename1/ui/geom/GeneralPath.html#quadTo(float,float,float,float)[`quadTo()`] : Appends a quadratic Bézier curve. It takes 2 points: a control point, and an end point. -2. link:https://www.codenameone.com/javadoc/com/codename1/ui/geom/GeneralPath.html#curveTo(float,%20float,%20float,%20float,%20float,%20float)[`curveTo()`] : +2. link:https://www.codenameone.com/javadoc/com/codename1/ui/geom/GeneralPath.html#curveTo(float,float,float,float,float,float)[`curveTo()`] : Appends a cubic Bézier curve, taking 3 points: 2 control points, and an end point. See the https://www.codenameone.com/javadoc/com/codename1/ui/geom/GeneralPath.html[General Path javadocs] for the full API. -You will make use of the link:https://www.codenameone.com/javadoc/com/codename1/ui/geom/GeneralPath.html#quadTo(float,%20float,%20float,%20float)[`quadTo()`] +You will make use of the link:https://www.codenameone.com/javadoc/com/codename1/ui/geom/GeneralPath.html#quadTo(float,float,float,float)[`quadTo()`] method to append curves to the drawing as follows: @@ -450,7 +450,7 @@ include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/g .Shape Clipping used to clip the image of duke within the given shape image::img/shaped-clipping.png[Shape Clipping used to clip the image of duke within the given shape,scaledwidth=20%] -TIP: Notice that this functionality isn't available on all platforms so you need to test if shaped clipping is supported using https://www.codenameone.com/javadoc/com/codename1/ui/Graphics.html#isShapeClipSupported--[isShapeClipSupported()]. +TIP: Notice that this functionality isn't available on all platforms so you need to test if shaped clipping is supported using https://www.codenameone.com/javadoc/com/codename1/ui/Graphics.html#isShapeClipSupported()[isShapeClipSupported()]. === The coordinate system @@ -631,7 +631,7 @@ Here are the pros/cons and logic behind every image type. This covers the logic ==== Loaded Image This is the basic image you get when loading an image from the jar or network using -https://www.codenameone.com/javadoc/com/codename1/ui/Image.html#createImage-java.lang.String-[Image.createImage(String)], https://www.codenameone.com/javadoc/com/codename1/ui/Image.html#createImage-java.io.InputStream-[Image.createImage(InputStream)] & https://www.codenameone.com/javadoc/com/codename1/ui/Image.html#createImage-byte:A-int-int-[Image.`createImage(byte[], int, int)`],... +https://www.codenameone.com/javadoc/com/codename1/ui/Image.html#createImage(java.lang.String)[Image.createImage(String)], https://www.codenameone.com/javadoc/com/codename1/ui/Image.html#createImage(java.io.InputStream)[Image.createImage(InputStream)] & https://www.codenameone.com/javadoc/com/codename1/ui/Image.html#createImage(byte[],int,int)[Image.`createImage(byte[], int, int)`],... TIP: Some other APIs might return this image type but those APIs do so explicitly! @@ -659,7 +659,7 @@ There are two types of RGB constructed images that are different from one anothe ===== Internal -This is a close cousin of the loaded image. This image is created using the method https://www.codenameone.com/javadoc/com/codename1/ui/Image.html#createImage-int:A-int-int-[Image.createImage(int array, int, int)] and receives the AARRGGBB data to form the image. It's more efficient than the Codename One RGB image but can't be modified, at least not on the pixel level. +This is a close cousin of the loaded image. This image is created using the method https://www.codenameone.com/javadoc/com/codename1/ui/Image.html#createImage(int[],int,int)[Image.createImage(int array, int, int)] and receives the AARRGGBB data to form the image. It's more efficient than the Codename One RGB image but can't be modified, at least not on the pixel level. The goal of this image type is to provide an easy way to render RGB data that isn't modified efficiently at platform native speeds. It's technically a <> internally. @@ -689,7 +689,7 @@ When drawing an `EncodedImage` it checks the weak reference cache and if the ima `EncodedImage` isn't final and can be derived to produce complex image fetching strategies for example: the https://www.codenameone.com/javadoc/com/codename1/ui/URLImage.html[URLImage] class that can dynamically download its content from the web. -`EncodedImage` can be instantiated through the create methods in the `EncodedImage` class. Pretty much any image can be converted into an `EncodedImage` through the https://www.codenameone.com/javadoc/com/codename1/ui/EncodedImage.html#createFromImage-com.codename1.ui.Image-boolean-[createFromImage(Image, boolean)] method. +`EncodedImage` can be instantiated through the create methods in the `EncodedImage` class. Pretty much any image can be converted into an `EncodedImage` through the https://www.codenameone.com/javadoc/com/codename1/ui/EncodedImage.html#createFromImage(com.codename1.ui.Image,boolean)[createFromImage(Image, boolean)] method. .EncodedImage Locking diff --git a/docs/developer-guide/io.asciidoc b/docs/developer-guide/io.asciidoc index 43a688bb488..d1b15a90a20 100644 --- a/docs/developer-guide/io.asciidoc +++ b/docs/developer-guide/io.asciidoc @@ -905,11 +905,11 @@ For example, the `URLImage` assumes that you know the size of the image in advan The download methods mentioned above are great alternatives but they're a bit verbose when working with images and don't provide fine grained control over the `ConnectionRequest` for example: making a `POST` request to get an image. TIP: Adding global headers is another use case but you can use -https://www.codenameone.com/javadoc/com/codename1/io/NetworkManager.html#addDefaultHeader-java.lang.String-java.lang.String-[addDefaultHeader] +https://www.codenameone.com/javadoc/com/codename1/io/NetworkManager.html#addDefaultHeader(java.lang.String,java.lang.String)[addDefaultHeader] to add those. To make this process simpler there is a set of helper methods in -https://www.codenameone.com/javadoc/com/codename1/io/ConnectionRequest.html#downloadImageToStorage-java.lang.String-com.codename1.util.SuccessCallback-[ConnectionRequest that downloads images directly]. +https://www.codenameone.com/javadoc/com/codename1/io/ConnectionRequest.html#downloadImageToStorage(java.lang.String,com.codename1.util.SuccessCallback)[ConnectionRequest that downloads images directly]. These methods complement the `Util` methods but go a bit further and feature terse syntax for example: you can download a `ConnectionRequest` to `Storage` using code like this: diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index 797a0cc4347..02b906bb4d3 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -405,6 +405,24 @@ def documented_chain_exists(package: str, chain: list[str]) -> bool: return True # the outer source moved; the class check above already spoke +# What javadoc actually emits, confirmed by generating some and reading the ids: +# a method is "name(java.lang.String)" or "name()" with NO spaces, an array is +# "byte[]", and a field or enum constant is a bare name. The dashed spelling +# "name-java.lang.String-" was a JDK 9-only style; the generator here runs JDK 25 +# and emits none of it, so a dashed fragment names an anchor that is not on the +# page. Thirty-five links in the guide still carried it. +LEGACY_JAVADOC_FRAGMENT_RE = re.compile(r"^[A-Za-z_$][\w$.]*(-|\s)") + + +def javadoc_fragment_is_current(fragment: str) -> bool: + """Whether a /javadoc/ fragment is a shape modern javadoc can emit.""" + if not fragment: + return True + if "%20" in fragment or " " in fragment: + return False # an id never contains a space + return not LEGACY_JAVADOC_FRAGMENT_RE.match(fragment) + + def javadoc_path_exists(target: str) -> bool: """Whether a /javadoc/ path names something the generated tree will hold. @@ -789,6 +807,10 @@ def findings_for(path: Path, known: set[str], patterns: list, declared: set[str] # is the Ollama endpoint the AI chapter documents on purpose. out.append((url, f"port {port} is not where the site is served")) continue + if host in SITE_HOSTS and split.path.startswith("/javadoc/"): + if not javadoc_fragment_is_current(split.fragment): + out.append((url, "a javadoc anchor in the retired JDK 9 dashed form; modern javadoc emits name(Type)")) + continue if host in SITE_HOSTS: target = split.path.rstrip("/") or "/" if links_into_this_book(target, split.fragment): diff --git a/scripts/developer-guide/missing-code-blocks-baseline.txt b/scripts/developer-guide/missing-code-blocks-baseline.txt index b41e59bf5cc..c0d517af65e 100644 --- a/scripts/developer-guide/missing-code-blocks-baseline.txt +++ b/scripts/developer-guide/missing-code-blocks-baseline.txt @@ -206,7 +206,7 @@ The-Components-Of-Codename-One.asciidoc The screenshot above was produced using The-Components-Of-Codename-One.asciidoc The split pane component is a bit desktop specific but works reasonably well on devices. To get the image below you changed `SalesDemo.java` in the kitchen sink by changing this: The-Components-Of-Codename-One.asciidoc Then implement the method `automoveToNext` as: The-Components-Of-Codename-One.asciidoc Then you can retrieve its properties using the `get()` method: -The-Components-Of-Codename-One.asciidoc This code should output "The result was 7" to the console. It's fully asynchronous, so you can include this code anywhere without worrying about it "bogging down" your code. The full signature of this form of the https://www.codenameone.com/javadoc/com/codename1/ui/BrowserComponent.html#execute-java.lang.String-com.codename1.util.SuccessCallback-[execute()] method is: +The-Components-Of-Codename-One.asciidoc This code should output "The result was 7" to the console. It's fully asynchronous, so you can include this code anywhere without worrying about it "bogging down" your code. The full signature of this form of the https://www.codenameone.com/javadoc/com/codename1/ui/BrowserComponent.html#execute(java.lang.String,com.codename1.util.SuccessCallback)[execute()] method is: The-Components-Of-Codename-One.asciidoc This sample below continues from the place where the <> stopped by adding validation to that code: The-Components-Of-Codename-One.asciidoc This swipe gesture is commonly used in touch interfaces to expose features such as delete, edit etc. It's trivial to use this component by determining the components placed on top and bottom (the revealed component): The-Components-Of-Codename-One.asciidoc To make the code tighter, keep a reference to the `Component` or extend it as https://www.codenameone.com/javadoc/com/codename1/ui/list/DefaultListCellRenderer.html[DefaultListCellRenderer] does: From e7bb4eefaafbadbb21661771eb7635ea3121a200 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Thu, 3 Sep 2026 00:38:19 +0300 Subject: [PATCH 37/51] An unquoted href value is still an href is valid HTML, and the extractor required an opening quote, so that spelling produced nothing and the route reached neither gate -- check-guide-xrefs.py skips root-relative hrefs because they are not same-page anchors. The quote is optional now; the character class already stops at whitespace or ">", which is exactly where an unquoted attribute value ends. old 0 -> new 1 new 0 unchanged The guide contains no unquoted href. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index 02b906bb4d3..4bd5440ea1c 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -42,7 +42,10 @@ # hrefs beginning with "/" because they are not same-page anchors. Between the two # gates the route went unchecked, so it is run through the same route model here. ROOT_RELATIVE_RE = re.compile( - r"""(?:\blink:|\bxref:|\bhref\s*=\s*["'])(/[^\s\[\]"'`>]*)""", re.IGNORECASE + # The quote is optional: is valid HTML, and the character class + # already stops at whitespace or ">", which is exactly where an unquoted + # attribute value ends. + r"""(?:\blink:|\bxref:|\bhref\s*=\s*["']?)(/[^\s\[\]"'`>]*)""", re.IGNORECASE ) # The one tree that genuinely cannot be enumerated from this repository: the # Javadoc is produced from the framework sources at build time. Everything else, From d3ba948c164e38fe8d8f340d8a1610da2cfbd556 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Thu, 3 Sep 2026 00:48:36 +0300 Subject: [PATCH 38/51] The array brackets I added last round broke two links, and aliases kept comments Converting the Javadoc anchors last round introduced #createImage(byte[],int,int) and its int[] sibling. In AsciiDoc the first "[" opens the link label, so the URL was cut at "createImage(byte" and the label was lost -- the rendered book showed a bare truncated URL where a labelled link belonged. Both are percent-encoded now, and both render as complete links with their labels. One of the two needed a second fix that the report did not mention: its label was `Image.\`createImage(byte[], int, int)\``, and a "]" INSIDE a label closes it just as surely, so the label ended at "byte[" and the remainder spilled into the paragraph as text. Written as "byte array" now, matching how the int[] link beside it was already phrased. Checked by rendering the whole book, not the one file: 0 truncated javadoc links anywhere. check-guide-links.py catches a raw array bracket from the source, because URL_RE stops at that "[" and never sees it. The empty pair is the unambiguous signal -- a label is never empty. #createImage(byte[],int,int) reported #createImage(byte%5B%5D,int,int) fine #createImage(java.lang.String) fine A first attempt at this guard required balanced parentheses in the fragment, which looked reasonable and reported all 36 javadoc links: URL_RE deliberately excludes ")" so it does not swallow sentence punctuation, so every modern fragment arrives truncated by construction. Running it was what showed that. Aliases now get the same comment handling as scalar values, so `- /old-route # legacy` records /old-route rather than the whole line and a link to that live alias stops being reported as broken. Quoted entries keep their "#", because in YAML a quoted "#" is literal -- my first test asserted the opposite and was wrong, not the code. Co-Authored-By: Claude Opus 5 (1M context) --- docs/developer-guide/graphics.asciidoc | 4 ++-- scripts/developer-guide/check-guide-links.py | 12 ++++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/docs/developer-guide/graphics.asciidoc b/docs/developer-guide/graphics.asciidoc index d48004e45b6..a3e14e36d37 100644 --- a/docs/developer-guide/graphics.asciidoc +++ b/docs/developer-guide/graphics.asciidoc @@ -631,7 +631,7 @@ Here are the pros/cons and logic behind every image type. This covers the logic ==== Loaded Image This is the basic image you get when loading an image from the jar or network using -https://www.codenameone.com/javadoc/com/codename1/ui/Image.html#createImage(java.lang.String)[Image.createImage(String)], https://www.codenameone.com/javadoc/com/codename1/ui/Image.html#createImage(java.io.InputStream)[Image.createImage(InputStream)] & https://www.codenameone.com/javadoc/com/codename1/ui/Image.html#createImage(byte[],int,int)[Image.`createImage(byte[], int, int)`],... +https://www.codenameone.com/javadoc/com/codename1/ui/Image.html#createImage(java.lang.String)[Image.createImage(String)], https://www.codenameone.com/javadoc/com/codename1/ui/Image.html#createImage(java.io.InputStream)[Image.createImage(InputStream)] & https://www.codenameone.com/javadoc/com/codename1/ui/Image.html#createImage(byte%5B%5D,int,int)[Image.`createImage(byte array, int, int)`],... TIP: Some other APIs might return this image type but those APIs do so explicitly! @@ -659,7 +659,7 @@ There are two types of RGB constructed images that are different from one anothe ===== Internal -This is a close cousin of the loaded image. This image is created using the method https://www.codenameone.com/javadoc/com/codename1/ui/Image.html#createImage(int[],int,int)[Image.createImage(int array, int, int)] and receives the AARRGGBB data to form the image. It's more efficient than the Codename One RGB image but can't be modified, at least not on the pixel level. +This is a close cousin of the loaded image. This image is created using the method https://www.codenameone.com/javadoc/com/codename1/ui/Image.html#createImage(int%5B%5D,int,int)[Image.createImage(int array, int, int)] and receives the AARRGGBB data to form the image. It's more efficient than the Codename One RGB image but can't be modified, at least not on the pixel level. The goal of this image type is to provide an easy way to render RGB data that isn't modified efficiently at platform native speeds. It's technically a <> internally. diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index 4bd5440ea1c..0a770cdc863 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -37,6 +37,12 @@ # So both spellings are refused instead, which keeps the gap from opening quietly. ATTRIBUTE_URL_DECL_RE = re.compile(r"^:[A-Za-z0-9_-]+:\s*https?://") ATTRIBUTE_LINK_RE = re.compile(r"\blink:\{[^}]+\}") +# An array parameter written raw ends the AsciiDoc link macro at the "[", so the +# URL is cut mid-signature and the label is lost -- #createImage(byte[],int,int) +# rendered as a bare link to "#createImage(byte". It has to be written %5B%5D. +# Detected in the source, because URL_RE stops at that "[" and never sees it. An +# empty bracket pair is unambiguous: a label is never empty. +RAW_ARRAY_IN_JAVADOC_RE = re.compile(r"/javadoc/[^\s\[]*#[^\s\[]*\[\]") # A root-relative target names a website route just as an absolute URL does, but # it carries no scheme, so URL_RE never sees it -- and check-guide-xrefs.py skips # hrefs beginning with "/" because they are not same-page anchors. Between the two @@ -117,7 +123,7 @@ def front_matter(page: Path) -> dict[str, object]: # YAML block sequence ("- /x") and TOML/flow array ("\"/x\",") both # appear in this tree, so accept either continuation shape. if stripped.startswith("-") or stripped.startswith(("\"", "'")): - aliases.append(stripped.lstrip("- ").strip().rstrip(",").strip("\"'")) + aliases.append(strip_inline_comment(stripped.lstrip("- ").strip().rstrip(","))) continue in_aliases = False # Hugo treats front-matter keys case-insensitively, and this tree mixes @@ -134,7 +140,7 @@ def front_matter(page: Path) -> dict[str, object]: if raw in {"", "[", "[]"}: in_aliases = raw != "[]" else: - aliases.extend(v.strip().strip("\"'") for v in raw.strip("[]").split(",") if v.strip()) + aliases.extend(strip_inline_comment(v) for v in raw.strip("[]").split(",") if v.strip()) continue out[key] = strip_inline_comment(raw) if aliases: @@ -746,6 +752,8 @@ def findings_for(path: Path, known: set[str], patterns: list, declared: set[str] for number, line in enumerate(path.read_text(encoding="utf-8").split("\n"), 1): if ATTRIBUTE_URL_DECL_RE.match(line.strip()): out.append((line.strip().split()[0], "an attribute holding a URL: any link built from it is unchecked, because this does not expand attributes")) + for hit in RAW_ARRAY_IN_JAVADOC_RE.findall(line): + out.append((hit, "an unencoded array bracket ends the link macro here; write %5B%5D")) if ATTRIBUTE_LINK_RE.search(line): out.append((ATTRIBUTE_LINK_RE.search(line).group(0), "a link target built from an attribute, which this cannot expand or check")) for target in ROOT_RELATIVE_RE.findall(line): From 92a9a912a74922c64cde316bb0141a77ad803cdc Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Thu, 3 Sep 2026 01:00:15 +0300 Subject: [PATCH 39/51] A macro target is not prose, and a chapter has one place in the book Trailing punctuation was trimmed off every URL, which is right after a BARE url -- the full stop belongs to the sentence -- and wrong inside an explicit macro, where "[" delimits the target and link:https://host/download.[label] really does request "/download.". Trimming there validated a different route than the browser asks for. The two cases are told apart now by whether a "link:" precedes the URL or a "[" follows it. link:https://www.codenameone.com/download.[label] old 0 -> new 1 "...at https://www.codenameone.com/download/." new 0 Grouping include edges by (parent, target) fixed same-parent duplicates and left a gap next to it: a chapter included from the manifest AND from some nested document has two different parents, so both counters read one and nothing is reported, while the title check only asks for "at least once". A direct chapter now has to have exactly one parent. Cross-parent reuse stays legitimate for a fragment -- that is what a fragment is for -- but a chapter already has its place. a manifest chapter also included by a nested file old 0 -> new 1 Neither construct is in the guide: no macro target ends in punctuation, and of the 90 direct chapters none is included anywhere else. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 13 +++++++++++-- .../developer-guide/check-guide-structure.py | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index 0a770cdc863..486b6e31e05 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -770,8 +770,17 @@ def findings_for(path: Path, known: set[str], patterns: list, declared: set[str] normalized = normalize_path(path) if not resolves(normalized, known, patterns): out.append((target, "the website serves no such path (checked _redirects and the content tree)")) - for url in URL_RE.findall(line): - url = url.rstrip(".,;:") + for match in URL_RE.finditer(line): + url = match.group(0) + # Trailing punctuation is sentence punctuation after a BARE url, and + # part of the path inside an explicit macro, where the "[" delimits the + # target: link:https://host/download.[label] really does request + # "/download.". Trimming unconditionally validated a different route. + explicit = line[: match.start()].rstrip().endswith("link:") or line[ + match.end() : match.end() + 1 + ] == "[" + if not explicit: + url = url.rstrip(".,;:") split = urlsplit(url) # urlsplit lowercases the host but keeps the root label's trailing dot, # so the fully qualified spelling "www.codenameone.com." misses diff --git a/scripts/developer-guide/check-guide-structure.py b/scripts/developer-guide/check-guide-structure.py index a6b0a4f1b6b..231ffb0c935 100755 --- a/scripts/developer-guide/check-guide-structure.py +++ b/scripts/developer-guide/check-guide-structure.py @@ -393,6 +393,24 @@ def main() -> int: # A chapter included twice by the manifest is rendered twice. The title check # below cannot see it, because it only asks whether a title appears AT LEAST # as often as it is declared. + # A chapter reached from the manifest AND from some nested document renders + # twice, but each (parent, target) pair counts one, so the duplicate rule sees + # nothing and the title check only asks for "at least once". Cross-parent reuse + # stays legitimate for a FRAGMENT; a direct chapter is a different thing -- + # it already has its place in the book. + for target in sorted(walker.direct, key=lambda path: path.name): + others = sorted( + parent.name + for (parent, other) in walker.include_edges + if other == target and parent != walker.root + ) + if others: + errors.append( + f"{target.name}: is a chapter in the manifest and is also included by " + f"{', '.join(others)}, so the book renders it twice. Include it in one " + f"place." + ) + for (parent, target), count in sorted( walker.include_edges.items(), key=lambda item: (item[0][0].name, item[0][1].name) ): From e54e3f2ceb8f50857fbae5930d865d941f0bdce8 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Thu, 3 Sep 2026 01:09:44 +0300 Subject: [PATCH 40/51] class-use pages are not generated, so linking to one is not fine When the Javadoc derivation went in I let a class-use/ path through by stripping the segment and validating the enclosing package, on the assumption that javadoc emits usage pages alongside the types. It does not, unless asked: the generator's invocation carries no -use, and run both ways on the same sources javadoc produced 0 class-use directories without it and 1 with it. So the leniency accepted links to pages the build never writes. That exemption was my own speculation rather than anything the guide needed -- it links to no class-use page at all -- and removing it needs no special case: the path names a package that does not exist, which the existing check already reports. /javadoc/com/codename1/ui/class-use/Component.html old 0 -> new 1 /javadoc/com/codename1/ui/Component.html new 0 /javadoc/com/codename1/ui/package-summary.html new 0 Index and overview pages are still accepted, because those javadoc does emit without being asked. Re-validated across the guide: 423 javadoc links, 0 rejected. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index 486b6e31e05..0ec7f2fa209 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -443,8 +443,8 @@ def javadoc_path_exists(target: str) -> bool: case-sensitive host served 404s while this reported success. Anything that is not a recognisable package or class page is still accepted: - javadoc emits index pages, class-use trees and frames this does not model, and - reporting those would be a false alarm rather than a finding. + javadoc emits index and overview pages this does not model, and reporting those + would be a false alarm rather than a finding. """ if _JAVADOC_ROOT is None: return True @@ -456,9 +456,10 @@ def javadoc_path_exists(target: str) -> bool: page = PurePosixPath(path).name if package == ".": return True # a top-level index or overview page, outside the model - # class-use/ holds one page per type, alongside the package it belongs to. - if package.endswith("/class-use"): - package = package[: -len("/class-use")] + # No class-use/ exemption: the generator does not pass -use, and without it + # javadoc emits no usage pages at all -- verified by running it both ways. An + # earlier version stripped the segment and validated the enclosing package, + # which accepted a link to a page that is never built. if package not in packages: # The package itself will not exist in the generated tree. This is the # case that mattered: com/codename1/JavaScript is spelt lowercase in the From bd3fb14d216ef559189f1d41831ea9e539193cf3 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Thu, 3 Sep 2026 01:16:08 +0300 Subject: [PATCH 41/51] A reused fragment renders twice, and the CLDC sources trigger nothing Expected titles were built from walker.reachable, which holds each path once, so a fragment two parents both include expected ONE title while rendering two. The check asks whether a title appears at least as often as expected, so a swallowed occurrence hid behind the surviving one. Counted per inclusion now. Probed by reusing a fragment from a second parent with prose immediately before the include: old passed silently new "appears 1 time(s) in the rendered book but 2 document(s) declare it" and legitimate reuse -- the same fragment from two parents, both spaced properly -- still passes. Note the spacing rule does NOT catch this shape: it fires when the INCLUDED file ends mid-paragraph, and here it is the parent that puts prose in front of the include. Separately, check-guide-links.py indexes Ports/CLDC11/src as a Javadoc source root, because build_javadocs.sh generates from it, but neither documentation workflow listed it as a trigger -- only its sibling CodenameOne/src. Deleting or renaming a linked CLDC type could therefore merge unvalidated, and the stale link would surface in the next scheduled website build, after the fact. Added to both the pull_request and push filters, next to the root it belongs beside. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/website-docs.yml | 8 ++++++++ scripts/developer-guide/check-guide-structure.py | 13 ++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/.github/workflows/website-docs.yml b/.github/workflows/website-docs.yml index fae57010a9f..f6bb22d1392 100644 --- a/.github/workflows/website-docs.yml +++ b/.github/workflows/website-docs.yml @@ -20,6 +20,10 @@ on: - 'vm/ByteCodeTranslator/**' - 'vm/JavaAPI/**' - 'CodenameOne/src/**' + # The other root build_javadocs.sh generates from, and the other one + # check-guide-links.py indexes. Without it, deleting a linked CLDC type + # merges unvalidated and the next scheduled build is where it surfaces. + - 'Ports/CLDC11/src/**' # The developer guide this site renders includes a build hint table that is # generated rather than committed, so a change to the catalog or to the # renderer changes the published page without touching docs/. The @@ -46,6 +50,10 @@ on: - 'vm/ByteCodeTranslator/**' - 'vm/JavaAPI/**' - 'CodenameOne/src/**' + # The other root build_javadocs.sh generates from, and the other one + # check-guide-links.py indexes. Without it, deleting a linked CLDC type + # merges unvalidated and the next scheduled build is where it surfaces. + - 'Ports/CLDC11/src/**' # As above: the build hint table is generated, not committed. - 'maven/build-hint-catalog/**' - 'maven/build-hint-tools/**' diff --git a/scripts/developer-guide/check-guide-structure.py b/scripts/developer-guide/check-guide-structure.py index 231ffb0c935..e5e785fcb34 100755 --- a/scripts/developer-guide/check-guide-structure.py +++ b/scripts/developer-guide/check-guide-structure.py @@ -511,8 +511,19 @@ def main() -> int: key = normalize(heading[1]) # A direct entry must appear at CHAPTER level. A nested fragment sits at # whatever depth its parent puts it, so it is only counted at all. + # + # Counted once per INCLUSION, not once per file. A fragment two parents + # both include renders twice, and expecting one title let a swallowed + # occurrence hide behind the surviving one -- the check only ever asks + # whether a title appears at least as often as expected. + occurrences = sum( + count + for (_, included), count in walker.include_edges.items() + if included == path + ) or 1 target = expected_chapters if path in walker.direct else expected - target.setdefault(key, []).append(path.name) + for _ in range(occurrences): + target.setdefault(key, []).append(path.name) for title, sources in sorted(expected_chapters.items()): found = rendered_chapters.get(title, 0) From 298265275b70dd9f95eb8a67404757c849a5b359 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Thu, 3 Sep 2026 01:24:49 +0300 Subject: [PATCH 42/51] An anchor decorates the block below it; it is not the block A bracketed attribute line counted as the promised listing, so an anchor in front of an ordinary paragraph -- [#next-section] and then prose -- suppressed exactly the defect this gate exists to find. Attribute lines are stepped over now and the block they attach to is what gets classified. [#next-section] + prose old 0 -> new 1 [source,java] + ---- new 0 [cols="1,2"] + |=== new 0 A first attempt also stepped over block TITLES, on the same reasoning, and it was wrong in a way the baseline caught immediately: 33 entries went stale. Reading them showed why -- "Simple usage of the `Calendar` class looks something like this:" followed by `.The Calendar component` and an image is a real hole, the listing having been removed by the snippet extraction while the figure stayed. A titled figure does not answer a promise of code, and treating the title as decoration would have banked 33 genuine holes as fixed. Only bracket attributes are skipped. One behaviour does change with no instance behind it: an anchor followed by a titled image now reports, where the anchor alone used to suppress it. That is the consistent answer -- the 33 above are exactly the untitled-anchor version of the same shape -- and the guide contains none either way. Baseline unchanged at 402, none new, none stale. Co-Authored-By: Claude Opus 5 (1M context) --- .../developer-guide/check-missing-code-blocks.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/scripts/developer-guide/check-missing-code-blocks.py b/scripts/developer-guide/check-missing-code-blocks.py index 988fa35d455..57d44446d7c 100755 --- a/scripts/developer-guide/check-missing-code-blocks.py +++ b/scripts/developer-guide/check-missing-code-blocks.py @@ -68,6 +68,11 @@ # already span [source], [listing], [cols=...], [options=...], [quote] and an # anchored image, and a whitelist would report the next kind nobody thought of. ADMONITION = "NOTE|TIP|IMPORTANT|WARNING|CAUTION" +# A bracketed attribute list or a block title. Both attach to the block BELOW them, +# so neither answers the question "is a listing here". +ATTRIBUTE_LINE_RE = re.compile( + r'^\[(?!(?:' + "NOTE|TIP|IMPORTANT|WARNING|CAUTION" + r')[,\]])[a-zA-Z%.#"][^\]]*\]\s*$' +) BLOCK_START_RE = re.compile( # The name may be followed by "]" or by further attributes, as in # [NOTE,caption="Aside"] -- requiring the bracket immediately made an @@ -112,6 +117,16 @@ def scan(path: Path) -> list[tuple[int, str]]: following = index + 1 while following < len(lines) and not lines[following].strip(): following += 1 + # An attribute line decorates whatever comes next; it is not itself the + # block. [source,java] is followed by the delimiter, [cols=...] by the + # table, an anchor by an image -- and [#next-section] by nothing but an + # ordinary paragraph, which is exactly the hole this gate looks for. So + # step over attribute lines and block titles and classify what they attach + # to. Admonitions never reach here; ADMONITION excludes them above. + while following < len(lines) and ATTRIBUTE_LINE_RE.match(lines[following].strip()): + following += 1 + while following < len(lines) and not lines[following].strip(): + following += 1 if following < len(lines) and BLOCK_START_RE.match(lines[following].strip()): continue findings.append((index + 1, normalize(stripped))) From 7cbeee17c1e3fe992af5bbb7f5d9e3a7b07b8011 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Thu, 3 Sep 2026 01:33:33 +0300 Subject: [PATCH 43/51] Two package pages javadoc never writes, and multiplicity that stopped at one edge package-frame.html is a pre-JDK-11 artifact and package-use.html needs -use, which the generator does not pass -- the same reason class-use/ is not accepted. Both sat in the accepted set on my assumption rather than on evidence. Running javadoc --release 8 -protected over a one-class package writes exactly package-summary.html and package-tree.html, so those two are what the set holds now. The guide links to none of the four. package-summary.html accepted package-tree.html accepted package-frame.html rejected package-use.html rejected The reuse fix in the previous round counted occurrences from the edges pointing at a file, which stops one level short: a fragment two parents both include renders twice, and so does everything IT includes, but _visit() returns early on the second traversal so only one edge exists for each descendant. Occurrences are computed across the whole graph now -- each node is the sum over its incoming edges of the parent's count times the edge multiplicity, root = 1 -- with a guard against a cycle asciidoctor would reject anyway. Checked on a synthetic diamond (root->a, root->b, a->frag, b->frag, frag->desc): frag and desc both come out at 2, a and b at 1, and a doubled single edge propagates as 2. Then on the real book: adding a second parent for Maven-Appendix-Goals takes it AND its appendix_goal_* descendants to 2, and removing it returns them to 1. Note the reviewer's route to this -- a conditional that swallows one occurrence -- is now refused outright wherever it appears, so the scenario is not currently reachable. The count was still wrong, and it is cheap to be right. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 6 ++- .../developer-guide/check-guide-structure.py | 51 +++++++++++++++---- 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index 0ec7f2fa209..b2f8a4113d7 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -253,10 +253,12 @@ def redirect_pattern(source: str) -> tuple[re.Pattern[str], list[str]] | None: NESTED_TYPE_RE = ( r"\b(?:public|protected)\b[^;{{]*?\b(?:class|interface|enum|record|@interface)\s+{stem}\b" ) +# What a --release 8 -protected run actually writes beside a package, checked by +# running it: package-frame.html is a pre-JDK-11 artifact and is never emitted, +# and package-use.html needs -use, which the generator does not pass -- the same +# reason class-use/ is not accepted. JAVADOC_PACKAGE_PAGES = { "package-summary.html", - "package-frame.html", - "package-use.html", "package-tree.html", } _javadoc_index: tuple[set[str], set[str]] | None = None diff --git a/scripts/developer-guide/check-guide-structure.py b/scripts/developer-guide/check-guide-structure.py index e5e785fcb34..ba87d57bec2 100755 --- a/scripts/developer-guide/check-guide-structure.py +++ b/scripts/developer-guide/check-guide-structure.py @@ -342,6 +342,39 @@ def _check_include_spacing( ) +def occurrence_counts(root: Path, edges: collections.Counter) -> dict[Path, int]: + """How many times each document renders, following multiplicity down the graph. + + A file included twice renders twice, and so does every file IT includes. The + include graph is a DAG -- asciidoctor rejects a cycle -- so each node's count + is the sum over its incoming edges of the parent's count times the edge's + multiplicity, with the root rendering once. + """ + incoming: dict[Path, list[tuple[Path, int]]] = collections.defaultdict(list) + for (parent, child), count in edges.items(): + incoming[child].append((parent, count)) + + counts: dict[Path, int] = {} + visiting: set[Path] = set() + + def count_for(node: Path) -> int: + if node == root: + return 1 + if node in counts: + return counts[node] + if node in visiting: + return 1 # a cycle asciidoctor would reject; do not spin on it + visiting.add(node) + total = sum(count_for(parent) * n for parent, n in incoming[node]) or 1 + visiting.discard(node) + counts[node] = total + return total + + for child in incoming: + count_for(child) + return counts + + def render(root: Path) -> str: with tempfile.TemporaryDirectory() as tmp: out = Path(tmp) / "guide.html" @@ -495,6 +528,8 @@ def main() -> int: f"A direct manifest entry must come out at level 2." ) + render_counts = occurrence_counts(root, walker.include_edges) + # 3. Outcome check: every included chapter's title survives into the book. rendered, rendered_chapters = rendered_titles(render(root)) expected: dict[str, list[str]] = {} @@ -512,15 +547,13 @@ def main() -> int: # A direct entry must appear at CHAPTER level. A nested fragment sits at # whatever depth its parent puts it, so it is only counted at all. # - # Counted once per INCLUSION, not once per file. A fragment two parents - # both include renders twice, and expecting one title let a swallowed - # occurrence hide behind the surviving one -- the check only ever asks - # whether a title appears at least as often as expected. - occurrences = sum( - count - for (_, included), count in walker.include_edges.items() - if included == path - ) or 1 + # How many times this file RENDERS, which is not how many edges point at + # it. Multiplicity multiplies down the graph: a fragment two parents both + # include renders twice, and so does everything it includes in turn -- + # counting the single edge recorded before _visit() returned early on the + # second traversal expected one title for two renderings, and a swallowed + # one hid behind the survivor. + occurrences = render_counts.get(path, 1) target = expected_chapters if path in walker.direct else expected for _ in range(occurrences): target.setdefault(key, []).append(path.name) From d45e1dae505c84efc3c459ec2b6d9adcd2ad20af Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Thu, 3 Sep 2026 01:42:10 +0300 Subject: [PATCH 44/51] Two leniency hatches that accepted anything shaped vaguely right A path without .html was taken for an asset and accepted whatever it named, so /javadoc/com/codename1/DefinitelyMissing/ passed on the strength of having no file extension. A directory under the tree is now one of three things: the root itself, one of javadoc's own asset directories, or a package -- and the package set is already derived, so nothing new had to be modelled. A page with no package component was taken for an index page and accepted for the same reason, so /javadoc/DefinitelyMissing.html passed too. The set javadoc writes at the root is finite; it is listed now, from a real run rather than from memory. Four of the eleven -- constant-values, deprecated-list, serialized-form, search -- are emitted only when the sources give them something to hold, so they are accepted without being required. /javadoc/ accepted /javadoc/index.html accepted /javadoc/com/codename1/ui/ accepted /javadoc/resources/glass.png accepted /javadoc/DefinitelyMissing.html rejected /javadoc/com/codename1/DefinitelyMissing/ rejected /javadoc/com/codename1/impl/ARImpl.html rejected Both hatches were mine, written when the derivation went in to avoid false alarms on shapes I had not enumerated. Enumerating them costs a javadoc run. 423 links in the guide, 0 rejected. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 36 ++++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index b2f8a4113d7..724945dde61 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -261,6 +261,24 @@ def redirect_pattern(source: str) -> tuple[re.Pattern[str], list[str]] | None: "package-summary.html", "package-tree.html", } +# The finite set javadoc writes at the root of the tree. Taken from a real run -- +# the first seven always appear; the rest are emitted only when the sources have +# anything to put in them, so they are accepted without being required. +JAVADOC_ROOT_PAGES = { + "index.html", + "overview-summary.html", + "overview-tree.html", + "allclasses-index.html", + "allpackages-index.html", + "index-all.html", + "help-doc.html", + "constant-values.html", + "deprecated-list.html", + "serialized-form.html", + "search.html", +} +# Directories javadoc writes beside the packages, for its own assets. +JAVADOC_ASSET_DIRS = {"legal", "resources", "script-dir"} _javadoc_index: tuple[set[str], set[str]] | None = None @@ -451,13 +469,25 @@ def javadoc_path_exists(target: str) -> bool: if _JAVADOC_ROOT is None: return True path = target[len("/javadoc/"):] if target.startswith("/javadoc/") else target - if not path.endswith(".html"): - return True # a directory or an asset, not a documented type + path = path.strip("/") packages, classes = javadoc_index(_JAVADOC_ROOT) + if not path.endswith(".html"): + # A directory: the tree root, one of javadoc's own asset directories, or a + # package. Anything else names a directory the generator never creates -- + # accepting every non-.html path let /javadoc/com/codename1/DefinitelyMissing/ + # through on the strength of having no file extension. + if not path: + return True + if path.split("/", 1)[0] in JAVADOC_ASSET_DIRS: + return True + return path in packages package = str(PurePosixPath(path).parent) page = PurePosixPath(path).name if package == ".": - return True # a top-level index or overview page, outside the model + # A page at the root of the tree. The set javadoc writes there is finite, + # so an invented one -- /javadoc/DefinitelyMissing.html -- is a 404 rather + # than something outside the model. + return page in JAVADOC_ROOT_PAGES # No class-use/ exemption: the generator does not pass -use, and without it # javadoc emits no usage pages at all -- verified by running it both ways. An # earlier version stripped the segment and validated the enclosing package, From 102bd459e34ab8e845b2edebde0eabd0f874ce43 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Thu, 3 Sep 2026 01:49:28 +0300 Subject: [PATCH 45/51] A wildcard declares a slashed route just as a literal one does The trailing-slash rule asked whether _redirects spells the path out literally, and three of its sources are wildcards that end in a slash -- /*.html/, /blog/*.html/ and /demos/*/. So /download.html/, which that first rule really does cover and really does serve, was reported as broken. A false positive on a working route is the worse half of this gate's failure modes: it blocks the workflow on prose nobody needs to change. The sources are compiled a second time for this, anchored exactly rather than with the "/?" the routing patterns carry. That leniency is right for asking "does this resolve" and wrong for asking "does the table declare THIS spelling": /*.html/ covers /download.html/ and does not cover /download.html, and a slash-insensitive match cannot tell the two apart. /download.html/ old 1 -> new 0 (wildcard covers it) /videos.html/ new 0 (literal, as before) /files/CodenameOneBuildClient.jar/ unchanged (nothing declares it) /blog/ new 0 (a directory route) One probe needed a second look: a real blog post with .html/ passed both versions, because that post has its own literal rule in the table -- the wildcard is belt-and-braces there rather than the thing being tested. /download.html/ is the case with no literal behind it. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 58 +++++++++++++++----- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index 724945dde61..65112247e0d 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -230,6 +230,30 @@ def redirect_pattern(source: str) -> tuple[re.Pattern[str], list[str]] | None: return re.compile("^" + pattern + "/?$"), names +def exact_redirect_pattern(source: str) -> re.Pattern[str] | None: + """Compile a source so it matches ONLY the spelling it declares. + + redirect_pattern() ends every rule with "/?" so a link resolves whichever way + it is written, which is right for routing and wrong for asking "does the table + declare this exact form". `/*.html/ /:splat/` really does cover /download.html/ + -- the slash is part of the source -- and matching it slash-insensitively would + have said the same about /download.html, which it does not cover. + """ + if "*" not in source and ":" not in source: + return None + pattern = "" + for part in re.split(r"(\*|:[A-Za-z_][A-Za-z0-9_]*)", source): + if not part: + continue + if part == "*": + pattern += "(.*)" + elif part.startswith(":"): + pattern += "([^/]+)" + else: + pattern += re.escape(part) + return re.compile("^" + pattern + "$") + + # build_javadocs.sh generates the API docs from these two roots, so the published # tree is derivable from the repository without building it. JAVADOC_SOURCE_ROOTS = ("CodenameOne/src", "Ports/CLDC11/src") @@ -554,7 +578,7 @@ def resolves(target: str, known: set[str], rules: list, depth: int = 0) -> bool: return False -def site_paths(repo_root: Path) -> tuple[set[str], list, set[str]]: +def site_paths(repo_root: Path) -> tuple[set[str], list, set[str], list]: """Every path the website is known to answer on, derived rather than listed. Returns the literal paths and every redirect rule, each as a matcher, its @@ -567,6 +591,9 @@ def site_paths(repo_root: Path) -> tuple[set[str], list, set[str]]: # ("^...$/?"), which is right for matching but loses the distinction the site # actually draws, so the trailing-slash rule needs the raw spelling. declared: set[str] = set() + # Wildcard sources, matched exactly: /*.html/ declares the slashed form of every + # root-level .html route, and a literal-set lookup cannot see that. + declared_patterns: list[re.Pattern[str]] = [] redirects = repo_root / "docs/website/static/_redirects" if redirects.exists(): @@ -576,6 +603,9 @@ def site_paths(repo_root: Path) -> tuple[set[str], list, set[str]]: continue destination = parts[1] if len(parts) > 1 else "" declared.add(parts[0]) + exact = exact_redirect_pattern(parts[0]) + if exact is not None: + declared_patterns.append(exact) compiled = redirect_pattern(parts[0]) if compiled is not None: patterns.append((compiled[0], compiled[1], destination)) @@ -713,7 +743,7 @@ def site_paths(repo_root: Path) -> tuple[set[str], list, set[str]]: if asset.name == "index.html": paths.add(normalize_path(asset.parent.relative_to(static).as_posix())) - return paths, patterns, declared + return paths, patterns, declared, declared_patterns def bare_authority(split, host: str, port: int | None) -> bool: @@ -742,7 +772,7 @@ def links_into_this_book(path: str, fragment: str) -> bool: return bool(fragment) and (path.rstrip("/") or "/") in SELF_PATHS -def undeclared_file_slash(path: str, declared: set[str]) -> bool: +def undeclared_file_slash(path: str, declared: set[str], declared_patterns: list) -> bool: """A file-like path wearing a trailing slash the redirect table does not spell out. The site treats "/x.html" and "/x.html/" as separate routes and declares both @@ -751,14 +781,16 @@ def undeclared_file_slash(path: str, declared: set[str]) -> bool: not asked for. Directory routes such as /blog/ and /javadoc/com/codename1/io/ have no dot in the last segment and never match. """ - return ( - path.endswith("/") - and "." in path.rstrip("/").rsplit("/", 1)[-1] - and path not in declared - ) + if not path.endswith("/"): + return False + if "." not in path.rstrip("/").rsplit("/", 1)[-1]: + return False + if path in declared: + return False + return not any(pattern.match(path) for pattern in declared_patterns) -def findings_for(path: Path, known: set[str], patterns: list, declared: set[str]) -> list[tuple[str, str]]: +def findings_for(path: Path, known: set[str], patterns: list, declared: set[str], declared_patterns: list) -> list[tuple[str, str]]: # Only http:// and https:// are extracted. Protocol-relative links were raised # as a gap; measured, the guide contains no `link://` macro at all, and its one # bare `//host/path` is a JavaScript string inside a source block, so widening @@ -795,7 +827,7 @@ def findings_for(path: Path, known: set[str], patterns: list, declared: set[str] if links_into_this_book(path, fragment): out.append((target, SELF_LINK_REASON)) continue - if undeclared_file_slash(path, declared): + if undeclared_file_slash(path, declared, declared_patterns): # Same rule as for an absolute URL: normalize_path would drop the # slash and validate the variant that was not asked for. out.append((target, "a file path with a trailing slash that _redirects does not declare")) @@ -868,7 +900,7 @@ def findings_for(path: Path, known: set[str], patterns: list, declared: set[str] target = split.path.rstrip("/") or "/" if links_into_this_book(target, split.fragment): out.append((url, SELF_LINK_REASON)) - elif undeclared_file_slash(split.path, declared): + elif undeclared_file_slash(split.path, declared, declared_patterns): out.append((url, "a file path with a trailing slash that _redirects does not declare")) elif not resolves(target, known, patterns): out.append((url, "the website serves no such path (checked _redirects and the content tree)")) @@ -910,7 +942,7 @@ def main() -> int: guide_dir = args.guide_dir.resolve() global _JAVADOC_ROOT _JAVADOC_ROOT = args.repo_root.resolve() - known, patterns, declared = site_paths(args.repo_root.resolve()) + known, patterns, declared, declared_patterns = site_paths(args.repo_root.resolve()) if not known: raise SystemExit("could not derive any site paths; is --repo-root correct?") @@ -920,7 +952,7 @@ def main() -> int: if path.suffix not in ASCIIDOC_EXTENSIONS or not path.is_file(): continue name = path.relative_to(guide_dir).as_posix() - for url, reason in findings_for(path, known, patterns, declared): + for url, reason in findings_for(path, known, patterns, declared, declared_patterns): entry = f"{name}\t{url}" current[entry] += 1 reasons[entry] = reason From 79cb5e9dff422ea2b4a41688d72eb5d2abb642d4 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Thu, 3 Sep 2026 01:57:14 +0300 Subject: [PATCH 46/51] Rejecting javadoc's asset directories rather than enumerating them Accepting anything whose first segment was legal/, resources/ or script-dir/ was the last of the "looks about right" hatches: /javadoc/resources/does-not-exist.js passed on the strength of the directory name. The reviewer's suggestion is to validate the full path against the generated file set, and that is the one option I will not take. Those directories hold javadoc's own plumbing and their contents are version specific -- a JDK 17 run here writes jquery-3.6.1.min.js, and the tree this actually gates is generated by JDK 25, which ships a different one. Listing them would be asserting the contents of a tree this repository does not build, and it would rot at the next JDK bump. So a path into one is rejected instead. The guide links into none of them, and documentation prose has no business pointing at javadoc's internals; if that ever changes, the fix is to link to the documented page rather than to its stylesheet. /javadoc/ accepted /javadoc/index.html accepted /javadoc/com/codename1/ui/ accepted /javadoc/com/codename1/ui/Form.html accepted /javadoc/resources/glass.png rejected /javadoc/resources/does-not-exist.js rejected 423 guide links, 0 rejected. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index 65112247e0d..0c4f245ca0d 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -301,8 +301,13 @@ def exact_redirect_pattern(source: str) -> re.Pattern[str] | None: "serialized-form.html", "search.html", } -# Directories javadoc writes beside the packages, for its own assets. -JAVADOC_ASSET_DIRS = {"legal", "resources", "script-dir"} +# javadoc writes legal/, resources/ and script-dir/ beside the packages for its own +# plumbing -- stylesheets, jQuery, licence texts. Their contents are version +# specific (JDK 17 ships jquery-3.6.1.min.js; another release ships another), so +# enumerating them here would hardcode a claim about a tree this repository does +# not build and would rot at the next JDK bump. The guide links into none of them, +# and documentation prose has no business pointing at javadoc's internals, so a +# path into one is rejected rather than waved through on its first segment. _javadoc_index: tuple[set[str], set[str]] | None = None @@ -502,8 +507,6 @@ def javadoc_path_exists(target: str) -> bool: # through on the strength of having no file extension. if not path: return True - if path.split("/", 1)[0] in JAVADOC_ASSET_DIRS: - return True return path in packages package = str(PurePosixPath(path).parent) page = PurePosixPath(path).name From abdb22b6e6494a3cf275079fdcece6b6c8e47b01 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Thu, 3 Sep 2026 02:07:59 +0300 Subject: [PATCH 47/51] A titled listing is a listing, and a figure was never the promised code Restricting the attribute skip to bracket lines last round introduced a false positive: `.Example` in front of [source,java] stopped the walk, and a block title is not a block start, so a perfectly good titled listing was reported as a missing one. [[anchor]] had the same problem. Both are metadata attached to the block below them and are skipped now. Skipping titles is what I tried first last round and reverted, because it turned 33 baseline entries stale. The reason it did is the actual defect underneath: image:: counted as an answer to a promise of CODE, so whether a hole was reported depended on whether the figure happened to carry a title -- titled ones were caught, untitled ones were not. A figure is not a listing either way, so image:: is out of the block set and the two cases agree. That surfaces two holes that were hidden, and both are real: Maps.asciidoc:132 "...for example \"try the native Google SDK, then the web map, then the vector MapView\":" followed by a screenshot Miscellaneous-Features.asciidoc:465 "...use the Media, MediaManager and MediaRecorderBuilder APIs to capture audio:" followed by a screenshot Baseline 402 -> 404. Growing a ratchet needs justification: these are not new debt, they are debt that was being hidden by a rule that could not tell a figure from a listing. .Example + [source,java] + ---- old 1 -> new 0 [[sample]] + [source,java] old 1 -> new 0 .A figure + image:: unchanged, still a hole Separately, a chapter whose own title sits inside a backend conditional has no title in the branch that excludes it, and its body merges into whatever precedes it -- which one render cannot show, since first_heading() reads the source and the HTML render contains the title. Rather than render the book twice for a construct the guide does not use (measured: zero headings inside a backend conditional), the construct is refused. Co-Authored-By: Claude Opus 5 (1M context) --- .../developer-guide/check-guide-structure.py | 36 +++++++++++++++++++ .../check-missing-code-blocks.py | 12 +++++-- .../missing-code-blocks-baseline.txt | 2 ++ 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/scripts/developer-guide/check-guide-structure.py b/scripts/developer-guide/check-guide-structure.py index ba87d57bec2..113815f83a1 100755 --- a/scripts/developer-guide/check-guide-structure.py +++ b/scripts/developer-guide/check-guide-structure.py @@ -80,6 +80,35 @@ def parse_lines(path: Path) -> list[str]: return path.read_text(encoding="utf-8").split("\n") +def heading_is_conditional(path: Path) -> bool: + """Whether the file's first heading sits inside a backend conditional. + + A chapter whose own title is conditional has no title in the branch that + excludes it, and its body merges into whatever precedes it there. The outcome + check cannot see that from one render: first_heading() reads the source, so + the title is found, and the HTML render contains it. Rather than render the + book a second time for a construct the guide does not use -- measured, zero + headings sit inside a backend conditional -- refuse the construct. + """ + open_fence: str | None = None + depth = 0 + for line in parse_lines(path): + fence = COMMENT_FENCE_RE.match(line) + if fence: + token = fence.group(1) + open_fence = token if open_fence is None else (None if token == open_fence else open_fence) + continue + if open_fence is not None: + continue + if BLOCK_DIRECTIVE_RE.match(line.strip()): + depth += 1 if not line.strip().startswith("endif::") else -1 + depth = max(0, depth) + continue + if HEADING_RE.match(line): + return depth > 0 + return False + + def first_heading(path: Path) -> tuple[int, str] | None: """Return (level, title) of the file's first heading outside a fenced block.""" open_fence: str | None = None @@ -540,6 +569,13 @@ def main() -> int: # title in this render would report a chapter that is deliberately # absent. Its level and spacing are still checked above. continue + if heading_is_conditional(path): + errors.append( + f"{path.name}: its own title sits inside a conditional. In the branch " + f"that excludes it the chapter has no heading and its body merges into " + f"whatever precedes it, which one render cannot show. Put the title " + f"outside the conditional." + ) heading = first_heading(path) if not heading: continue diff --git a/scripts/developer-guide/check-missing-code-blocks.py b/scripts/developer-guide/check-missing-code-blocks.py index 57d44446d7c..16e77c6a9c7 100755 --- a/scripts/developer-guide/check-missing-code-blocks.py +++ b/scripts/developer-guide/check-missing-code-blocks.py @@ -58,7 +58,11 @@ # (*text*) are not. Stripping the marker lets the prose test see the sentence, # so an introduction written as a list item is not mistaken for markup. LIST_MARKER_RE = re.compile(r"^([*\-]+|\.{1,5}|[0-9]+\.)\s+") -# What a real block looks like when it starts. An introduction separated from its +# What a real block looks like when it starts. image:: is deliberately absent: a +# figure is not the listing a sentence promised, which is what the 33 baseline +# entries of the form "looks something like this:" followed by a titled image +# already record. Counting it made the answer depend on whether the figure +# happened to carry a title. An introduction separated from its # listing by more than one blank line is untidy, not a hole, and reporting it # would make the gate reject valid AsciiDoc spacing. Deliberately conservative: # only unambiguous starts, so a genuine hole is never explained away. @@ -71,14 +75,16 @@ # A bracketed attribute list or a block title. Both attach to the block BELOW them, # so neither answers the question "is a listing here". ATTRIBUTE_LINE_RE = re.compile( - r'^\[(?!(?:' + "NOTE|TIP|IMPORTANT|WARNING|CAUTION" + r')[,\]])[a-zA-Z%.#"][^\]]*\]\s*$' + r'^(\[\[[^\]]+\]\]\s*$' # [[anchor]] + r'|\[(?!(?:' + "NOTE|TIP|IMPORTANT|WARNING|CAUTION" + r')[,\]])[a-zA-Z%.#"][^\]]*\]\s*$' + r'|\.[^.\s].*$)' # .Block title ) BLOCK_START_RE = re.compile( # The name may be followed by "]" or by further attributes, as in # [NOTE,caption="Aside"] -- requiring the bracket immediately made an # attributed admonition look like the listing the sentence promised. r'^(\[(?!(?:' + ADMONITION + r')[,\]])[a-zA-Z%.#"]' - r'|image::|include::|\|===|(----|\.\.\.\.|````|\+\+\+\+|====|\*\*\*\*|____)\s*$)' + r'|include::|\|===|(----|\.\.\.\.|````|\+\+\+\+|====|\*\*\*\*|____)\s*$)' ) diff --git a/scripts/developer-guide/missing-code-blocks-baseline.txt b/scripts/developer-guide/missing-code-blocks-baseline.txt index c0d517af65e..ff6cb31277f 100644 --- a/scripts/developer-guide/missing-code-blocks-baseline.txt +++ b/scripts/developer-guide/missing-code-blocks-baseline.txt @@ -104,6 +104,7 @@ Introduction.asciidoc Next consider the first lifecycle method `init(Object)`. T Introduction.asciidoc Now that you have a general sense of the lifecycle lets look at the last two lifecycle methods: Introduction.asciidoc The hello world Java source file looks like this (removed some comments and whitespace): Maps.asciidoc A native provider only renders on the platforms that ship its SDK. To show a provider's map *everywhere* -- including platforms with no native SDK for it -- register a `WebMapProvider`, which hosts the provider's JavaScript SDK inside a `BrowserComponent`: +Maps.asciidoc Because it needs only a web view, the web provider (id `web`) is the natural last step before the pure-vector fallback in a provider chain. The order is fully customizable from code, so you can express per-platform preferences -- for example "try the native Google SDK, then the web map, then the vector `MapView`": Maps.asciidoc Every map -- vector or native -- exposes the same operations through `MapSurface`: Maps.asciidoc For a real app you point `MapView` at a hosted tile service. The simplest keyless option is OpenFreeMap (OpenStreetMap-based vector tiles); for branded styles or higher quotas use a keyed provider such as MapTiler or your own self-hosted Protomaps/TileServer GL endpoint: Maps.asciidoc When a provider is selected the build server injects that provider's implementation into your app and wires it in; with no provider selected (or when the provider is unavailable at runtime, for example when Google Play Services is missing) `NativeMap` simply renders the vector `MapView` fallback. You can configure the fallback basemap explicitly: @@ -117,6 +118,7 @@ Miscellaneous-Features.asciidoc For example: you can copy the `Image` to `Storag Miscellaneous-Features.asciidoc However, it gets better, say you want to return a value: Miscellaneous-Features.asciidoc If you need to apply the scale manually for custom fonts or layout calculations, read the values directly: Miscellaneous-Features.asciidoc It allows formatting numbers/dates & time based on platform locale. It also provides a great deal of the information you need such as the language/locale information you need to pick the proper resource bundle: +Miscellaneous-Features.asciidoc Or, you can use the `Media`, `MediaManager` and `MediaRecorderBuilder` APIs to capture audio, as a more customizable approach than using the Capture API: Miscellaneous-Features.asciidoc The `Capture` API also includes a callback based API that uses the `ActionListener` interface to implement capture. For example: you can adapt the previous sample to use this API as such: Miscellaneous-Features.asciidoc The following code demonstrates usage of the GeoFence API: Miscellaneous-Features.asciidoc The list of available languages in the resource bundle could be retrieved like this. Notice that this a list that was set by you and doesn't need to confirm to the ISO language code standards: From 7c75a568bab14acef1cdcb73bb3e77e43846b15d Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Thu, 3 Sep 2026 02:17:16 +0300 Subject: [PATCH 48/51] A package directory has no index page, so it is not a destination javadoc writes package-summary.html and package-tree.html into a package directory and nothing else, so /javadoc/com/codename1/ui/ is a 404 however real the package is. Accepting any directory whose package existed was the last of the directory-shaped hatches. Only the tree root is a destination now: it does have an index, and build.sh moves that aside to render a Hugo page in its place. /javadoc/ accepted /javadoc/com/codename1/ui/package-summary.html accepted /javadoc/com/codename1/ui/Form.html accepted /javadoc/com/codename1/ui/ rejected /javadoc/com/codename1/Nope/ rejected Measuring this nearly went badly. `grep -o 'javadoc/[^ \[]*/'` reports 40 package directories, and every one is an artifact: the pattern matches the longest run ending in a slash, so a class link like .../capture/Capture.html contributes ".../capture/". Extracting whole URLs instead gives 418 page links and 5 directory links, and all five are /javadoc/ itself. I had a rewrite ready for those 40 -- it changed nothing only because its own pattern was stricter than the grep that found them. No guide content is touched here. Also worth recording from the same reading: JDK 25 puts javadoc's assets in resource-files/, not the resources/ and script-dir/ that a JDK 17 run produces. That is exactly why the previous commit rejects asset paths instead of listing them -- a list taken from the JDK to hand would have been wrong on arrival. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index 0c4f245ca0d..968ffb1609c 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -505,9 +505,13 @@ def javadoc_path_exists(target: str) -> bool: # package. Anything else names a directory the generator never creates -- # accepting every non-.html path let /javadoc/com/codename1/DefinitelyMissing/ # through on the strength of having no file extension. - if not path: - return True - return path in packages + # Only the tree root. A package directory has no index.html -- javadoc + # writes package-summary.html and package-tree.html and nothing else -- + # so /javadoc/com/codename1/ui/ is a 404 even though the package is real. + # The root does have one, and build.sh moves it aside to render a Hugo + # page in its place. The guide links to the root five times and to no + # package directory at all; a link to a package should name the summary. + return not path package = str(PurePosixPath(path).parent) page = PurePosixPath(path).name if package == ".": From b540251816813424fea18ce1fffb4e8d4b42b5cb Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Thu, 3 Sep 2026 02:25:20 +0300 Subject: [PATCH 49/51] An attribute hides a target whichever macro carries it, and reuse must agree The refusal for attribute-built targets recognised link:{...} only, so xref:{root}does-not-exist and slipped past it -- the same three spellings the root-relative extractor already had to learn one at a time. All three are refused now, from one pattern rather than three. xref:{root}does-not-exist[label] old 0 -> new 1 link:{root}does-not-exist[label] unchanged old 0 -> new 1 an ordinary URL new 0 And _visit() records the attributes of the FIRST inclusion and returns early on every later one, so a fragment brought in twice -- once with leveloffset=+1, once without -- was validated against whichever parent happened to come first, while its heading rendered at two different depths and one of them could be a part rather than a section. Attributes are collected per target now and a disagreement is reported, which is the same answer this checker gives everywhere else it cannot model two spellings of one thing. included twice with different leveloffsets old 0 -> new 1 included twice with the same attributes new 0 Neither construct is in the guide: no attribute-built target of any spelling, and no fragment with two parents at all. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 4 +++- .../developer-guide/check-guide-structure.py | 20 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index 968ffb1609c..e252a548edf 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -36,7 +36,9 @@ # measured: zero URL-valued attribute declarations and zero link:{...} targets. # So both spellings are refused instead, which keeps the gap from opening quietly. ATTRIBUTE_URL_DECL_RE = re.compile(r"^:[A-Za-z0-9_-]+:\s*https?://") -ATTRIBUTE_LINK_RE = re.compile(r"\blink:\{[^}]+\}") +ATTRIBUTE_LINK_RE = re.compile( + r"""(?:\blink:|\bxref:|\bhref\s*=\s*["']?)\{[^}]+\}""", re.IGNORECASE +) # An array parameter written raw ends the AsciiDoc link macro at the "[", so the # URL is cut mid-signature and the label is lost -- #createImage(byte[],int,int) # rendered as a bare link to "#createImage(byte". It has to be written %5B%5D. diff --git a/scripts/developer-guide/check-guide-structure.py b/scripts/developer-guide/check-guide-structure.py index 113815f83a1..6fe85d95f08 100755 --- a/scripts/developer-guide/check-guide-structure.py +++ b/scripts/developer-guide/check-guide-structure.py @@ -162,6 +162,7 @@ def __init__(self, root: Path, guide_dir: Path) -> None: # and two rendered titles and passed, because it only asks whether a # title appears AT LEAST as often as it is declared. self.include_edges: collections.Counter = collections.Counter() + self.include_attrs: dict[Path, set[str]] = {} self.errors: list[str] = [] self._visit(root, "") @@ -250,6 +251,14 @@ def _visit(self, path: Path, attrs_from_parent: str) -> None: ) else: self.include_edges[(path, target)] += 1 + # _visit() records the attributes of the FIRST inclusion and returns + # early on every later one, so a fragment brought in twice with + # different leveloffsets was validated against whichever came first -- + # and its heading renders at two different depths. Collected per + # target so the disagreement can be reported. + self.include_attrs.setdefault(target, set()).add( + " ".join(attrs.split()) + ) self._visit(target, attrs) @staticmethod @@ -460,6 +469,17 @@ def main() -> int: # nothing and the title check only asks for "at least once". Cross-parent reuse # stays legitimate for a FRAGMENT; a direct chapter is a different thing -- # it already has its place in the book. + for target, seen in sorted( + walker.include_attrs.items(), key=lambda item: item[0].name + ): + if len(seen) > 1: + spellings = ", ".join(repr(a) for a in sorted(seen)) + errors.append( + f"{target.name}: is included with different attributes ({spellings}), " + f"so its heading renders at more than one depth. Use the same " + f"attributes everywhere, or give each parent its own fragment." + ) + for target in sorted(walker.direct, key=lambda path: path.name): others = sorted( parent.name From abce72f96fdfe56672405a66284374af6d59c240 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Thu, 3 Sep 2026 02:34:14 +0300 Subject: [PATCH 50/51] javadoc drops an @hidden type, so the index should not hold one A public type tagged @hidden gets no page at all -- confirmed by generating docs for a two-class package where the tagged one produced no HTML. Two such types sit outside com.codename1.impl and were therefore in the index: com.codename1.vpn.tunnel.TunnelBuffers and TunnelHost, both public, both marked "@hidden not part of the public API". A link to either would have passed. The tag is read from the ORIGINAL source at the declaration's offset, because blank_java_noise has erased the comment by the time the declaration is located, and both comment styles occur in this tree -- /** */ and the /// markdown form these two use. TunnelBuffers, TunnelHost no longer indexed VpnTunnel, TunnelConfiguration still indexed 1845 public types -> 1843 423 guide links, 0 rejected Measuring this went wrong twice before it went right, both times in the throwaway script rather than in the checker. First it looked for /** */ only and reported zero, missing both files because they use ///. Then, with /// handled, it still missed TunnelBuffers: the declaration regex matched the word "public" inside the sentence "it is hidden rather than public API", and [^;{]* happily spanned the newlines to the real declaration below. That is precisely the hazard blank_java_noise exists for, and the measurement was not using it -- so the real implementation locates the declaration in the blanked text and reads the comment from the original. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/developer-guide/check-guide-links.py | 30 ++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/scripts/developer-guide/check-guide-links.py b/scripts/developer-guide/check-guide-links.py index e252a548edf..9782e320550 100755 --- a/scripts/developer-guide/check-guide-links.py +++ b/scripts/developer-guide/check-guide-links.py @@ -325,8 +325,34 @@ def is_public_type(source: Path, stem: str) -> bool: text = source.read_text(encoding="utf-8", errors="ignore") except OSError: return False - text = blank_java_noise(text) - return re.search(PUBLIC_TYPE_RE.format(stem=re.escape(stem)), text) is not None + blanked = blank_java_noise(text) + match = re.search(PUBLIC_TYPE_RE.format(stem=re.escape(stem)), blanked) + if match is None: + return False + # javadoc drops an element tagged @hidden entirely, so a public type carrying + # it gets no page. The tag lives in the doc comment, which blank_java_noise has + # just erased, so read it from the ORIGINAL text at the same offsets. Both + # comment styles occur here: /** */ and Java's /// markdown form, which is what + # com.codename1.vpn.tunnel.TunnelBuffers and TunnelHost use. + return "@hidden" not in doc_comment_before(text, match.start()) + + +def doc_comment_before(text: str, position: int) -> str: + """The doc comment attached to a declaration, in either comment style.""" + before = text[:position] + block = re.search(r"/\*\*((?:(?!\*/).)*)\*/\s*(?:@\w+(?:\([^)]*\))?\s*)*$", before, re.S) + if block is not None: + return block.group(1) + collected: list[str] = [] + for line in reversed(before.split("\n")): + stripped = line.strip() + if stripped.startswith("///"): + collected.append(stripped) + elif stripped == "" or stripped.startswith("@"): + continue + else: + break + return "\n".join(collected) def javadoc_index(repo_root: Path) -> tuple[set[str], set[str]]: From ce8307788d8aaf210d43a321693af27f2e20f982 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Thu, 3 Sep 2026 02:43:56 +0300 Subject: [PATCH 51/51] Paragraph text before an include swallows the heading after it The spacing rule guarded one side only: it asked what FOLLOWS an include and how the included file ends. Prose immediately BEFORE an include absorbs that file's first heading just as surely, and the rendered-title check cannot see it when another file shares the title -- "Getting started" is in this book three times, so losing one still leaves the count above the single expected occurrence. This is the finding I answered earlier by pointing at the cause-level rule, and I was wrong: that rule does not cover this shape. It does now, with the same exemptions, established the same way: prose, no blank line SWALLOWED prose, with leveloffset renders blank line before renders after a closed literal block renders directly after a heading renders directives between them SWALLOWED (they vanish; look past them) A/B against the real book, putting prose in front of the Maven-Getting-Started include: headings for "Getting started" 4 -> 3 (one swallowed) old gate passed new gate fails Only reported when the included file actually starts with a heading, which is what there is to lose. That exempts the one instance in the guide today: Advanced-Topics-Under-The-Hood puts ".Build hints" in front of _generated-build-hints.adoc, and that file opens with comments and a table, so nothing is absorbed. Co-Authored-By: Claude Opus 5 (1M context) --- .../developer-guide/check-guide-structure.py | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/scripts/developer-guide/check-guide-structure.py b/scripts/developer-guide/check-guide-structure.py index 6fe85d95f08..2db89e25dec 100755 --- a/scripts/developer-guide/check-guide-structure.py +++ b/scripts/developer-guide/check-guide-structure.py @@ -347,6 +347,40 @@ def _check_include_spacing( cursor = index + 1 while cursor < len(lines) and BLOCK_DIRECTIVE_RE.match(lines[cursor].strip()): cursor += 1 + # The same hazard on the other side: paragraph text immediately BEFORE the + # include absorbs the included file's first heading, and the rendered-title + # count cannot see it when another file happens to share that title -- + # "Getting started" is in the book three times. Measured, the exemptions + # are the same ones: a blank line, a line that closes the paragraph, or a + # leveloffset, whose attribute entry does the closing. + if "leveloffset" not in attrs: + back = index - 1 + while back >= 0 and re.match( + r"^(ifdef|ifndef|ifeval|endif)::", lines[back].strip() + ): + back -= 1 + preceding = lines[back].strip() if back >= 0 else "" + if preceding and not self._CLOSES_PARAGRAPH.match(preceding): + try: + first = next( + ( + line + for line in parse_lines(target) + if line.strip() + ), + "", + ) + except OSError: + first = "" + if HEADING_RE.match(first): + self.errors.append( + f"{path.name}:{index + 1}: include of {target_raw} follows a " + f"paragraph with no blank line between them, so that paragraph " + f"absorbs {target.name}'s heading and the section disappears. " + f"Add a blank line before the include, or a leveloffset " + f"attribute." + ) + following = lines[cursor] if cursor < len(lines) else "" if not following.strip(): return

lOPZfQMLG~QTQ7RAhW8ccdrRM~vi?Xfnlr4C*nOmfh z@sGbwMy6lm_pXIHGH@BrWPSHlDd(PcU|kvl2{XAly@b{3ja&ygI~TY;T#JSG0ltSN z**cB2%nE;%q&MtSuaH-uqO6$ARdp2;5Y2~mcqLpauY@ty|- z!@luHDVybyA&^}xcC#?~E0+pc`RtO~X_F}TZ}zZRF6>q+XKWSFY?OCRKj$uI&U+4w z5a(6wT>En7Z|g%mz#R*EyVsF)7jsXsfHqVeI24+oA0|boJ^5En+gZi@f3Qo4`KGnz z14P;KmjfBo9xVo=zwNXLd!TU&`gmAlqA#_9Z<4?>&Mt3sn`Ca=C8-3%;C&RY=E3KR` zx3dck*C*SGo$&mPiEv|Xt`HgWc;&F~vmFu;4lT`KVEny;pq74Fhg%*THynWsA!>9) zqrH$5C3cHXm~y7$2D(>-@x9GZOQK_BtNp>GxtYHI8#Hl@|q0sX13$dJe>k9T; zy;$Q?Um~+!X5d~vsHLkVW-Q($FveIXD8>ZLfm{4kZ$<0Zer-Qss=upw8rR3Rb0G+! z$RzL!#pe4drdFdUXYt47`h(!z*`rv+JgxhkRa*UMCZLp1&zfp4-EvANrOkrI6aWR( z{TOwLapro`Q(x8M0NJzudAdR3jNP~2PbayB% zOQ(W#cc<)90?X2k)Y7rQe)kEVdY{+#_y6y@?rX1m@11*g=EP^tIdf)4#`C^Iqea;xjKE%p zIBz6Gi#*}NU-AQcf5exOmDwNQtBrIcnm@OP?dlc!QFLPi*9`Ch6z?+PNtC%i)_MmA z49tN2yeqNbE0I~~;ul$*1P#RGp@OzV%+NL)iS)J=!+!hCG?hy1$Ij}7qHclucNIhI zRgM`qbw-Y|=dxF_D6AEekwL73>JxA4<4h)=RUbj}M!X5(q{#AF;?JGvqfl|ix8iZn zK00ytoB7H%-jNpyS-+-rx$d-<+F@k-cB1n{9!Sqcj%oJneCKa=IMa;f?$#hYfzwwHS4j;yy$`DeZfnM zM|!8y#_|Rx4{y(*Y2&7&u1VQqP9*MWKDhhE-v>nxW7uRM)FDm6LwD1!D>=-my@dk< zd3@|h=?Iw$XY6FS=%k;?m_q@NLmLd!+mk7l16TSElrh=^aZfCbFKkF8hcST*4nfJ8A@|? zSAg=8GGW8J^3lu+kJd>AFhsz2zz5HQ*MgA=y@^EJgKJzsw;inYQ>Qvw*o2(sn59`s`W#r^PAhq=9QM$J%+YI1tBU!=*4Y&oIO)Wa- z!-F?;Jk%&L5aT0$Zz9nIl3wDd3tf(O%8U&-Ov(Or-o5@Yk#!jKoR3#wlAqe<g<8zWL4c>OgR30Zo#`9 zx{MHmfM~XW+8~BydERapdOh8EmwU3wEu$3Z1INNSpUOs84H;7j8|+@{;nmw@=D={7 zKhf|9v-N&itVK-oZYQr2o9F*zWsyICz#WCTB^!#cjDCzvOOCshnUyd776kwwUcGHu z+a&RNnA!&`;~~lG&;NBDL3^*9U)2rXx$h|mO)2KHF5J!yY{CiYmlG$!K$ArgtGz{t z@o0ypiLQuLRh>j*HA0sZja{R~-N8WRf><42isU|Rm}n8|7A>O2RZ{OqH zcLk7oqxrkWV!V(;vl z*A1WOAE|dtMY@ypHSe{yeDp%oU#h7X+;J$;Zt*DAV9I1dJ9ch6iF_q;Tpj!G{}Lu@ zhEf%$kR0xZ;f_X^&g|WHtPZ|>qVqwH%w+A#`qq4`$L;wu-6V^d%&J^wfimc9wQyb= zM6?xEpj;8ZfZA)Og!YQfT7#zV8A;XiwQK8R#=_obq&f^JbTt3{Qo%ua4@xL4u5@}P zFJLG35mjg}EwA&%BHhnk_!i2^68gs$?n2YlQ(IM8<+FvI zvfVk2H7QXv$^U*i(&KMM;&SX>t~5MPYfuL~9j=&KENHe#DZ4r|cfFsN+VsHc1pom8 z354LzlCeK}ZGphH)PYC*7iRpzAyGFP{8Xmle8HDyg(N68s~KjR()2diuTyr5hV-Ey zUI`xE-L2r#myNpK;KTYP@zc8eFiaScmCdQx#FsnENSzkUfVT7+s=i*b3a+FYMbAGR zJ1BbHD~%Xm>7U3N`$<2MKVdQ8&wU(YPSdrpo3!Tk^srT9jjA)d`9P`jR+|L^YA$dP zf`D4ob$>=KNg8yN_u*rjmqxm{yEWP-kcV9FbSA4pA(CY^9z!!T^k-L0z3)A(o-qG+ zrqZCyMT#cm98Vi%Z!Z*nTEFogzH5BFc`fttWP2{5*60glr)RVVN43#nC9E|0^NXLg zM}X14U(&LKQMg1C10(_}(FmEsYrWh9t%=ZCHHEE&mBfCQ{ptJ6{{8ySVF$)kPL{jg z@H9%nj;EERlsqnNt1C>b&ue}vo=vf$CS3W(W{H}YIZUU=+h%K<%;xfEU$~)ml4{LQ z4PE;mREfyK&*VqBhaDu<;@=Yd7u5I-O)!YU6cR#cS|}6Iivgi&%+`Wehh19xDU|++ znOoJ~p=r@G$!rq=4#e8gr=&lvtzVR8a82+t*Mvbr-lK$-b$FD`oUHIeZ0~_uP*S8)m;u!?6<3SIu&#-5)$J#K#uew>#f!n*V?*@x8}`pn%OH%c{aN&Ka)Pa zbWxKWZuKp5tl%1tZO}vM{Ti+e)>?3RIzKrbVSes|K9D~1PZ>|Q_zSDpwyn5mH;tB} zuWUeL>2NB3khSPSI&^8e1OAbJsj*_zdUVh}T&Q*wam;r({i^9-(ff~w)rz-@UrCy` zU3h-aRv!d`>ZDtDU=nI>5u+|AW@T@JH(b)b^1MzvX~&u-{>&J~L0+=~dadu?w-bFw zu(q}}1R`>M8-DSk%0ccl&@P~rBrP0y1r?-=cY4&}QGc{jMF7--KOnOMgee1U6L z?#Ug69UC1^H3;dB1FHy`Lq^Lwc)iF0YCNvC`(Out=3|1J};MPfK()qX;(y?&|t4E))pMofcG0Kma zSt+h|ref1KfY-iGKG}ZbL7V^}KE_Nwa)oM58#|Xz(UYB01#@fohU`SW07!o?hFL8( zJau?}XN{rDvYvd8PA)kIZ>!gB#dlu@nj3g(+*CpRw(*F74^vO%$tDlLsr4drzc`NI zM0j0j0zy5XL7jbd0XrpT*P`T68Y?V^Lx%#m4a+w8jrT_=d$DPZdG2_p&}KC{1?D)h45F0y)kP6yJ~ z;;`G~+4RA-rPy)rmPM8862_{~osFlUIaA7Pye6xiw;E`YS;j;o-k*%AsZW&t1j`8N z_Tk0IJbz`S=-u;^1+@if)2s1~W*eDwh_U9^Yy)-$!45~tYdB2|AYwM;BAz&Ri@f;R z+Oy0Cd#!iDpIe7-%m-dq{@xuvlzm#qdMHeMUahYa@7@(*P@+BPyoD-;mqxM{O-W`G zHH4nXUrB6H|Jc!fM9q7OWtTQBc765(Wr`9V(O-eip8@54#8}B;yN@fp`AJDrY9%UG zux`z8RBK6A!xaB9o!Jp&pF-|)*zfp-CR#*^RC zmf4i>ml)ZjQ{hCpQkAXs#IPqT0#y@F>}BV@{?l&AA}0)UzQ8?96L>!9m;da1an3U8 z+O$njG4z}2uV$b>NObYJvm>3C>xdR8rIk4>`N<}RH`6!GZ!v#i=kK7%NQ-}=U>O6C za56qaT-q_;gwIz{rlS%Er0(q7?l6)q)x^BUcH??6NU)LVdlamU-n9_ihE`bb*RVon z!})UV0O;>-6`2O~yFvqU?Pi3)d2q;A0)u)mlF=Mmg*Kh}%�mXyAvpfG&K-@X!v% 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