Commit 1130d2a
feat(compile): make on.pr a first-class trigger via synthetic CI-derived PR context (#922)
* feat(compile): add synthetic-from-ci front-matter knob to on.pr
Default true. Plumbs the schema through PrTriggerConfig with a serde-renamed field; existing struct-literal call sites use ..Default::default() for forward-compat.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat(compile): add build_pr_synth_spec for PR_SYNTH_SPEC env var
Serializes on.pr branches/paths to base64-encoded JSON consumed by the upcoming exec-context-pr-synth.js bundle. Mirrors GATE_SPEC encoding and adds an 8 KiB defence-in-depth cap.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat(scripts): scaffold exec-context-pr-synth ado-script bundle
Adds skeleton index.ts (no-op main) and match.ts (picomatch-based branch/path glob helpers with refs/heads/ and leading-slash normalisation). Wires the bundle into the npm build/clean/test:smoke chain and the release.yml ado-script.zip packager. Adds picomatch as a direct dependency so ncc bundles it deterministically.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat(scripts): implement exec-context-pr-synth runtime contract
Decodes PR_SYNTH_SPEC, no-ops on real PR builds and GitHub-typed repos, queries ADO REST for active PRs by sourceRefName, enforces exactly-one-match + target-branch filter + path filter, emits AW_SYNTHETIC_PR* outputs consumed by gate.js and exec-context-pr.js. Adds listActivePullRequestsBySourceRef to shared/ado-client.ts.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* test(scripts): vitest coverage for exec-context-pr-synth bundle
26 new tests across match.ts (glob normalisation + include/exclude semantics) and index.ts (real-PR no-op, GitHub no-op, spec decode errors, zero/multi-match skips, path filter rejection, happy path with all five AW_SYNTHETIC_PR* outputs). Adds an ESM entry-point guard to index.ts so importing main() does not trigger top-level process.exit.
Removes the source-branch pre-filter; pr.branches filters the TARGET ref per the issue spec, not the build source.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(gate): honour AW_SYNTHETIC_PR so synthetic PR builds skip the bypass
When the upstream synthPr Setup-job step has elected a CI build for PR treatment, the gate must run the full PR-spec predicates instead of auto-passing via the 'not a PullRequest build' bypass. Only PullRequest specs honour the override; PipelineCompletion specs are unaffected.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat(compile): emit synthPr Setup step when synthetic-from-ci active
Adds EXEC_CONTEXT_PR_SYNTH_PATH constant, synthetic_pr_active + pr_trigger_for_synth fields to AdoScriptExtension, synthetic_pr_step() generator, and wires collect_extensions to populate the flags from on.pr.synthetic-from-ci. Setup-job emits the synthPr step BEFORE prGate so downstream env coalescing can read the dependencies.Setup.outputs['synthPr.*'] values.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat(compile): coalesce real + synthetic PR env vars in gate and exec-context-pr
Extends compile_gate_step_external with a synthetic_pr_active flag. When true and ctx == PullRequest, ADO_PR_ID / ADO_SOURCE_BRANCH / ADO_TARGET_BRANCH are emitted as coalesce(variables.System.PullRequest.*, dependencies.Setup.outputs.synthPr.*) so the gate evaluator picks up either the real PR variables or the synthPr Setup-job outputs. Also exports AW_SYNTHETIC_PR so gate/bypass.ts can detect the synthetic-promotion case. PrContextContributor gains the same synthetic_pr_active flag and switches SYSTEM_PULLREQUEST_PULLREQUESTID + SYSTEM_PULLREQUEST_TARGETBRANCH to the coalesced form, with the step condition broadened to accept either real or synthetic PR. This also closes compile-exec-context-cond.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat(compile): update Agent-job dependsOn condition for synthetic PR
Extends generate_agentic_depends_on with a synthetic_pr_active flag. When true the condition gains a leading ne(synthPr.AW_SYNTHETIC_PR_SKIP, true) guard plus a broadened PR clause accepting real PR builds, synthPr promotion, or gate-passed. Threads the flag from compile_shared via front_matter.pr_trigger().synthetic_from_ci. Existing callers default to false (no behavioural change). Adds two unit tests.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat(compile): auto-emit narrowed CI trigger when synthetic-from-ci is on
When on.pr.synthetic-from-ci is on (default) and on.pr.branches.include is non-empty, emit a top-level trigger: block mirroring those branches so CI fires only on the configured set. Without this, ADO would queue a build for every push and most would be wasted compute (synthPr would skip them). Pipeline/schedule suppression still wins, synthetic-from-ci: false preserves the previous default, and an empty include list disables the narrowing. Five new unit tests.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* test(compile): snapshot fixtures for synthetic-from-ci default-on and opt-out
Adds two fixtures and two integration tests. Fixture A asserts the full synth wiring is emitted (synthPr step, PR_SYNTH_SPEC env, broadened exec-context-pr.js condition, AW_SYNTHETIC_PR_SKIP guard, narrowed trigger block). Fixture B asserts ALL synth artefacts are absent under synthetic-from-ci: false (substring-negation back-compat guard, no stored baseline needed). The GitHub-resource case planned as fixture C is omitted because it produces the same YAML as A; the runtime no-op is covered by the bundle's vitest suite.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs: document on.pr.synthetic-from-ci across front-matter and prompt files
front-matter.md gains the new knob in the example block and a 'PR Triggering in Azure Repos' section walking through why the feature exists, the 7-step runtime contract, the auto-narrowed CI trigger, and how to opt out. The three prompt files (create/update/debug) each cross-link to the new section with a one-paragraph note tailored to their context.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* style: cargo fmt on touched files
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(compile): drop synthetic-from-ci CI trigger narrowing
The narrowed trigger emitted by branch 2 of generate_ci_trigger used pr.branches.include as the trigger include list. Those are PR target branches (e.g. 'main'), but ADO trigger: fires on pushes TO listed branches, so narrowing to [main] suppressed CI on the feature branches synthPr actually needs to react to: a push to feature/x with an open PR feature/x -> main would never queue a build, defeating the entire synthetic-from-ci feature.
Remove branch 2 of generate_ci_trigger, the four narrowing-shape unit tests, and the narrowed-trigger assertion in test_synthetic_pr_default_emits_full_synth_wiring. Add a positive 'does not narrow' unit test, a negative integration assertion, and keep the pipeline-trigger priority test. Update docs/front-matter.md and prompts/create-ado-agentic-workflow.md to explain why narrowing is intentionally absent.
Cost concern from the original commit (a217df1) is addressed by the synthPr Setup step's existing fast-exit: a single listActivePullRequestsBySourceRef call returns [] for branches without a matching PR and the Agent job self-skips via AW_SYNTHETIC_PR_SKIP.
Addresses Rust PR Reviewer feedback on #922.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat(compile)!: replace synthetic-from-ci bool with on.pr.mode enum
Replaces the unshipped on.pr.synthetic-from-ci: true|false boolean with a two-value enum on.pr.mode: synthetic|policy (default synthetic). The two modes give the agent author a single coherent choice between the no-policy-required path and the operator-installed-branch-policy path.
Mode semantics:
* synthetic (default) — emit synthPr Setup-job step + downstream env coalescing + broadened conditions. CI trigger left at ADO default (all branches). Synth promotes CI builds with a matching open PR; non-matching CI builds self-skip cleanly via AW_SYNTHETIC_PR_SKIP. No Build Validation branch policy required.
* policy — omit all synth wiring AND emit rigger: none. Branch-policy-driven PR builds are the sole source of pipeline runs; feature-branch pushes no longer queue duplicate CI builds. Choose this when an operator has explicitly installed a Build Validation branch policy.
Previously, synthetic-from-ci: false omitted the synth wiring but did NOT suppress the CI trigger, so feature-branch pushes still queued CI builds that immediately bypassed the gate as 'not a PR build'. The new mode: policy closes that gap by emitting rigger: none, so every PR update fires exactly one PR-typed build.
Implementation:
* New PrMode { Synthetic, Policy } enum (Default = Synthetic) in src/compile/types.rs, replacing PrTriggerConfig.synthetic_from_ci: bool. PrTriggerConfig now derives Default.
* generate_ci_trigger gains a mode: policy → trigger: none branch after the existing pipeline/schedule suppression branch.
* All internal call sites (extensions/mod.rs, extensions/exec_context/mod.rs, common.rs::generate_agentic_depends_on derivation) replace p.synthetic_from_ci with matches!(p.mode, PrMode::Synthetic). The internal synthetic_pr_active: bool flag is preserved — it remains the right semantic abstraction.
* Fixtures: synthetic-pr-opt-out.md renamed to pr-mode-policy.md with mode: policy; synthetic-pr-default.md description cleaned (no longer references the removed narrowing). The policy fixture's integration test now asserts rigger: none is emitted.
* Unit tests rewritten around the two-mode contract: synth mode keeps the ADO default, policy mode emits trigger:none, pipeline-completion trigger still wins on priority. Schema tests cover all four cases (omitted, synthetic, policy, invalid value).
* Docs (front-matter.md), and prompts (create/update/debug) rewritten to present the two modes as a table and explain the policy mode's rigger: none emission.
No back-compat alias for synthetic-from-ci since the knob never shipped (still on the feature branch).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(compile): gate-step same-job synthPr ref and agent-condition gate enforcement
Addresses two real correctness bugs and one stale comment from the Rust
PR Reviewer feedback on #922.
(1) Gate-step same-job synthPr reference (filter_ir.rs::compile_gate_step_external):
The gate step is emitted into the Setup job (same job as `synthPr`),
so the env-block references `dependencies.Setup.outputs['synthPr.X']`
were silently wrong — that is cross-job syntax and resolves to null
inside the producing job, making `coalesce(...)` always return the
empty string. On synth-promoted CI builds this left
`AW_SYNTHETIC_PR=''`, so `gate/bypass.ts` took the "not a PR build"
auto-pass and the agent ran without `pr.filters` being evaluated at
all.
Fixed by switching the gate-step env coalesce to the same-job runtime
expression `variables['synthPr.X']`, which resolves step output
variables added to the producing job's variable scope. The Agent-job
env (in `exec_context/pr.rs`) keeps `dependencies.Setup.outputs[...]`
— that step runs cross-job where the dependencies form is the correct
one.
(2) Agent-job condition gate enforcement (common.rs::generate_agentic_depends_on):
With `mode: synthetic` + `pr.filters`, the synth branch emitted
`or(eq(Build.Reason, 'PullRequest'), eq(synthPr.AW_SYNTHETIC_PR,
'true'), eq(prGate.SHOULD_RUN, 'true'))`. The first two arms make
any PR build (real or synth) run the agent UNCONDITIONALLY —
silently bypassing the gate that `pr.filters` exists to enforce.
Replaced with `or(and(ne(Build.Reason, 'PullRequest'),
ne(synthPr.AW_SYNTHETIC_PR, 'true')), eq(prGate.SHOULD_RUN, 'true'))`
— non-PR / non-synth builds run unconditionally; real-PR and synth-PR
builds must pass the gate.
(3) Removed stale `compile-coalesce-env todo` comment in
`exec_context/pr.rs`; the work referenced is now implemented in the
same function.
Findings 2 and 3 from the same review were false alarms:
`$[ coalesce(...) ]` IS documented as valid in step-level `env:`
blocks, and `System.PullRequest.TargetBranch` is documented as the
full `refs/heads/<name>` form, matching `pr.targetRefName`. Both
clarified inline with MS-docs cross-references.
Test changes:
* `test_agentic_depends_on_synthetic_pr_active_emits_skip_guard_and_gate_enforced_pr_clause`
(renamed from `_and_broader_pr_clause`) — pins the new AND-NOT shape
and asserts the old permissive bypass arms are gone.
* `test_pr_filter_synth_mode_agent_condition_enforces_gate` —
integration test that exercises the `pr-filter-tier1-agent.md`
fixture (mode: synthetic + pr.filters) and asserts the Agent-job
dependsOn condition contains both AND-NOT arms and none of the
buggy bypass arms.
* `test_pr_filter_synth_mode_gate_step_uses_same_job_synth_ref` —
integration test asserting the gate-step env uses
`variables['synthPr.X']` (same-job) and contains no
`dependencies.Setup.outputs['synthPr.X']` cross-job references
inside the producing job.
* `test_synthetic_pr_default_emits_full_synth_wiring` — dropped the
misleading `eq(synthPr.AW_SYNTHETIC_PR, 'true')` assertion (the
fixture has no filters, so that string came from the
exec-context-pr step, not the Agent-job condition).
All `cargo test` (1811 lib + 131 compiler-integration + others) and
`cargo clippy --all-targets --all-features` pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: address Rust PR Reviewer feedback round 4 (#922)
Four findings from the latest review on this PR:
(1) `exec-context-pr-synth/index.ts` runtime-contract comment was
misleading: step 4 said `branches.include/exclude miss on
BUILD_SOURCEBRANCH → skip`, but the bundle never filters
`on.pr.branches` against the source branch (that would be wrong —
`on.pr.branches` lists PR *target* branches per ADO semantics). The
actual flow fetches PRs by `sourceRefName == BUILD_SOURCEBRANCH`,
then filters the matched PRs by their `targetRefName` against
`spec.branches`. Updated the contract comment to reflect this.
(2) `ado-client.ts` comment claimed "first page (200 PRs)" — ADO's
`getPullRequests` default page size without an explicit `$top` is
100, not 200. Updated to match the SDK default.
(3) `AdoScriptExtension` previously had two coupled fields
(`synthetic_pr_active: bool` + `pr_trigger_for_synth:
Option<PrTriggerConfig>`) whose pairing was enforced only by a
runtime `anyhow!` guard in `setup_steps`. Refactored to a single
field `pr_trigger_for_synth: Option<...>` whose `is_some()` IS the
activation predicate, exposed as `synthetic_pr_active()` for callers
that read it. The invariant is now unrepresentable-wrong at the type
level; the runtime guard is gone. Tests and `collect_extensions`
updated accordingly.
(4) Wrapped `$[ ... ]` runtime expressions in YAML double quotes in
the step `env:` blocks emitted by `filter_ir.rs::compile_gate_step_external`
and `exec_context/pr.rs::prepare_step`. The values contain single
quotes (`variables['System.PullRequest.X']`) and although ADO's YAML
parser accepts them unquoted in practice, double-quoting is the form
shown in ADO docs and is strictly conformant to the YAML spec (which
reserves `'` as a scalar indicator). Adjusted the corresponding
integration-test assertions to match.
Validation:
- `cargo build` clean
- `cargo test` (1811 lib + 131 compiler-integration + others) 0 failures
- `cargo clippy --all-targets --all-features` clean
- `npm test` in scripts/ado-script/ — 281/281 vitest passes
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: address Rust PR Reviewer round-5 suggestions (#922)
Three minor suggestions from the latest review.
(1) `ado-client.ts::listActivePullRequestsBySourceRef` — added `?? []`
guard on the SDK call. azure-devops-node-api's `getPullRequests` can
return `null` instead of `[]` on empty REST bodies; the bundle's
`.filter(...)` on the result would have thrown at runtime. Matches
the established pattern (`getIterationChanges` uses
`result.changeEntries ?? []`).
(2) `exec_context/pr.rs` — added a `#[cfg(test)] mod tests` block
with two targeted unit tests pinning the emitted YAML for
`PrContextContributor::prepare_step`:
* `prepare_step_synth_active_emits_coalesced_env_and_broadened_condition`
— asserts the synth-mode env coalesces (PR id + target branch,
YAML double-quoted runtime expressions) and the broadened
`or(eq(Build.Reason,'PullRequest'), eq(synthPr.AW_SYNTHETIC_PR,
'true'))` condition.
* `prepare_step_synth_inactive_emits_plain_macros_and_narrow_condition`
— asserts plain `$(System.PullRequest.*)` macros + narrow
`eq(Build.Reason,'PullRequest')` condition + defensive
"no synthPr references in synth-inactive output".
Previously these were only covered indirectly via the
`synthetic-pr-default.md` snapshot fixture.
(3) `types.rs::SanitizeConfigTrait for PrTriggerConfig` — added a
one-line comment explaining why `mode` is intentionally absent from
`sanitize_config_fields` (it's a `Copy` enum with no string content
and any malformed input is rejected at deserialisation).
Validation:
- `cargo build` clean
- `cargo test` 1813 lib + 131 compiler-integration + others, 0 failures
- `cargo clippy --all-targets --all-features` clean
- `npm test` in scripts/ado-script/ — 281/281 vitest passes
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: address Rust PR Reviewer round-6 suggestions (#922)
Three items from the latest review.
(1) Stale test name (`tests/compiler_tests.rs` ~L4239) —
`test_exec_context_pr_only_downloads_bundle_in_agent_job_not_setup`
was the original intent, but the body was later updated to assert
the Setup job DOES carry the bundle download (the synthPr step is a
Setup-job bundle consumer). Renamed to
`test_exec_context_pr_downloads_bundle_in_both_jobs_with_synth_mode`
and updated the doc-comment to describe the two consumers.
(2) `is_synthetic_pr()` helper on `FrontMatter` —
`front_matter.pr_trigger().is_some_and(|p| matches!(p.mode,
PrMode::Synthetic))` was duplicated verbatim in three places
(`compile_shared`, `ExecContextExtension::new`,
`collect_extensions`). Extracted to `FrontMatter::is_synthetic_pr()`
in `src/compile/types.rs` so a future `PrMode` variant can't drift
across the three sites. All three call sites now use the helper.
(3) Truncated doc-comment on `PrTriggerConfig.mode` — the previous
text ("Whether to synthesise PullRequest semantics on CI builds when
an / PR-trigger mode. Drives whether ...") read as a cut-off
sentence. Rewrote to "Determines how `on.pr` builds reach the
pipeline; see [`PrMode`] for the two supported strategies
(`synthetic`, `policy`). Defaults to [`PrMode::Synthetic`]."
Validation:
- `cargo build` clean
- `cargo test` 1813 lib + 131 compiler-integration + others, 0 failures
- `cargo clippy --all-targets --all-features` clean
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>1 parent ce617a7 commit 1130d2a
28 files changed
Lines changed: 2442 additions & 220 deletions
File tree
- .github/workflows
- docs
- prompts
- scripts/ado-script
- src
- exec-context-pr-synth
- __tests__
- gate
- src/compile
- extensions
- exec_context
- tests
- fixtures
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
73 | 73 | | |
74 | 74 | | |
75 | 75 | | |
76 | | - | |
| 76 | + | |
77 | 77 | | |
78 | 78 | | |
79 | 79 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
104 | 104 | | |
105 | 105 | | |
106 | 106 | | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
107 | 125 | | |
108 | 126 | | |
109 | 127 | | |
| |||
328 | 346 | | |
329 | 347 | | |
330 | 348 | | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
429 | 429 | | |
430 | 430 | | |
431 | 431 | | |
| 432 | + | |
| 433 | + | |
432 | 434 | | |
433 | 435 | | |
434 | 436 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
32 | 32 | | |
33 | 33 | | |
34 | 34 | | |
35 | | - | |
| 35 | + | |
36 | 36 | | |
37 | 37 | | |
38 | 38 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
47 | 57 | | |
48 | 58 | | |
49 | 59 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| 6 | + | |
6 | 7 | | |
7 | 8 | | |
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
10 | | - | |
11 | | - | |
| 10 | + | |
| 11 | + | |
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
18 | | - | |
| 19 | + | |
19 | 20 | | |
20 | 21 | | |
21 | 22 | | |
22 | 23 | | |
23 | | - | |
| 24 | + | |
| 25 | + | |
24 | 26 | | |
25 | 27 | | |
26 | 28 | | |
| 29 | + | |
27 | 30 | | |
28 | 31 | | |
29 | 32 | | |
| |||
Lines changed: 61 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 | + | |
0 commit comments