Repository navigation
Commit 3d875d2
authored
Tae conversion gates (#440)
* efftriage: map a failed run to the gotcha that explains it (MTE-5827)
HARNESS-GOTCHAS is at 57 entries and CONVERSION-LESSONS ~40. Nobody recalls that mid-debug,
so the same failures get re-derived on device at 1-2 cycles each with the answer already
written down. This reads what the loop already produced and names the likely cause, citing
the gotcha id to go read.
Read-only — it never touches the tree or the device, so it can be run on every failure
without risk. It also encodes the two triage rules people get wrong: scan the FIRST
attempt (later attempts die on leftover state, somewhere later and more confusingly), and
treat status.json as authoritative for pass/fail while the trace explains why.
Eleven rules, all keyed to patterns from real runs: T0 absence assertion that can never
come true (selector matching another surface), T1 arrival check satisfied behind an
overlay, T2 clickAndSync reporting a landed click as failed, T3 mozEnterText's
non-asserting locate, T4 ambiguous Compose match reported as not-found, T5 system overlay
masking as absence, T6 long press behaving as a tap, T7 stale PageStateTracker routing
through a destructive edge, T8 merged-vs-unmerged text miss, T9 arrival timeout, T10 crash
rather than assertion failure.
Hardened against 8 labelled failures from the search batch, each with a cause established
by hand on device: b4/b6-privhist -> A39, b9b -> A40, b13 -> A3/A42, b14d -> A42,
b17b -> A39, b17e -> A22, b10-searchclass -> A37. All 8 now match. Three defects were
found and fixed during that exercise, which is the argument for keeping the corpus:
- it confidently mis-diagnosed b14d as an arrival timeout, because the absence-assertion
rule was keyed to the thrown-exception wording rather than the phrasing the trace
actually logs, and the arrival rule matched the harmless pre-check every navigateToPage
emits. A confidently wrong triage is worse than none.
- a crash was reported as a footnote, so the one failure mode that also fools effverify
printed "no rule matched".
- it counted one "Started try #1" block per test as a retry, marking every passing class
run as retried — the exact mistake CONVERSION-LESSONS warns about.
* Stamp the toolchain: VERSION, CHANGELOG, and --version on every tool (MTE-5770)
Tools and docs are versioned together, since they cite each other by gotcha/lesson id and a
split version would only create skew. CalVer rather than semver: these are internal scripts
read from a checkout, nobody pins them, and the only question anyone asks is "is my copy
older than the thing being discussed".
- VERSION at the tae-conversion root, currently 2026.08.13.
- CHANGELOG.md, curated rather than a commit log: entries are changes a consumer depends on
(a new gate, changed verdict semantics, changed flags), each citing its gotcha ids and Jira
keys so "when did this gate appear" is answerable.
- --version on all 12 tools (10 python, 2 shell), handled before any other arg parsing.
The version lookup deliberately resolves symlinks. These tools are routinely invoked through
another checkout's tools/ dir, where the eff* entries are symlinks into this repo; an
unresolved path would look for VERSION in the wrong repo and report "unknown" in exactly the
situation a staleness check exists for. That symlink layout is also how MTE-5764 stayed
invisible to us while being broken for everyone else, which is the argument for the stamp.
Verified: all 12 tools print a version, and effnext/effverify/efftriage/effcheck/effloop.sh
still behave normally (effloop's no-arg exit 1 is the pre-existing ${1:?} behaviour).
* effdoctor slice 1: the toolchain map, so the queue stops drifting (MTE-5766)
The eff* tools exist once but are reachable from two checkouts — testops-tools/tae-conversion/tools
and ui-test-modernization/tools, where the entries are symlinks into the former. effwatch.sh
computes its queue from `dirname $0`, which does NOT resolve symlinks, so the queue it watches
is a function of the path it was launched from while the tools themselves are identical either
way. Drop a request in the other checkout's queue and it sits there forever: nothing consumes
it, nothing errors, and the run simply never happens.
That has bitten us more than once, most recently this batch, so this stops relying on anyone
remembering which checkout was used this time. effdoctor reads the live process list and prints
the queue to actually use.
Slice 1 checks, all read-only:
- the toolchain map: canonical tools + queue, and per live effwatch its pid, launch path and the
queue it is therefore watching, flagged canonical or not
- more than one effwatch running (two gradle builds on one device read as flakiness, MTE-5768)
- the alt checkout diverging: an eff* entry that is a SEPARATE copy rather than a symlink, or
missing entirely — which is how a tool silently ages out of one checkout
- effpretty resolvable under $REPO (MTE-5764 / gotcha A24)
- a stale mach_android.lockfile with no process holding it (gotcha A38)
- an adb device present
Exit 1 on anything needing attention, so it can gate the start of a session.
Run against the live setup it immediately reported both real problems: effwatch was launched from
ui-test-modernization so the canonical queue was the wrong place to queue (the exact failure from
earlier today), and effdoctor/efftriage were missing from the alt checkout. The latter is now
symlinked, and resolves to the right VERSION through the symlink, which is what the realpath-based
version lookup exists for.
* effdoctor: resolve the watched queue against effwatch's cwd, not ours (MTE-5766)
Its first live run misdiagnosed the very thing it exists to prevent. effwatch had been launched as
`./tae-conversion/tools/effwatch.sh`, and the relative path was resolved with os.path.abspath — i.e.
against effdoctor's cwd. Run from the firefox repo, it reported the live queue as
firefox/tae-conversion/conversion-runs/_queue, a directory that has never existed, and advised
queueing into it. A request dropped there is never consumed and never errors, which is the exact
failure mode this tool was written to catch.
Read the watcher's own cwd via lsof and resolve against that, so the answer no longer depends on
where effdoctor was invoked from. Absolute launch paths are used as-is.
Two guards for the class rather than the instance: a computed queue that is not a directory on disk
is a FAIL, and a watcher whose cwd cannot be read is reported as undetermined with the lsof command
to run. Both refuse to name a path instead of naming a wrong one, since a confidently wrong answer
sends the reader somewhere silent.
Verified: correct and identical from two different cwds, and the FAIL and multi-watcher paths
exercised with a decoy watcher whose computed queue does not exist.
* Unit-test the conversion toolchain, and fix the four defects that found (MTE-5766, MTE-5827)
The toolchain had no tests. Its verdicts are what we decide "done" on, and the way we checked them
was to run a tool, read its output, and judge whether it looked right — which is how two confidently
wrong diagnoses survived review. Both were in the gates written to prevent exactly that.
44 tests, stdlib unittest, no device or Firefox checkout needed: ps/lsof/adb/git are stubbed and the
edge cases build synthetic batch dirs. The efftriage rule tests instead run against REAL labelled
conversion runs, now checked in under tests/fixtures/corpus with a labels.json manifest. That
distinction is the point: hand-written traces only exercise the shapes their author imagined, so they
go green while the tool mismatches real output — a false green in the suite meant to prevent false
greens. The corpus also existed only as batch dirs in one person's conversion-runs/, unversioned and
impossible to run in CI, which is a poor home for the campaign's main diagnostic asset.
Four defects, three of them in code already reviewed by eye and pronounced fine:
- efftriage diagnosed GREEN runs. Traces normally carry non-fatal [ERR] lines (nav-graph polling,
tolerated absence checks) and the rules scanned them whatever the outcome, so a passing run was
reported as an absence-assertion failure. Two labelled runs in our own corpus were affected. Still
triaged on purpose: a retry-pass, where attempt 1 did fail and clean=false means flaky-not-done,
and a crash, since crash mode is where `outcome: pass` is itself the lie (MTE-5822).
- efftriage blamed the harness for a typo: a nonexistent batch dir came back as gotcha A24, sending
the reader to check effpretty resolution and pull dumps off a device. It also tracebacked.
- effdoctor named the wrong queue — the failure it exists to prevent. effwatch is launched by a
relative path, resolved with abspath against effdoctor's cwd instead of the watcher's, so from a
Firefox checkout it reported a queue under firefox/tae-conversion/ that has never existed and told
us to use it. Requests there are never consumed and never error. Now reads the watcher's own cwd
(/proc, then lsof); a computed queue that is not on disk is a FAIL and an unreadable cwd is
"undetermined", because declining to answer beats answering wrongly.
- effdoctor's self-exclusion skipped any ps line containing the substring "effdoctor", so a watcher
under a directory with that name was invisible. Unnoticed watchers are the whole point of the tool.
Recorded as known gaps rather than papered over: rules T3/T4/T5 have no labelled example in the
53-run corpus, so they are unvalidated rather than known-good, and 3 of 28 failures still get no
diagnosis. Both are asserted, so the lists cannot go stale in either direction.
* A skip is not a pass: fix the fifth false-green shape (A44, MTE-5827, MTE-5766)
Baselining a legacy test for batch 2 produced outcome=pass, failures=0 — for a test that never ran.
MainMenuTest.verifyTheMoreMainMenuSummarizePageButtonTest is @ignore'd on bug 2059592, so it skipped,
and effloop's verdict was `failures == 0 and tests > 0`, which a skip satisfies. efftriage then read
that outcome and said "run passed — nothing to triage". effverify was the only tool that got it right
(ok:false, passed:false), so the disagreement between them was the tell.
A skip asserts nothing, so it must never read as green:
- effloop now counts what actually ran: outcome=skipped when nothing did, partial when only some did,
both exiting 5 — a new code meaning "ran, but the verdict is incomplete", distinct from 1 (failed)
because the test did not fail, it never started.
- efftriage rule T11 diagnoses it from the per-test statuses rather than from `outcome`, since the
field that should have raised the alarm was the one lying. It names the gate candidates: an
Assume()/assumeTrue, an @ignore, a Nimbus flag, a pref, absent hardware.
- Documented as gotcha A44, with the standing instruction not to read failures:0 as success on its
own but to confirm results[].status == "pass" for every test expected to run.
Run over the existing corpus, T11 immediately found 2 silently SKIPPED tests (browserSearchBarItemsTest,
homeSearchBarItemsTest) inside an earlier 10-test run that nothing had ever reported — that run was
recorded as a plain failure of one other test. The labelled fixture keeps both shapes: the skip scored
as pass, and the mixed run.
Verified end-to-end on device, not just in unit tests: re-running the same @ignore'd test now yields
outcome=skipped with effloop_exit=5. Suite is 48 tests, green with ResourceWarnings as errors.
* efftriage: rules for a compile failure and a wrong-screen arrival check (T12, T13, A45)
Both found while converting the first batch-2 test, and both cases where the tool sent the reader
somewhere unhelpful.
T12 — a compile failure was answered with "no rule matched". status.json states compiled:false
outright, so there is never a reason to make someone hunt through a trace that was never produced.
It now names build-report.txt, where effloop already puts the Kotlin errors with file:line. This also
re-labels an existing fixture: b18-fxsuggest was recorded as an "empty report" case and drew the
misleading A24 advice (check effpretty resolution, pull dumps off the device) when it had simply
failed to compile.
T13 — the arrival check passed on the WRONG screen. Both requiredForPage anchors for a new Settings
sub-page also resolved on the parent Settings screen (the row carrying the destination's own title,
plus the ubiquitous Navigate up), so mozIsOnPageNow() reported arrival and navigateToPage skipped its
own click. Documented as gotcha A45, alongside A42 and the nav-graph gap it rhymes with.
T5 was tightened in the same pass. Its matcher keyed on "non-application window(s) present", but the
status bar is itself a SYSTEM window, so that warning is in nearly every dump and the rule fired on
almost any not-found. It answered the A45 case above with "a system overlay was over the app",
blaming the status bar — its first real firing was a false positive, which is exactly why it was
listed as unvalidated rather than known-good. It now requires that the app NOT hold focus.
T13's first draft keyed on "not found" and stole the diagnosis from six other rules; the corpus tests
caught that immediately. It is now narrowed to the group-level failure line and placed last so
anything more specific wins first — a reminder that a new rule's blast radius needs checking against
the whole corpus, not just the case that motivated it.
* docs: gotcha A46, a Compose toggle whose state is selected on the merged row
Cost a cycle on the never-translate conversion, and it is the reason legacy tests fall back to
positional UiSelector().index(n) for checked state: in the unmerged a11y tree the stateful row has no
text, content description or resource-id. Two traps stack — the Switch is blanked with
clearAndSetSemantics so no ToggleableState exists at all (assert selected, not checked), and the state
lives on the merging row, so COMPOSE_BY_TEXT resolves a stateless descendant.
Also records that a surviving testTag is not evidence of assertable state: RadioButtonListItem tags the
icon before the clearAndSetSemantics that strips selected/role/onClick.
* efftriage: rule T14 for a checked-state assertion on the wrong node (A46, MTE-5827)
The never-translate conversion's real failure — mozVerifyElementIsChecked against a node that carries
no state — came back as "no rule matched". It now names gotcha A46 and both halves of the fix: assert
`selected` rather than `checked`, and match on the MERGED tree. This is the shape behind every legacy
test that asserts checked state via positional UiSelector().index(n), so it will come up again.
The first draft over-matched. Keying on "' is (not )?checked" also hit the `[CMD] Verifying ... is
checked...` and `[OK] ... is checked` lines of runs that PASSED that assertion and failed for unrelated
reasons, and it silently stole the diagnosis from two labelled gap cases (a keyboard-close
PerformException and the ads-client NoHandle crash). The corpus tripwire caught it immediately — the
second time in this batch that a new rule's blast radius was wider than the case that motivated it, so
the matcher now requires the [ERR] marker.
Fixture keeps the run as labelled evidence, including the detail that it predates the ScreenDump those
verbs now emit, which is what made it opaque in the first place.
* changelog: correct the rule and test counts
Both were consumer-facing and stale: 11 rules -> 15 (T0-T14), 44 tests -> 48. Also notes that only 12
of the 15 are trace-matching entries in RULES, since T10/T11/T12 are status-based checks in triage() and
anyone counting RULES would otherwise think three were missing.
* effbug: let update post a comment, so a filed bug can be corrected (MTE-5763)
I filed a conversion bug with a TestRail id I had transcribed wrong. Comment 0 cannot be edited through
the Bugzilla API, and update only whitelisted summary/status/keywords/whiteboard/priority/severity plus
relations and assignee — so there was no way to annotate the bug at all, and the error would have stood
in a public bug indefinitely.
On create, `comment` remains the description; on update it is now a new comment. Blank is ignored rather
than posting an empty comment, and still counts as "nothing to change".
Adds effbug_tests.py, which stubs the one function that talks to Bugzilla and asserts what would be
sent. Worth pinning precisely because a wrong field writes to a public bug and there is no undo: it also
covers the existing rule that relations are wrapped as {"add": [...]} rather than sent as a bare list,
which would REPLACE the set and silently drop every other bug a meta bug tracks.
* efftriage: point at the in-tree screen-dump tool when a selector does not resolve (MTE-5827)
EffScreenDumpRunner already exists in ui/efficiency/devtools and does exactly what is needed when a
selector fails — an on-demand dump of a screen's live Compose tree, so selectors are authored against
ground truth rather than inferred from legacy robots whose locators are often stale. It is easy to miss.
Not knowing it was there, I spent several device cycles provoking failures with throwaway assertions
purely to obtain a dump.
efftriage now surfaces it, with the queue invocation, whenever the report contains a "not found", plus
the caveat from its own docstring: graph-navigable pages only, since a launch-reached page like
customTabs has no nav edge.
This is a discoverability fix rather than a new capability, which is the cheaper half of most tooling
problems here.
* efftriage: add a report-level rule tier, fix three rules that could never fire, and record A47-A53
Hardened live against the batch-2 conversions (MTE-5827, MTE-5831). Every change here came from a real failure
during those conversions, and each new rule has a labelled corpus fixture taken from the run that motivated it.
RULE DEFECTS FIXED. All three looked correct and could never fire, which is worse than a missing rule because
"no rule matched" at least sends you to read the report:
* T4 claimed to detect an AMBIGUOUS Compose match but its regex matched Compose's ZERO-match messages
("Expected exactly '1' node but could not find any node...", "Can't retrieve node at index '0'"). Those
appear in T1-arrival-timeout, T7-multi and T2-selector-surface, so had T4 ever been ordered earlier it would
have confidently misdiagnosed three labelled runs. Now requires "but found 'N' nodes" with N > 1.
* T14 matched only "is (not) checked", so following the advice in its own gotcha (A46: switch to
mozVerifyElementIsSelected) produced "is not selected" -- a message the rule could not see. The gotcha
silently stopped applying the moment you obeyed it. Now matches both state words, and its fix text covers
what to do when the failure is already "is not selected".
* T9's first branch expected "Navigation to 'X' failed", but the ordinary arrival failure throws "Failed to
navigate to X", which only ever lands in the FAILURES summary and never inside an [ERR] window. The branch
was dead. Removed rather than extended, and the case is now handled by T18 in the report tier.
NEW REPORT-LEVEL TIER. Rules in REPORT_RULES match against status.json's primary failure message instead of a
window of trace around an [ERR] line. This exists because some failures leave NO [ERR] line at all -- a crashed
instrumentation process produces an ~11-line report -- and others put the real exception outside the window
(failure_windows takes 25 lines after the [ERR]; the ads-client stack lands 36 lines later). Widening the
window was rejected: it drags stack text into unrelated windows, which is the same cross-contamination that
makes T6 and T9 fire on the wrong evidence today (filed as MTE-5832).
* T16 / A37 - the instrumentation process crashed; there is no assertion to read.
* T17 / K13 - a UniFFI fake built with NoHandle had an un-overridden method called. Recurs in 3 of 19 corpus
runs and can fail a test AFTER its assertions have passed. Deliberately NOT matched report-wide: the same
text appears as a Suppressed exception in T0-absence-assert and T9-permission, so a substring match would
steal both.
* T18 / A6+A45+B7 - the thrown form of an arrival failure, pointing at the anchor's STRATEGY first (an
ESPRESSO selector cannot see a Compose node, and Settings screens are routinely a View toolbar over Compose
content).
TEST GUARD FIXED. efftriage_tests.rule_ids() only inspected RULES, so the three new report-tier rules were
admitted with no labelled example -- exactly what that guard exists to prevent. It now covers both tiers. Three
fixtures added from real runs: T14-selected-not-checked, T15-external-app-blocked, T18-arrival-wrong-tree.
Corpus 19 -> 21 labelled runs; two long-standing known_gap runs are now diagnosed. Suite: 58 tests, green.
DOCS. HARNESS-GOTCHAS gains a "How to write an entry" convention, which is the most important change here.
Claims about the HARNESS generalise and may be stated plainly; claims about PRODUCT code must be scoped to the
file they were observed in, must say what to verify first, and should carry a counter-example. A46 asserted
that Compose toggle rows expose state as `selected`; that is true of ListItem.kt and false of
SearchEngineShortcuts.kt, and reading it as a law cost two cycles. A46 is rescoped accordingly, with its
counter-example named.
New entries: A47 (requiresScroll is inert for the singular mozVerify, and mozSwipeTo's direction default is
the opposite of the precondition path's), A48 (an external-app assertion blocked by a system dialog, and the
legacy twin that swallows its AssertionFailedError), A49 (a rule deliberately NOT mechanised, with the reason
recorded so it does not read as an oversight), A50 (the stylus prompt steals keystrokes and causes no locate
miss, so OverlayRegistry never fires), A51 (mozEnterText can leave a Compose field looking filled while the app
never saw it), A52 (a custom search engine survives a retry but MockWebServer's port does not), A53 (some
suggestion rows sit outside the Compose test tree -- read the right block of the dump).
Also: efftriage's header no longer hard-codes a gotcha count. It said "57" and was wrong twice, which is the
same failure mode the rules are meant to prevent. It now states the two standing rules instead -- match only
text OBSERVED in a real run, and prefer "no rule matched" to a confident mismatch.
* tae-conversion 2026.08.19: efftriage T19, effnext other-branch warning, gotchas A54-A59
Comes out of converting the seven site-permissions smoke tests (bugs 2064810/2064815/2064823/2064833).
efftriage gains rule T19 for "No navigation path found from X to Y", which it previously left unmatched
while its generic hint pointed at selectors and dumps - misleading, because that failure is a navigation
graph gap where nothing was searched for on screen. Labelled corpus fixture T19-no-nav-path is a real
run, so the rule is validated rather than listed as unvalidated.
effnext now warns when a pick is already converted on another local branch. Its in-tree filter only sees
the checked-out branch, so it offered CustomTabsTest.verifyLoginSaveInCustomTabTest, which has been
converted and awaiting review on efficiency-batch-2 since last week. Advisory rather than a filter, and
backup/* is excluded, because branches also carry abandoned work - the two faker conversions - and
filtering on any branch would silently drop outstanding tests from the pool.
That check shipped broken twice while being written, both times reporting a clean "nothing on other
branches" while checking nothing at all: git grep -E cannot parse \b or \s, and subprocess was never
imported so the NameError was swallowed by a bare except. Both paths now surface as branches_unchecked,
and tests/effnext_tests.py covers them.
HARNESS-GOTCHAS A54-A59 record what the device runs taught: option text is label plus subtext joined by a
newline; permission-screen res-ids are shared across screens and ESPRESSO_BY_ID ignores visibility;
BrowserPage has inbound edges only from HomePage and itself; a page-content text selector can resolve a
non-clickable heading, giving "found" then a failed click; a system app-permission row title is present
whether the permission is allowed or denied, so assert checkSelfPermission instead; and a page object
missing from PageContext never registers its navigation.
docs/SMOKE-CONVERSION-AUDIT.md is new: the standing burndown of remaining legacy @smoketest methods, what
blocks each, and the parser to reproduce the count.1 parent f02e082 commit 3d875d2
72 files changed
Lines changed: 12921 additions & 11 deletions
File tree
- .github/workflows
- tae-conversion
- docs
- tests
- fixtures/corpus
- T0-absence-assert
- T1-arrival-timeout
- T10-crash
- T13-arrival-wrong-screen
- T14-checked-wrong-node
- T14-selected-not-checked
- T15-external-app-blocked
- T18-arrival-wrong-tree
- T2-selector-surface
- T6-count-mismatch
- T7-multi
- T8-ad-surface
- T9-permission
- compile-failed-fxsuggest
- compile-failed
- gap-qrdialog-b17d
- gap-sponsored-b13d
- gap-sponsored-b14e
- pass-clean
- pass-with-nonfatal-errs
- skipped-scored-as-pass
- tools
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
51 | 51 | | |
52 | 52 | | |
53 | 53 | | |
| 54 | + | |
| 55 | + | |
54 | 56 | | |
55 | 57 | | |
56 | 58 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
483 | 483 | | |
484 | 484 | | |
485 | 485 | | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
0 commit comments