Commit 473b847
authored
fix(chart): discovery-based defaults for subnets; required endpoint and VIP (#130)
* fix(chart): default kubelet.validSubnets from discovered primary subnet
When .Values.advertisedSubnets is unset in values.yaml, fall back to
the CIDR of the node's default-gateway-bearing link (as returned by
talm.discovered.default_addresses_by_gateway). Previously the chart
emitted whatever was in values.yaml verbatim, so a stale placeholder
like 192.168.100.0/24 silently landed in machine configs for nodes
on completely different networks.
Talos' validSubnets matching uses net.ParseCIDR + IPNet.Contains, so
emitting the node's IP-with-prefix (e.g. 192.168.201.10/24) is
semantically equivalent to the network form (192.168.201.0/24) — no
network-alignment math needed.
Applied symmetrically to both cozystack and generic presets.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
* fix(chart): default etcd.advertisedSubnets from discovered primary subnet
Same shape as the kubelet.validSubnets fallback: when
.Values.advertisedSubnets is unset, pick the CIDR of the node's
default-gateway-bearing link via talm.discovered.default_addresses_by_gateway
instead of silently emitting the stale 192.168.100.0/24 placeholder
baked into values.yaml.
etcd matches advertisedSubnets against local addresses using the
same CIDR semantics as kubelet, so the discovered IP/prefix form is
safe to emit directly.
Applied symmetrically to both cozystack and generic presets.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
* fix(chart): require cluster endpoint in values.yaml
Replace the bare "{{ .Values.endpoint }}" interpolation with
Helm's required() so an unset or empty endpoint produces a clear
error at render time instead of silently embedding a stale
192.168.100.10:6443 placeholder in machine configs.
Unlike kubelet validSubnets and etcd advertisedSubnets, endpoint
has no per-node fallback: it is the cluster-wide URL every node
dials for the API server, so it must come from operator input
(VIP, LB, single-node IP) — there is nothing to discover locally.
Applied symmetrically to both cozystack and generic presets.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
* chore(values): drop misleading placeholder subnet + clarify endpoint
Two related changes to the chart's default values file:
- advertisedSubnets: was pre-populated with 192.168.100.0/24. Every
user not running on that subnet got a stale value silently baked
into their machine config. Now defaults to an empty list so the
chart's new fallback path (default_addresses_by_gateway) kicks in.
The in-file comment explains when to override.
- endpoint: the placeholder https://192.168.100.10:6443 is kept as
an example but the comment is rewritten to mark the field REQUIRED
and explain why no auto-discovery is possible (cluster-wide value,
not per-node). The chart now uses required() so an unset or empty
value fails loudly rather than silently embedding this placeholder.
Applied symmetrically to cozystack and generic presets.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
* test(engine): cover discovery-based subnet fallbacks and required endpoint
Five new tests pin the behavior introduced by the chart changes in
this branch:
- TestMultiDocCozystack_ValidSubnetsFallsBackToDiscovery — empty
advertisedSubnets in values, lookup yields 192.168.201.10/24 on the
gateway-bearing link; rendered kubelet.validSubnets must contain
the discovered CIDR and must NOT contain the historical
192.168.100.0/24 placeholder.
- TestMultiDocCozystack_AdvertisedSubnetsFallsBackToDiscovery —
same setup, assertion on etcd.advertisedSubnets.
- TestMultiDocCozystack_ValuesAdvertisedSubnetsOverridesDiscovery —
explicit [10.0.0.0/8] in values; rendered config must use the
operator's value in both subnet-selector fields, discovered CIDR
must not leak into either. Counts occurrences of the override
(expect ≥2 — once per consumer) and rejects the discovered CIDR
in a subnet-list context (excluding LinkConfig address lines).
- TestMultiDocCozystack_EndpointRequired — empty endpoint in
values; Render must fail with Helm's required() error mentioning
endpoint, instead of silently embedding the stale placeholder.
- TestMultiDocGeneric_ValidSubnetsFallsBackToDiscovery —
equivalent smoke check for the generic preset.
Adds simpleNicLookup() — a minimal single-physical-interface lookup
fixture with a deliberately non-100.* subnet so the tests can
distinguish 'discovered' from 'historical default' in the output.
Adds renderCozystackWith / renderGenericWith — thin wrappers over the
existing chart-render pattern used by TestMultiDoc* suites, keeping
the new tests readable.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
* fix(values): blank default endpoint so required fires on fresh install
Previously 'endpoint' kept its https://192.168.100.10:6443 placeholder
even after the chore(values) commit dropped advertisedSubnets —
meaning Helm's required() guard never fired for a fresh user who
kept defaults; the chart silently embedded the wrong endpoint.
Set endpoint to the empty string so required() surfaces the missing
value loudly. Comment block above the key explains the motivation
and points at an example for operators to copy. Same change applied
symmetrically to cozystack and generic presets.
Also adds a commented format-example under advertisedSubnets so
operators overriding discovery have a syntax reference.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
* test(engine): adapt existing tests to empty-endpoint default; add fresh-default + worker coverage
Two mechanical changes + two new tests motivated by the fix(values)
commit that blanks the shipped endpoint:
1. Existing TestMultiDoc*, TestLegacyCozystack_NrHugepages and the
renderChartTemplate helper previously relied on chrt.Values
carrying a non-empty endpoint default. With the default blank they
all hit the required() guard and fail. Inject a testEndpoint
constant (https://talm-test.invalid:6443) in tests that are not
specifically exercising the guard, so the rest of the chart is
still reachable.
2. renderCozystackWith / renderGenericWith helpers gain an
auto-inject so all new tests going through them don't have to
spell out the endpoint.
Two new tests:
- TestMultiDocCozystack_ShippedDefaultsFailFresh — renders with
chrt.Values exactly as shipped, expects a required() error. This
test would fail if a future commit reintroduced a placeholder
endpoint into values.yaml. Pins the fix(values) commit's intent at
the test level.
- TestMultiDocCozystack_WorkerValidSubnetsFallsBackToDiscovery —
kubelet.validSubnets lives in the shared talos.config.machine.common
block, so it is emitted for workers too. This test guards against a
regression that would only break the worker path.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
* fix(chart): canonical subnet form + required guard on empty discovery
Two correctness fixes to the discovery fallback:
1. Emit the network form of the CIDR (192.168.201.0/24), not the
host form (192.168.201.10/24). Talos matches both equivalently
via netip.Prefix.Contains, but the ticket reporter explicitly
asked for the canonical network form, and every Talos doc and
third-party example uses it. Host-form output in a subnet-selector
field is a trap for anyone comparing rendered configs against
upstream references.
Adds a small cidrNetwork template function to pkg/engine/helm that
wraps net/netip.ParsePrefix+Masked and handles IPv4/IPv6
uniformly. Sprig ships no equivalent. The chart helpers pipe the
discovered address through it in the fallback branches.
2. When the operator leaves advertisedSubnets empty AND discovery
yields no default-gateway-bearing link (offline render, pre-boot
node, no default route), the previous fallback produced an empty
validSubnets list silently. A silent empty field is worse than
the old broken default because nothing surfaces the problem.
Wrap the fallback in a required() guard that fires on empty
discovery with a clear remediation message pointing at both
options (set values.yaml explicitly, or fix the node's default
route). The etcd fallback reuses the validSubnets guard's fire
path — same chart render, same .Values state — so a second
required() there would just add noise without extra signal.
Test updates:
- All existing assertions on 192.168.201.10/24 in the subnet-
selector fields switched to 192.168.201.0/24 (the masked form).
LinkConfig's 'address: 192.168.201.10/24' stays host-form, which
is correct for interface addresses.
- New TestMultiDocCozystack_EmptyDiscoveryErrors exercises the new
required() guard: advertisedSubnets empty + empty lookup → assert
render fails with advertisedSubnets in the error message.
- The override-precedence leak check updated to scan for the
fallback's canonical form rather than the host form.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
* docs: couple endpoint+floatingIP in values.yaml and README getting-started
Two adjacent docs fixes:
- README getting-started previously said to run talm init then talm
template -t ... > nodes/node1.yaml. With the new required-endpoint
guard, that second command fails with a required() error because
values.yaml ships endpoint empty. Add an explicit 'edit values.yaml'
step between init and template, covering the endpoint + floatingIP
coupling for cozystack deployments and the single-node / external-LB
alternatives. Subnet fields are now covered in the same paragraph
since they discover automatically.
- charts/cozystack/values.yaml gained a long endpoint comment earlier
in this branch but still left a silent trap: users who set
'endpoint: https://192.168.100.10:6443' by copying the example
without also editing floatingIP ended up with an endpoint pointing
at an IP no node VIP-claims. Comment now makes the coupling
explicit and tells single-node / external-LB users to blank
floatingIP. The floatingIP key itself gained a one-line comment
pointing back at endpoint.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
* fix(values): blank default floatingIP so VIP never ships a placeholder
Same reasoning as the earlier endpoint-blanking commit: floatingIP
shipped as 192.168.100.10, which for any user whose network was not
192.168.100.0/24 silently embedded a Layer2VIPConfig pointing at an
IP no node claims. Even worse than the endpoint case because Talos
actively advertises the bogus VIP on the primary link, visibly
broken without any kube-proxy round trip.
Blank the default so operators opt into VIP explicitly. Single-node
clusters and external-LB topologies leave it blank and get no VIP
document; cozystack multi-node setups set it to match endpoint.
Regression guards: TestMultiDocCozystack_NoVIPOnFreshDefaults pins
the shipped-default behavior (no VIP); existing
TestMultiDocCozystack_ControlPlane loses its pre-PR
'expects 192.168.100.10' assertion; TestMultiDocCozystack_
Layer2VIPConfigWhenFloatingIPSet covers the opt-in path.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
* fix(chart): dedupe subnet fallback; reword required messages
Two small-but-meaningful improvements to the subnet fallback and
error wording:
1. Dedupe subnets derived from multiple addresses on the same link.
validSubnets is a set semantically (Talos uses it as a CIDR match
list), so a link with a secondary address in the same subnet
previously emitted two identical list entries. The new pass
collects cidrNetwork results and runs them through sprig's uniq
before emitting. TestMultiDocCozystack_DedupesDuplicateSubnets-
FromMultipleAddresses pins this.
2. Reword required() messages to explain why auto-discovery is not
possible ('talm template runs once per node and cannot reconcile
per-node IPs into one cluster value') instead of the dismissive
'no auto-discovery is possible'. The original ticket author
explicitly asked for auto-derivation, so the message should
explain the constraint instead of just refusing. Swap em-dashes
for -- since Helm's error wrapping is known to mangle em-dashes
in some terminals.
3. advertisedSubnets docstring in charts/generic/values.yaml cleaned
up to match the wording of charts/cozystack/values.yaml for
symmetry.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
* docs+test: align README example; add VIP + dedupe + floatingIP tests
README getting-started block previously showed endpoint=192.168.0.1
followed by a tutorial node at 1.2.3.4 -- inconsistent for a reader
walking the example. Rewrite the example to use 1.2.3.4 throughout
as a single-node scenario (endpoint=node IP, floatingIP blank), which
also demonstrates the 'blank floatingIP for single-node' path that
the new default enables.
Test additions and updates on the engine side:
- TestMultiDocCozystack_Layer2VIPConfigWhenFloatingIPSet covers the
opt-in VIP path (user sets floatingIP, chart emits VIP doc).
- TestMultiDocCozystack_NoVIPOnFreshDefaults pins the shipped-empty
default behavior: no VIP on a vanilla 'talm init' render.
- TestMultiDocCozystack_DedupesDuplicateSubnetsFromMultipleAddresses
covers the new uniq-pass in the subnet fallback: two addresses in
the same subnet collapse to one list entry per consumer
(validSubnets + advertisedSubnets = 2 total occurrences).
- TestMultiDocCozystack_ControlPlane (pre-existing) retired its
'expect 192.168.100.10 VIP' assertion in favor of an explicit
'no VIP on fresh defaults' assertion, reflecting the new shipped
behavior.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
* test: unit-test cidrNetwork + strengthen empty-discovery assertion
Two test-quality polish items from review:
- TestCidrNetworkTemplateFunc covers cidrNetwork via a trivial chart
that just renders {{ cidrNetwork INPUT }}: happy-path IPv4/IPv6
host-form masking, already-canonical round-trip, narrow prefix
round-trip, and malformed inputs. Runs in ~0ms each. Catches a
regression in the function without needing a full chart render.
- TestMultiDocCozystack_EmptyDiscoveryErrors now asserts both the
advertisedSubnets field name AND the 'default route' diagnostic
phrase. Two independent signals pin the error's guidance shape,
so a future reword cannot silently drop half the message.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
* fix(chart): use fail instead of required for unconditional discovery error
Address review feedback from gemini-code-assist on
charts/cozystack/templates/_helpers.tpl:32:
The empty-discovery branch used `required "msg" ""` to fail — the
literal empty string as value makes the check unconditionally-true,
which is semantically confusing since required() is for optional-vs-
required checks. `fail "msg"` expresses the same intent in one
function call and matches the engine's existing helpers (the render
harness already registers both required and fail).
No behavior change; same error message, same trigger condition.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
* fix(chart): use fail instead of required for unconditional discovery error (generic)
Address review feedback from gemini-code-assist on
charts/generic/templates/_helpers.tpl:27:
Mirror the cozystack-preset change — swap `required "msg" ""` for
`fail "msg"` in the empty-discovery branch. Keeps the two presets
symmetric.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
* test(engine): deep-copy chart values in render helpers
Address review feedback from gemini-code-assist on
pkg/engine/render_test.go:71:
maps.Copy does a shallow copy of chrt.Values. Today's tests only
mutate top-level keys, but a future contributor writing something
like `values["podSubnets"] = append(values["podSubnets"].([]any), x)`
could corrupt chrt.Values via the shared slice's backing array, and
downstream tests loading the same chart would pick up the mutation.
Introduce cloneValues — a small recursive deep-copy handling maps,
slices, and primitives — and use it in the renderCozystackWith,
renderGenericWith, and renderChartTemplate helpers where chrt.Values
is the starting point. The existing maps.Copy for merging in caller-
supplied overrides is kept; overrides maps are built fresh per test
so they are already safe.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
* docs(readme): use RFC 5737 documentation IPs in getting-started walkthrough
Address review feedback from coderabbitai on README.md:135:
The rendered config sample showed the old placeholder
https://192.168.0.1:6443, which contradicted the values.yaml example.
Swap the walkthrough to the RFC 5737 TEST-NET-1 range (192.0.2.0/24)
for both node and gateway so the example uses IPs reserved for
documentation and cannot accidentally collide with a real network.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
---------
Signed-off-by: Aleksei Sviridkin <f@lex.la>1 parent 00358fd commit 473b847
8 files changed
Lines changed: 806 additions & 24 deletions
File tree
- charts
- cozystack
- templates
- generic
- templates
- pkg/engine
- helm
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
59 | 59 | | |
60 | 60 | | |
61 | 61 | | |
62 | | - | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
63 | 82 | | |
64 | 83 | | |
65 | 84 | | |
66 | | - | |
| 85 | + | |
67 | 86 | | |
68 | 87 | | |
69 | 88 | | |
70 | 89 | | |
71 | | - | |
| 90 | + | |
72 | 91 | | |
73 | 92 | | |
74 | 93 | | |
| |||
89 | 108 | | |
90 | 109 | | |
91 | 110 | | |
92 | | - | |
| 111 | + | |
93 | 112 | | |
94 | 113 | | |
95 | | - | |
| 114 | + | |
96 | 115 | | |
97 | 116 | | |
98 | 117 | | |
| |||
113 | 132 | | |
114 | 133 | | |
115 | 134 | | |
116 | | - | |
| 135 | + | |
117 | 136 | | |
118 | 137 | | |
119 | 138 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
| 21 | + | |
21 | 22 | | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
22 | 42 | | |
23 | 43 | | |
24 | 44 | | |
| |||
85 | 105 | | |
86 | 106 | | |
87 | 107 | | |
88 | | - | |
| 108 | + | |
89 | 109 | | |
90 | 110 | | |
91 | 111 | | |
| |||
119 | 139 | | |
120 | 140 | | |
121 | 141 | | |
| 142 | + | |
122 | 143 | | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
123 | 159 | | |
124 | 160 | | |
125 | 161 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
2 | 22 | | |
3 | | - | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
4 | 32 | | |
5 | 33 | | |
6 | 34 | | |
7 | 35 | | |
8 | 36 | | |
9 | | - | |
10 | | - | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
11 | 51 | | |
12 | 52 | | |
13 | 53 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
| 16 | + | |
16 | 17 | | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
17 | 37 | | |
18 | 38 | | |
19 | 39 | | |
| |||
33 | 53 | | |
34 | 54 | | |
35 | 55 | | |
36 | | - | |
| 56 | + | |
37 | 57 | | |
38 | 58 | | |
39 | 59 | | |
| |||
42 | 62 | | |
43 | 63 | | |
44 | 64 | | |
| 65 | + | |
45 | 66 | | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
46 | 82 | | |
47 | 83 | | |
48 | 84 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
2 | 11 | | |
3 | 12 | | |
4 | 13 | | |
5 | 14 | | |
6 | | - | |
7 | | - | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
8 | 29 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
| 22 | + | |
22 | 23 | | |
23 | 24 | | |
24 | 25 | | |
| |||
218 | 219 | | |
219 | 220 | | |
220 | 221 | | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
221 | 235 | | |
222 | 236 | | |
223 | 237 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1218 | 1218 | | |
1219 | 1219 | | |
1220 | 1220 | | |
| 1221 | + | |
| 1222 | + | |
| 1223 | + | |
| 1224 | + | |
| 1225 | + | |
| 1226 | + | |
| 1227 | + | |
| 1228 | + | |
| 1229 | + | |
| 1230 | + | |
| 1231 | + | |
| 1232 | + | |
| 1233 | + | |
| 1234 | + | |
| 1235 | + | |
| 1236 | + | |
| 1237 | + | |
| 1238 | + | |
| 1239 | + | |
| 1240 | + | |
| 1241 | + | |
| 1242 | + | |
| 1243 | + | |
| 1244 | + | |
| 1245 | + | |
| 1246 | + | |
| 1247 | + | |
| 1248 | + | |
| 1249 | + | |
| 1250 | + | |
| 1251 | + | |
| 1252 | + | |
| 1253 | + | |
| 1254 | + | |
| 1255 | + | |
| 1256 | + | |
| 1257 | + | |
| 1258 | + | |
| 1259 | + | |
| 1260 | + | |
| 1261 | + | |
| 1262 | + | |
| 1263 | + | |
| 1264 | + | |
| 1265 | + | |
| 1266 | + | |
| 1267 | + | |
| 1268 | + | |
| 1269 | + | |
| 1270 | + | |
| 1271 | + | |
| 1272 | + | |
| 1273 | + | |
0 commit comments