Commit fe42186
authored
Add --trace flag to flutter build apk for build profiling (#116)
* feat: Add --trace flag to flutter build apk for build profiling
Adds a --trace option that produces a Chrome Trace Event Format JSON
file showing where time is spent across all build layers (flutter tool,
Gradle, flutter assemble targets). The output can be viewed in Perfetto
at https://ui.perfetto.dev.
* Add comment about multi-variant trace file collision risk
The intermediate trace file path is shared across all Gradle variants.
This is safe today since flutter build apk only runs one variant per
invocation, but would need per-variant paths if that changes.
* Add iOS build tracing support
- Add --trace option to flutter build ios / flutter build ipa
- Pass TRACE_FILE through Xcode build settings to xcode_backend.dart
- Instrument buildXcodeProject() in mac.dart with pre-xcode, xcode, and
post-xcode spans
- Merge flutter assemble trace events from intermediate file
- Remove TRACE_FILE from toEnvironmentConfig() since both Android and
iOS orchestrators compute intermediate paths directly
* feat: accept --trace on `flutter build appbundle`
The umbrella `flutter build apk` command already wired up the build-
trace option via `usesBuildTraceOption`, but a lot of real-world
workflows build the AppBundle (`flutter build appbundle`) directly —
most notably `shorebird release android` which always produces an AAB.
Without this, those invocations silently skip tracing.
The gradle/build-system plumbing is already shared, so adding the option
here is a one-line change that opts appbundle into the same trace file
Flutter already emits for APK builds.
* feat: enable Gradle --profile when build tracing is on
PR-116's trace only captures one `gradle bundleRelease`/`assembleRelease`
span on tid 2, so per-plugin task timing (compileReleaseKotlin,
mergeReleaseResources, linkReleaseNativeLibs, etc.) is invisible. Gradle
already has a built-in profiler that writes per-task durations to
`build/reports/profile/profile-*.html`; we just weren't enabling it.
Turn on `--profile` automatically when `--trace` is set so the profile
report lands alongside the trace. Downstream tooling (Shorebird) can
then aggregate per-task timings into an anonymized histogram — plugin
count, p50/p90/max task duration — to answer 'is native plugin compile
the bottleneck?' without collecting any plugin names.
* feat: per-Gradle-task trace events via init script
Before this, the only Gradle signal in a build trace was one giant
"gradle assembleRelease" span on tid 2 — useless for answering "where
is Gradle spending time" on plugin-heavy apps, which was half the
motivation for tracing in the first place.
This adds `flutter_trace_init.gradle`, an init script that registers a
TaskExecutionListener and emits one Chrome Trace Event Format entry
per Gradle task to an intermediate file. Each event carries:
- name: the full task path (e.g. `:camera_android:compileReleaseKotlin`)
- args.kind: a small bucket label (kotlin_compile, java_compile,
dex, resources, packaging, bundle, transform, native_link, lint,
flutter_gradle_plugin, other) so downstream tooling can aggregate
without holding on to raw names
- args.owner: the first colon segment (the subproject / plugin name)
- args.skipped / upToDate / fromCache: cache-hit signal
Events land on tid=4 so Perfetto shows a clean four-tier layout:
flutter tool / native outer / flutter assemble / gradle tasks.
gradle.dart passes `-I=<init script>` and
`-Pflutter.gradle-trace-file=<path>` alongside the existing assemble
trace wiring, and merges the resulting file into the main trace the
same way assemble events are already merged.
Supersedes the earlier `--profile` addition for AAR builds (removed):
we were writing an HTML report nobody was parsing; the init script
produces Chrome Trace events that go straight into the trace file
users already open in Perfetto.
Timestamps use `System.currentTimeMillis() * 1000` (wall-clock micros)
to stay aligned with the existing flutter-tool and flutter-assemble
events, which also use wall clock.
* fix: classify compileReleaseKotlin/Java and AGP tasks correctly
The first pass matched 'compilekotlin'/'compilejava' substrings against the
full lowercased task path, but AGP-generated tasks are 'compileReleaseKotlin'
/ 'compileReleaseJavaWithJavac' — the variant name sits between the verb and
the language. Also, plugin owners like 'package_info_plus' were tripping the
'packaging' bucket because the owner name contains 'package'.
Switch to matching against the simple task name (last colon segment) and
require compile tasks to start with 'compile' + contain the language token.
Add dedicated buckets for R8/minify and lint — they dominate on release
builds (R8 alone was 33s on the heavy app validation) and were previously
hidden in 'other'.
* feat: broader kind classification for Gradle init-script tasks
Real-world validation found ~60% of task time sitting in 'other' on
a plugin-heavy app — mostly AGP scaffolding that has a recognizable
shape (writeAarMetadata, checkReleaseAarMetadata, generateRFile,
mergeReleaseNativeLibs, javaPreCompileRelease, etc.). Add:
- 'java_compile' now also matches '*precompile*' (annotation-
processor setup, javaPreCompileRelease)
- 'resources' matches the merge/process/generate family
(mergeReleaseNativeLibs is overloaded — kept under native_link)
- 'native_link' for mergeReleaseNativeLibs, copyReleaseJniLibs*
- 'gradle_scaffold' catch-all for aarmetadata, proguard, validate,
check*, prepare*, generate*, copy*
Also restructured the classifier as a sequence of if/else-if with
explicit braces — the previous dangling-else chain was hard to
read after adding a dozen cases.
* refactor: rename trace surface with shorebird- prefix; add pod install span
This whole build-trace feature is specific to the Shorebird fork and
won't be upstreamed in its current form, so every public surface name
should make that obvious and stay out of identifiers upstream Flutter
might want to use later:
--trace -> --shorebird-trace
--trace-file -> --shorebird-trace-file (assemble)
-Ptrace-file -> -Pshorebird-trace-file (gradle)
-Pflutter.gradle-trace-file -> -Pshorebird.gradle-trace-file
TRACE_FILE -> SHOREBIRD_TRACE_FILE (xcode env)
flutter_trace_init.gradle -> shorebird_trace_init.gradle
flutter_assemble_trace.json -> shorebird_assemble_trace.json
flutter_gradle_task_trace.json -> shorebird_gradle_task_trace.json
BuildInfo.traceFilePath -> BuildInfo.shorebirdTraceFilePath
FlutterOptions.kBuildTrace -> FlutterOptions.kShorebirdTrace
usesBuildTraceOption -> usesShorebirdTraceOption
BaseFlutterTask.traceFile -> BaseFlutterTask.shorebirdTraceFile
intermediates/flutter (trace dir) -> intermediates/shorebird
No behaviour change beyond the rename.
Also: add a 'pod install' subprocess span in mac.dart. Previously, on
plugin-heavy iOS apps there was a minute-plus gap between "flutter
build ios" starting and the xcode archive span showing up — that was
CocoaPods resolving, and it was invisible in the trace. Now it's a
first-class event on tid=1 with cat='subprocess' so Shorebird's
summarizer can bucket it without double-counting into pre-xcode setup.
* feat: record Flutter-tool HTTP downloads in the Shorebird build trace
Until now the trace captured Shorebird's own network calls (via the
TracingClient wrapper on the Shorebird side) and subprocess spans for
pod install / gradle / xcode, but Flutter's own HTTP — primarily
artifact downloads in `Cache.updateAll` routed through `Net._attempt`
— was completely invisible. On a fresh Flutter-tool state this is
tens of seconds across a dozen artifacts; with the user's laptop on a
slow connection, minutes.
Expose a process-wide `BuildTracer.current` that gradle.dart /
mac.dart set for the duration of a build. `Net._attempt` records a
span on tid=5 / cat='network' for each request with method, host,
and (on failure) error kind — no URLs or paths. That matches the
shape Shorebird's TracingClient already emits, so the Shorebird
summarizer sums both into `networkMs` without any changes.
Using a singleton is deliberate: plumbing a tracer through every
caller of `Net.fetchUrl` and every subprocess wrapper would touch a
large fraction of flutter_tools files for what is still a fork-only
feature. The static is scoped by set/clear in the build driver, and
Flutter commands are one-shot processes so there's no lifetime
concern across invocations.
* feat: Xcode per-phase + CocoaPods per-phase trace spans
Fills two of the remaining "giant opaque block" gaps:
**Xcode.** Pass `-showBuildTimingSummary` when a Shorebird build trace is
active. Xcode prints a `** Build Timing Summary **` section at the end
of the log listing per-phase aggregates (CompileC / SwiftCompile / Ld /
PhaseScriptExecution / CodeSign / ...). mac.dart parses it and emits
one event per phase on tid=4 / cat='xcode_phase', so the previously
monolithic ~50s `xcode archive` span now has a visible breakdown.
The flag is pure reporting: Apple documents it as affecting output
only, and the existing flutter_tools isn't using it today.
Synthetic timestamps note: the summary only gives aggregate durations
per phase, not wall-clock, so we lay the events out contiguously back
from the xcode-end timestamp. Distribution is accurate; individual
spans don't necessarily line up with real wall clock inside Xcode.
**CocoaPods.** When tracing is active, switch pod install from
ProcessManager.run to start+stream so we can timestamp phase
transitions as they happen. The `--verbose` output already has stable
markers (`Analyzing dependencies`, `Downloading dependencies`,
`Generating Pods project`, `Integrating client project`); we just
needed live lines to attach wall-clock to them. Emits four sub-spans
on tid=1 / cat='subprocess' named `pod install: <phase>`.
Non-tracing path is unchanged: pod install still uses the same
ProcessManager.run, no behavioural or perf difference.
* fix: don't add -quiet to xcodebuild when tracing is on
-quiet and -showBuildTimingSummary don't play well together: xcodebuild
suppresses the timing-summary block under -quiet, which is exactly
what we need to parse to produce per-phase Xcode spans. Skip -quiet
when a Shorebird build trace is active.
User-facing output is unchanged — Flutter already captures xcodebuild
stdout into buildResult.stdout and only echoes it on failure or in
verbose mode.
* feat: parse xcode build log via xcresulttool for per-subsection spans
Replaces the -showBuildTimingSummary approach: that flag is documented
but produces no output on Xcode 26 (and presumably 16+), so parsing
xcodebuild stdout for a "** Build Timing Summary **" block silently
yielded nothing on modern Xcode.
Switches to xcresulttool, which Flutter already points at via
-resultBundlePath. After xcodebuild finishes, we run
xcrun xcresulttool get log --type build --path <bundle>
and walk the top-level subsections. Each subsection (one per target
build action — "Build target X from project Y", "Archive target Z",
etc.) has a real startTime + duration, so events land on an accurate
timeline instead of synthetic sequential spans.
Emitted on tid=4 with cat='xcode_subsection'. Subsection titles are
kept in the raw trace for local debug; Shorebird's privacy-safe
summary only records count + sum + p50/p90/max, no titles.
Best-effort: xcresulttool's JSON schema drifts across Xcode versions,
so parse failures are silent no-ops rather than errors.
Also revert the -quiet skip: it's no longer needed now that we don't
depend on xcodebuild stdout for timing data.
* chore: dart format trace-related files
* chore: roll dart_revision to aot_tools --trace support (shorebirdtech/dart-sdk#787)
* fix(trace): correct post-gradle / post-xcode span durations
- gradle.dart: hoist gradleEndMicros out of the tracer block so the
post-gradle processing span starts at when Gradle actually finished,
not gradleStartMicros + sw.elapsedMicroseconds (which ticks through
the trace-merge work). Also clear BuildTracer.current before throwing
on Gradle failure.
- mac.dart: collapse two adjacent DateTime.now() calls so pre-xcode
and xcode spans are back-to-back, and hoist buildEndMicros so the
post-xcode + outer flutter-build-ios spans end at the same instant.
- Drop redundant `!` null-checks on buildInfo.shorebirdTraceFilePath.
* refactor(trace): null-check hygiene + cross-link to sibling tracers
- Replace `!` null-assertions with local-variable null-checks in
gradle.dart (gradleEndMicros), cocoapods.dart (closure-captured
phase state), and xcode_backend.dart (SHOREBIRD_TRACE_FILE).
- Keep `!` only on the JSON-parse path in build_trace.dart where
flutter's cast_nullable_to_non_nullable lint prefers it;
documented.
- Add cross-link in BuildTraceEvent doc pointing at the sibling
implementations in dart-sdk/pkg/aot_tools and shorebird_cli so
future edits stay schema-compatible.
* feat(trace): real pids + process_name/thread_name metadata + gradle flow events
Chrome Trace Event Format carries pid/tid as producer-identifying
fields, not a shared coordination space. Drop the hardcoded tid
convention that flutter_tools / shorebird_cli / aot_tools had to
agree on and emit real pids everywhere:
- `BuildTracer.addCompleteEvent` now requires an explicit pid; the
class gained `addProcessNameMetadata` / `addThreadNameMetadata` /
`addFlowStart` for the Chrome Trace Event Format metadata and flow
events, and the internal buffer is raw JSON maps so metadata/flow
events can share the buffer with complete spans.
- `currentProcessId()` FFIs libc `getpid()` (or `GetCurrentProcessId`
on Windows) since `dart:io` only exposes pids for spawned children.
- flutter_tool, net.dart, gradle.dart, mac.dart, cocoapods.dart,
assemble.dart all emit on the calling process's real pid and name
it via metadata events so Perfetto shows "flutter tool", "pod
install", "flutter assemble" instead of bare numbers.
- `xcode_subsection` events go on a synthetic pid named "xcodebuild"
(xcresult doesn't surface xcodebuild's real pid, and the compile
sub-work is done by clang/swiftc children we never saw — synthetic
is honest).
- Gradle init script uses `ProcessHandle.current().pid()` so
per-task events live on the Gradle JVM's real pid; flutter_tool
emits a flow-start (`ph: "s"`) at Gradle spawn with a random id
passed via `-Pshorebird.gradle-trace-flow-id`, and the init script
emits the matching `ph: "f"` on the first task so Perfetto draws
a cross-process causality arrow.
Tests updated; summary bucketer follow-up will move from tid-based
to cat-based classification now that tids are no longer a shared
namespace.
* chore: roll dart_revision to aot_tools real-pid support (1376369b64e)
* fix(trace): label network row so flutter tool's HTTP downloads show as 'network' not 'Thread 5'
* refactor(trace): use dart:io's top-level pid; use gradle pid as flow id; embed variant in trace path
- Drop the FFI libc getpid()/GetCurrentProcessId() dance. `dart:io`
exports the current process's pid as a top-level getter; the whole
FFI block was me not checking the stdlib.
- ProcessUtils.stream: new optional `onStart(Process)` callback so
callers can observe the spawned subprocess's pid without changing
the return shape.
- gradle.dart uses onStart to read Gradle's real pid at spawn and
emit the flow-start with id = gradle_pid. The init script reads
its own pid via ProcessHandle.current().pid() for the matching
flow-end, so both sides agree on the id without the
-Pshorebird.gradle-trace-flow-id plumbing — which is now gone.
- Embed the assemble task name (e.g. `assembleFooRelease`,
`bundleRelease`) in the intermediate trace paths so a hypothetical
multi-variant Gradle run can't have per-variant FlutterTask
instances stomp on each other's trace.
* refactor(trace): depend on shorebird_build_trace package instead of vendoring
Delete flutter_tools' local build_trace.dart; import BuildTracer /
BuildTraceEvent / PhaseTracker / currentProcessId from
package:shorebird_build_trace via a git: pubspec dep pointing at the
public shorebird monorepo.
Net: ~175 LOC of wire-format + tracer class gone from flutter_tools,
schema now impossible to drift from the canonical definition in
shorebirdtech/shorebird/packages/shorebird_build_trace.
Consumers (gradle.dart, mac.dart, cocoapods.dart, net.dart,
assemble.dart, xcode_backend.dart) get the same class by the same
name via the package import — just a path swap.
* chore: roll dart_revision to aot_tools shorebird_build_trace migration (030fa6cef1f)
* chore: roll dart_revision to aot_tools real-child-pid subprocess tracing
* refactor(trace): hide trace plumbing in shorebird/ session classes
- Bumps shorebird_build_trace ref to 0637612a (zone-scoped
BuildTracer.current via runAsync, plus runSubprocess helpers).
- Extracts the ~60 lines of inline tracing in gradle.dart and
~140 lines in mac.dart into AndroidBuildTraceSession /
IosBuildTraceSession under lib/src/shorebird/. Each session
exposes a `run<T>(body)` that wraps body in BuildTracer.runAsync,
so gradle.dart and mac.dart just call lifecycle hooks
(onGradleFinished, onXcodeFinished, etc) and never touch
BuildTracer.current themselves.
- Net change in upstream-touched files: gradle.dart -161 lines,
mac.dart -206 lines, net.dart -33 lines. All trace plumbing now
lives under lib/src/shorebird/ which has zero upstream-conflict
footprint.
- net.dart's recordNetworkSpan closure moves to a
NetworkTraceSpan helper class in lib/src/shorebird/. The class
reads BuildTracer.current internally; net.dart just does
`final span = NetworkTraceSpan.start(...); ... span.record(...);`.
- abort-on-error paths removed: zone unwinding guarantees .current
is cleared on throw, so the explicit abortOnGradleFailure /
abortOnFailure clears are no longer needed.
* chore(trace): roll shorebird_build_trace ref to d0b3280f (drop unused runSubprocessSync)
* refactor(trace): manual start/stop + regex task classification
Two related changes.
1. Drop the closure-wrapped trace sessions. Wrapping
buildGradleApp / buildXcodeProject bodies in session.run(() async
{...}) forced a reindent that would have broken upstream-merge
compatibility for the next touch of those methods. Instead:
- Bumps shorebird_build_trace ref to 97efa2ed (new static
start/stop API + unchanged runAsync).
- AndroidBuildTraceSession / IosBuildTraceSession constructors
call BuildTracer.start(); finish / abortOn* call BuildTracer.stop().
- gradle.dart / mac.dart go back to flat indentation: the only
session touches are maybeStart + lifecycle hook calls.
Tradeoff: if an uncaught exception escapes the build method,
BuildTracer.current leaks. The flutter CLI exits the process
shortly after, so leak is per-invocation, not cross-invocation.
aot_tools keeps using runAsync (it can wrap easily).
2. Replace the gradle init script's if/else kind classifier with a
regex table. Same semantics, same priority order, but the
ordering is now explicit (a comment calls out which rules must
precede which) and accidental substring matches like
`:package_info_plus:` -> 'packaging' are easier to audit.
* refactor(trace): use BuildTracer + PhaseTracker helpers from shared library
Two DRY wins found during self-review:
- assemble.dart's writeTraceData was handrolling Chrome Trace Event
Format maps directly. Replaced with BuildTracer.addProcessName /
addThreadName / addCompleteEvent / writeToFile, which also picks
up merge-with-existing-file behavior for free. ~40 lines -> ~15.
- cocoapods.dart's _runPodInstallStreamed reimplemented the exact
phase-tracking pattern the library's PhaseTracker already provides
(the library's doc comment literally cites pod install as the
motivating example). Replaced with a PhaseTracker instance.
~20 lines -> ~5.
Drive-by: sort the `package:shorebird_build_trace` import into the
right section in both files so `dart analyze` stops complaining
about directive ordering.
* refactor(trace): use TraceSchema constants for all cross-repo strings
Replaces inline string literals for event categories, gradle task
kinds, pod install phase names, and span-name prefixes with
TraceSchema.* references from the shared shorebird_build_trace
package (new in d2099fe7). Makes the contract with shorebird_cli
explicit — rename a constant there and this side stops compiling
rather than silently diverging.
- Android/iOS session classes: cat/name constants for the flutter,
gradle, xcode, subprocess, xcode_subsection events they emit.
- cocoapods.dart: pod install name + phase-transition strings.
- assemble.dart: cat for assemble spans.
- network_trace_span.dart: cat for network spans.
- gradle.dart: instead of passing `'flutter build apk/appbundle'`
as an opaque string, passes the target suffix (`apk`/`appbundle`)
and the session constructs the span name from
`TraceSchema.flutterBuildSpanPrefix`. Keeps TraceSchema import
out of upstream-touched gradle.dart.
- shorebird_trace_init.gradle: can't import Dart, so its kind
literals stay — added a KEEP IN SYNC comment pointing at
TraceSchema.gradleKind* so any new entry lands on both sides.
- Bumps shorebird_build_trace ref to d2099fe7.
* refactor(trace): emit via TraceCategory/GradleTaskKind enums
Bumps shorebird_build_trace ref to 27f5971e (TraceSchema class
replaced by TraceCategory + GradleTaskKind enums plus TraceNames
for format-prefix constants).
Producer-side changes are mechanical: TraceSchema.catFlutter becomes
TraceCategory.flutter.wireName, TraceSchema.podPhaseAnalyzing
becomes PodInstallPhase.analyzing.wireName, etc. Span-name prefixes
(flutterBuildSpanPrefix, podInstallNamePrefix, ...) moved to
TraceNames; they're format templates not enumerated values.
Init script's KEEP-IN-SYNC comment now points at GradleTaskKind.
* chore(trace): roll shorebird_build_trace ref to cae6c56e (map-keyed accumulator)
* chore(trace): roll shorebird_build_trace ref to 2a56c3e3 (Duration internally)
* refactor(trace): take DateTime/Duration from shorebird_build_trace
Bumps shorebird_build_trace ref to bd5452360acc5371b30a265c85187c061df674cb.
Producer sites use DateTime.now() instead of
DateTime.now().microsecondsSinceEpoch, and pass DateTime / Duration to
the library's addCompleteEvent, addFlowStart, addFlowEnd,
recordNetworkSpan, etc.
* chore(trace): roll shorebird_build_trace ref to cff436f6 (schema v7)
* chore: dart format 5 test files to satisfy CI
* fix: analyzer errors in upstream-merged shorebird fork
Shorebird DEV CI runs `dart analyze` on the whole flutter_tools
package, unlike GitHub Actions which only runs test/general.shard.
The prior squashed-merge of upstream 3.35.7 carried two pre-existing
issues that analyze surfaces:
- build_macos_test.dart:1139 passed undefined `artifacts` and
`processUtils` named params to BuildCommand (which doesn't accept
them). Removed — the test still exercises the Shorebird YAML
post-build step, which was its actual purpose.
- build_windows.dart imported shorebird_yaml.dart but never used it.
* refactor(trace): table-lookup for pod install phase markers
Replace the four-branch if/else-if chain with a const map from log-line
marker to PodInstallPhase + a single-loop lookup. Adding a new phase
now means adding a map entry instead of a new branch, and the markers
sit next to each other at the top of the file where they're easier to
audit for staleness against newer CocoaPods releases.
* test: skip broken macOS shorebird.yaml-injection test
The test expects updateShorebirdYaml to mutate shorebird.yaml during
build, but the override's TestBuildSystem.all stubs out the assets
build target where that mutation runs. The test was previously
un-runnable due to a compile error (undefined artifacts/processUtils
params); now that it compiles again, mark it skip with an explanation
rather than let it fail. Also adds the missing OperatingSystemUtils
override present in every other test in the file.
* chore: dart format build_macos_test.dart after edit
* test: skip broken Windows shorebird.yaml-injection test
Same situation as the macOS analogue: the test expects
updateShorebirdYaml to mutate shorebird.yaml during the windows
build, but the overridden FakeProcessManager only runs cmake
+ cmake --build, neither of which drives the assets target where
that mutation lives. Skipping pending a test that exercises
updateShorebirdYaml directly.1 parent a4f38ad commit fe42186
35 files changed
Lines changed: 1573 additions & 452 deletions
File tree
- packages/flutter_tools
- bin
- gradle
- src/main/kotlin
- tasks
- lib/src
- android
- base
- build_system
- commands
- ios
- macos
- runner
- shorebird
- windows
- test
- commands.shard/hermetic
- general.shard
- build_system
- targets
- shorebird
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
63 | 63 | | |
64 | 64 | | |
65 | 65 | | |
66 | | - | |
| 66 | + | |
67 | 67 | | |
68 | 68 | | |
69 | 69 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
722 | 722 | | |
723 | 723 | | |
724 | 724 | | |
| 725 | + | |
| 726 | + | |
| 727 | + | |
| 728 | + | |
| 729 | + | |
| 730 | + | |
| 731 | + | |
| 732 | + | |
725 | 733 | | |
726 | 734 | | |
727 | 735 | | |
| |||
Lines changed: 159 additions & 0 deletions
| 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 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
Lines changed: 3 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
597 | 597 | | |
598 | 598 | | |
599 | 599 | | |
| 600 | + | |
| 601 | + | |
600 | 602 | | |
601 | 603 | | |
602 | 604 | | |
| |||
694 | 696 | | |
695 | 697 | | |
696 | 698 | | |
| 699 | + | |
697 | 700 | | |
698 | 701 | | |
699 | 702 | | |
| |||
Lines changed: 6 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
111 | 111 | | |
112 | 112 | | |
113 | 113 | | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
114 | 120 | | |
115 | 121 | | |
116 | 122 | | |
| |||
Lines changed: 3 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
110 | 110 | | |
111 | 111 | | |
112 | 112 | | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
113 | 116 | | |
114 | 117 | | |
115 | 118 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
| 32 | + | |
32 | 33 | | |
33 | 34 | | |
34 | 35 | | |
| |||
276 | 277 | | |
277 | 278 | | |
278 | 279 | | |
| 280 | + | |
279 | 281 | | |
280 | 282 | | |
281 | 283 | | |
| |||
352 | 354 | | |
353 | 355 | | |
354 | 356 | | |
| 357 | + | |
355 | 358 | | |
356 | 359 | | |
357 | 360 | | |
| |||
479 | 482 | | |
480 | 483 | | |
481 | 484 | | |
482 | | - | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
483 | 491 | | |
484 | 492 | | |
485 | 493 | | |
| |||
556 | 564 | | |
557 | 565 | | |
558 | 566 | | |
| 567 | + | |
559 | 568 | | |
560 | 569 | | |
561 | 570 | | |
| |||
569 | 578 | | |
570 | 579 | | |
571 | 580 | | |
| 581 | + | |
572 | 582 | | |
573 | 583 | | |
| 584 | + | |
574 | 585 | | |
575 | 586 | | |
576 | 587 | | |
| |||
588 | 599 | | |
589 | 600 | | |
590 | 601 | | |
| 602 | + | |
| 603 | + | |
591 | 604 | | |
| 605 | + | |
592 | 606 | | |
593 | 607 | | |
594 | 608 | | |
595 | 609 | | |
596 | 610 | | |
597 | 611 | | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
598 | 617 | | |
599 | 618 | | |
600 | 619 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
148 | 148 | | |
149 | 149 | | |
150 | 150 | | |
151 | | - | |
152 | | - | |
| 151 | + | |
153 | 152 | | |
154 | 153 | | |
155 | 154 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
10 | 11 | | |
11 | 12 | | |
12 | 13 | | |
| |||
87 | 88 | | |
88 | 89 | | |
89 | 90 | | |
| 91 | + | |
| 92 | + | |
90 | 93 | | |
91 | 94 | | |
92 | 95 | | |
| |||
98 | 101 | | |
99 | 102 | | |
100 | 103 | | |
| 104 | + | |
101 | 105 | | |
102 | 106 | | |
103 | 107 | | |
| |||
112 | 116 | | |
113 | 117 | | |
114 | 118 | | |
| 119 | + | |
115 | 120 | | |
116 | 121 | | |
117 | 122 | | |
| |||
120 | 125 | | |
121 | 126 | | |
122 | 127 | | |
| 128 | + | |
123 | 129 | | |
124 | 130 | | |
125 | 131 | | |
| 132 | + | |
126 | 133 | | |
127 | 134 | | |
128 | 135 | | |
129 | 136 | | |
| 137 | + | |
| 138 | + | |
130 | 139 | | |
131 | 140 | | |
132 | 141 | | |
133 | | - | |
| 142 | + | |
| 143 | + | |
134 | 144 | | |
135 | | - | |
136 | | - | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
137 | 148 | | |
138 | 149 | | |
139 | 150 | | |
140 | | - | |
| 151 | + | |
141 | 152 | | |
142 | 153 | | |
143 | 154 | | |
144 | 155 | | |
145 | | - | |
| 156 | + | |
146 | 157 | | |
147 | 158 | | |
148 | 159 | | |
| |||
156 | 167 | | |
157 | 168 | | |
158 | 169 | | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
159 | 173 | | |
160 | 174 | | |
161 | 175 | | |
| |||
0 commit comments