Compare commits

...

16 commits

Author SHA1 Message Date
3e2c83435d
import the regular way, fixing error: attribute 'age' missing 2025-03-18 09:56:08 +01:00
e3a7cdde96
comment fediversity.eu option as its subdomains named after our services are used for production instances
08d109cc82/services/fediversity/sharedOptions.nix (L44)
2025-03-18 09:56:08 +01:00
6275e8b2dc
pass in dummy initialUser to trigger orchestration from the panel 2025-03-18 09:56:08 +01:00
8fbe59af55
default form to .net as .eu subdomains are used for live services 2025-03-18 09:56:08 +01:00
0bd65f1ed5
add openssh to devshell, as seemingly needed to trigger nixops4 by flake in django 2025-03-18 09:56:08 +01:00
fbd1f2f576
move from documenting to automating configurable-impure-env 2025-03-18 09:56:08 +01:00
29f841d1db
pass flake path as inputs.self.outPath? 2025-03-18 09:56:08 +01:00
b0a8690511
WIP: change env to environment 2025-03-18 09:56:08 +01:00
7b77e2ad72
use imputs over self 2025-03-18 09:56:08 +01:00
4987e9f530
pass self thru in flake 2025-03-18 09:56:08 +01:00
f39f5d295a
Remove addding nixpkgs (did not fix the issue) 2025-03-18 09:56:08 +01:00
7b6e8fa9ba
Pass REPO_DIR implicitly 2025-03-18 09:56:08 +01:00
3b6fcc2878
add NIX_DIR 2025-03-18 09:56:08 +01:00
bc670296d7
Convert configuration form to json
WIP: Get nix in scope
2025-03-18 09:56:08 +01:00
9c40fd0bfb
WIP: trigger nixops from panel
Closes #76.

Note I had not yet manage to successfully test this.

Manually trying the parameterized NixOps4 I tried using the following
command, tho I had yet to get this to work as well:

```sh
DEPLOYMENT='{"domain": "fediversity.net", "mastodon": {"enable": false},
"pixelfed": {"enable": true}, "peertube": {"enable": false}}' nix
develop --extra-experimental-features "configurable-impure-env"
--command nixops4 apply test
```

(or rather, I used a hardcoded Nix here so as to make it not use Lix.)

So far this had failed for me with:

```
the following units failed:
acme-mastodon.web.garage.fediversity.net.service
...
nixops4 error: Failed to create resource garage-configuration
```
2025-03-18 09:56:08 +01:00
98c4490b4e update fedi201 host public key (#251)
this is a hack in order to be able to redeploy; that machine was still provisioned
manually

Reviewed-on: Fediversity/Fediversity#251
2025-03-18 09:51:27 +01:00
15 changed files with 136 additions and 74 deletions

View file

@ -58,7 +58,10 @@
packages = [ packages = [
pkgs.nil pkgs.nil
inputs'.agenix.packages.default inputs'.agenix.packages.default
inputs'.nixops4.packages.default (inputs'.nixops4.packages.default.overrideAttrs {
impureEnvVars = [ "DEPLOYMENT" ];
})
pkgs.openssh
pkgs.httpie pkgs.httpie
pkgs.jq pkgs.jq
]; ];

View file

@ -143,7 +143,17 @@ in
## - We add a “test” deployment with all test machines. ## - We add a “test” deployment with all test machines.
nixops4Deployments = genAttrs machines makeDeployment' // { nixops4Deployments = genAttrs machines makeDeployment' // {
default = makeDeployment machines; default = makeDeployment machines;
test = makeTestDeployment (fromJSON (readFile ./test-machines/configuration.json)); test = makeTestDeployment (
fromJSON (
let
env = builtins.getEnv "DEPLOYMENT";
in
if env != "" then
env
else
builtins.trace "env var DEPLOYMENT not set, falling back to ./test-machines/configuration.json!" (readFile ./test-machines/configuration.json)
)
);
}; };
flake.nixosConfigurations = flake.nixosConfigurations =
genAttrs machines (makeConfiguration false) genAttrs machines (makeConfiguration false)

View file

@ -1,17 +1,25 @@
{ {
inputs,
config, config,
pkgs,
... ...
}: }:
let let
name = "panel"; name = "panel";
panel = (import ../../../panel/default.nix { }).package; panel = (import ../../../panel/default.nix { }).package;
in in
# builtins.trace args.pkgs
{ {
imports = [ imports = [
../../../panel/nix/configuration.nix ../../../panel/nix/configuration.nix
]; ];
nix.settings = {
extra-experimental-features = "configurable-impure-env";
};
environment.systemPackages = [ environment.systemPackages = [
inputs.self.outPath
panel panel
]; ];
@ -36,4 +44,8 @@ in
STATIC_ROOT = "/var/lib/${name}/static"; STATIC_ROOT = "/var/lib/${name}/static";
}; };
}; };
systemd.services.${name}.environment = {
REPO_DIR = inputs.self.outPath;
NIX_DIR = pkgs.nix;
};
} }

View file

@ -1 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILhSlUo7L/TjoAILfLv/BDxlBT+rGudh9VoK50Uiu2lZ root@fedi201 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKBpnV6zzgdJN5pjw2oWryneE6kZ5rQ343Ut4ed12Cm9 root@fedi201

View file

@ -34,6 +34,7 @@ in
export CREDENTIALS_DIRECTORY=${builtins.toString ./.credentials} export CREDENTIALS_DIRECTORY=${builtins.toString ./.credentials}
export DATABASE_URL="sqlite:///${toString ./src}/db.sqlite3" export DATABASE_URL="sqlite:///${toString ./src}/db.sqlite3"
''; '';
NIX_DIR = pkgs.nix;
}; };
tests = pkgs'.callPackage ./nix/tests.nix { }; tests = pkgs'.callPackage ./nix/tests.nix { };

View file

@ -39,11 +39,11 @@ class Configuration(BaseModel):
# XXX: hard-code available apex domains for now, # XXX: hard-code available apex domains for now,
# they will be prefixed by the user name # they will be prefixed by the user name
class Domain(Enum): class Domain(Enum):
EU = "fediversity.eu" # EU = "fediversity.eu"
NET = "fediversity.net" NET = "fediversity.net"
domain: Domain = Field( domain: Domain = Field(
default=Domain.EU, default=Domain.NET,
description="DNS domain where to expose services" description="DNS domain where to expose services"
) )

View file

@ -5,7 +5,7 @@
{{ form.as_p }} {{ form.as_p }}
<button class="button" disabled>Deploy</button> <button class="button" type="submit" name="deploy">Deploy</button>
<button class="button" type="submit" >Save</button> <button class="button" type="submit" name="save">Save</button>
</form> </form>
{% endblock %} {% endblock %}

View file

@ -1,6 +1,10 @@
from enum import Enum from enum import Enum
import os
import json
from django.urls import reverse_lazy from django.urls import reverse_lazy
import os
import subprocess
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.views.generic import TemplateView, DetailView from django.views.generic import TemplateView, DetailView
@ -10,6 +14,7 @@ from panel import models
from panel.configuration import forms from panel.configuration import forms
class Index(TemplateView): class Index(TemplateView):
template_name = 'index.html' template_name = 'index.html'
@ -41,6 +46,39 @@ class ConfigurationForm(LoginRequiredMixin, FormView):
operator=self.request.user, operator=self.request.user,
) )
# Check for deploy button
if "deploy" in self.request.POST.keys():
print("DEPLOYING:")
print(os.getenv("REPO_DIR"))
print(os.getenv("NIX_DIR"))
submission = obj.parsed_value.model_dump_json()
deployment = json.dumps(json.loads(submission) | {
"initialUser": {
"displayName": "Testy McTestface",
"username": "test",
"password": "testtest",
"email": "test@test.com",
},
})
env = {
"DEPLOYMENT": deployment,
"PATH": f"{os.getenv("NIX_DIR")}/bin/",
}
print(f"env: {env}")
print(f"Path: {os.getcwd()}/..")
cmd = [
"nix",
"develop",
"--extra-experimental-features",
"configurable-impure-env",
"--command",
"nixops4",
"--show-trace",
"--verbose",
"apply",
"test",
]
subprocess.run(cmd, cwd=os.getenv("REPO_DIR") or f"{os.getcwd()}/..", env=env)
return obj return obj
# TODO(@fricklerhandwerk): # TODO(@fricklerhandwerk):

View file

@ -1,18 +1,17 @@
age-encryption.org/v1 age-encryption.org/v1
-> ssh-ed25519 Jpc21A aY4iHQUrjmuTgBkIwG3vg8XBK458PWXpiZ5E/m/UHnU -> ssh-ed25519 Jpc21A JzLWMEH98I5/A8O55mKUMy5zo2kg3Qk8SfXnHvkjwT4
VCuYTllN1tW5RzIigPiN+p/W5uI3Urh0J3IpLXDL1H4 8f7zDHSp3AHoAQy0dVWMa1TurCBLnsHNtbNjaD++7ow
-> ssh-ed25519 BAs8QA pP6PTq+vp+fP1oOv3ep4dWspwANxj9DSS94t0a+1Q1o -> ssh-ed25519 BAs8QA eCD3saYXdv1bjAoQghmyVqHjMBu/o2lWgu7grk1vgRs
tpqUnXqp/wmfXFMe2iXRRda+JmW5ZgypduKOS8meCJw //pOnkzqQTK3xmeCjruo46ju2X136KEt6DpsegMouFQ
-> ssh-ed25519 ofQnlg om0geQk3YR3+WXsPdIC46wL02M57Qror6MD/PynrTAs -> ssh-ed25519 ofQnlg ePjq7GmM36qaGxcJ0qnW8FdKDjwlXtFqOBK8OgWY3Co
Yj5xcXf203kW70SndVBBagh62yAn0T41lzg3ReD1kEs gVmsDP9rMcQD/B6BpNhCn+avdgjhyyohNUXlatXpXo0
-> ssh-ed25519 COspvA bvBwdWb0kO89Myw3u2heNwd/4vN1+4tiWjNyoF3t+hM -> ssh-ed25519 COspvA lrQB/NEmMUR2RWxfRzE2iTDkjMYsrIaiKn8thxZR+RA
eCX26mAJy8stuYrRijqicgODAlyKt3zjeZchCkBpfOI MU23Z28v+cNk2VxpAYaYoFb53js2Zr9/KAM9uMe6+EA
-> ssh-ed25519 2XrTgw wQMvYCYmw4Iql/EmUSW5HG0fz4POn/VIZrMsL5vuUBc -> ssh-ed25519 2XrTgw z1ixx5dYCNbgw6wWV45b4wn69X/5/4MzesTomWa4WB4
RaDLMF7OadInlWbQ70/5gpQ4tpwae8i74hu5Wftf6Yg eNSlP6+nUW9rpsGyzqOEQ+7IVpGeU3UcZpyfB9XT2/4
-> ssh-ed25519 1MUEqQ ygipOVN6+Z09bfMZFdHRT8Wx+H4Ml0YM0w0vrUANugA -> ssh-ed25519 1MUEqQ c6ps9RB6Dw9JtR0+4eB1NDx44uUes8YjLrY7RCpD0jg
XvtQMpD+iEpEKGwPVcq9mAftfaRlOJXTXUdcqyvVn9w GwVRqR5t07ctbWhwH76T+SAe2Y6Vv1uY/AHkzd/gw/c
-> ssh-ed25519 Fa25Dw qc7z4aL3dHjoOTdPBVm4q6V458BuTGLMekP5Hlk0bk0 -> ssh-ed25519 Fa25Dw jTqtV2RWsXBH4zgWAYr9tBGC/BbXKBvr3uyL8IgmI1o
kZuabCaiH7DBhO8mDta8AXUxH65Cpm8u9P9ntw8A5pI qBirnzIpi9hB61xwyS+5U6XBobAquEJrV3cleDtG8/4
--- zpGb6Td6MdLKxE3mkK1a7JqBH77th6045mcdGIsNth0 --- j/vJgDV+47UmKokdvztXntBIhCLEyUm2aYoGJ2WMKbU
ÿr*"DQÏÛ-©·í½`ÀU¯…µŠ`ËÒ¹Æu{<7B>ªC<C2AA>]GZ(p ¢¹ŽÀi±ËQõf §¥ÐÅ·DN§àB"—ÍvsëB6QžorF‡<46>Å
Ü×Uf‰

View file

@ -1,18 +1,17 @@
age-encryption.org/v1 age-encryption.org/v1
-> ssh-ed25519 Jpc21A ExqTXUYWuoVsdKwuWzCD72NctIpGvAF4QknTU04he2M -> ssh-ed25519 Jpc21A l6Xwv4JBlTeRTC7RgjxY9gDrCk96atMUH/62P+u55Qs
rN48eYUwPJtTc/UBpB79FayC0W2UnrKdjFTdWKShtc0 CrYsLZgDFAiR8up87lhGZqsbAEZtOXG+l5IzLh2uaqg
-> ssh-ed25519 BAs8QA xODgENkmP/KjT6IGiMW3cBkdrY+o5rbAGywY7Fx99EY -> ssh-ed25519 BAs8QA lgtmfoc4vKfRpI/XbIS258BMyIB4mTdquEx/Kxm5OTI
DNAlVBdObTlgeVhKYtzPv46RCtn7zNm1aURWBOpBXEs 3gQL8Rnqc7JfqsRmKYU3rD0cWMKdnIeVXbY3eFM07RU
-> ssh-ed25519 ofQnlg cEM500igumTfcCWWCH55z22Pp8QqLcqmjTD5e1lp1T0 -> ssh-ed25519 ofQnlg 0vwuCrduMLjssA3CK3gfVPMSPYKO9cF7HH1JF/oJv18
oKBWnaFpaFiEGf51fPqObAkRfRE4gywjQrYGB9kygUs 2KrZgQmpvw/tNDJrDArinnbEjopkkmuG8s7t6klBXcQ
-> ssh-ed25519 COspvA gQbazYgzv8oBeND0VtZ3P241kZM9klO2qysjkc20CFQ -> ssh-ed25519 COspvA NT+/h2KsiZN2XbaWAlrTlDwyAPmHWrwgr6f0uhSbEGs
nW558CrEvtuUEpLo6EUeUTVK6EVUXbNZwP4+GLVVH3A QpoAd+69VYrZwAC0LwDm1m/zfslVgzxpVFihQWDcqzE
-> ssh-ed25519 2XrTgw QlyQRFaRkniJ4BrJEVEP5muS+POPdKSmpS5u4ORiRTc -> ssh-ed25519 2XrTgw QoJ/74FOqYFxHJYXJEkyzbGY0xptSjorNvnyUS1p6zk
/UeO72Y/U9aml3S2s9wE9HUIXPoR+6GDSXF+PT141Qg 0sJ2F6IFuTrRvXO5ND1QL4CZ2lr1BAU3iQffC6Uc3h4
-> ssh-ed25519 1MUEqQ oMz1Cq68FuE1jm63H2Rfr/WqhkCeJ2SQrVtk88FBYGo -> ssh-ed25519 1MUEqQ xxgEUIhvWN/ZfRMGfu3fKQ+fWM5WSz8OexXPm6jaXDk
ou2ZRPuGTlLxsV/DhXoRUhqaQq9Ub+1ZdOcqqazrBZM RXe0JMZ0sYMdQvrbi+zAs9F3d98ocRFnsSGUuUWccRk
-> ssh-ed25519 Fa25Dw USp87LMAo6HfD6gHdA+lrRlwHzKtMwXGjELImsQ7onk -> ssh-ed25519 Fa25Dw tw4sqQcO86Gh0FGUD+O3bJ+8OcaN5rm8R6qocXvDbRg
g8GvPArugT7KIdpgpfWjHFUNyXgL9rRuymQg/RIiQJw 7hiWa4qznHTV45kvC7ucj7j7FbPrqYK5OcCcByrcSxg
--- 6oCFkdV4DmaxMe7lDoDSKgtCKySGqVqrbDv8aRa/h/o --- kvZDYq5n/OXu7xe2Kf5vGN0zosl9fgH4CAf3K0Tq3U4
»W)Eí¨{ä žÑrÛ ¤D!´Ój]2ï݃T+• ÃUó¬æcgÝoP”‰ ˆF.Þ¿_vbÕÓÔdª9
à3OVx)ö¶QéȬ6‰b¶¶O·O¸Ü—ÇÈ‘%Ë

Binary file not shown.

View file

@ -1,17 +1,17 @@
age-encryption.org/v1 age-encryption.org/v1
-> ssh-ed25519 Jpc21A jzJ5wTSLBsJ0DxelUDsT7BxM9qc73hPsCvB/1R3qGC4 -> ssh-ed25519 Jpc21A fBhVzGFs61K63QtA8RdOuuGfHFjMe/Dp0M6TXGLGWDU
5giHjKIjnBVmn4NAtGLSIgKQGts9kOc+EPS6AKugn1s qppnUZ+LQCXhuMCFMYv2D2CkmEfjb7mpmJufIeVjjaM
-> ssh-ed25519 BAs8QA J/y7P+A4z1iETfzta1UBf2AnKOD5lFTuGRo7EjWF4Qw -> ssh-ed25519 BAs8QA PNicZCWLkbvM4ih77/F4z6FzHomL9EsJCuSCjbdRTwA
zUBV+byTPL2kbKS6ZCbu8mk9Lp/fq1iF2Sii0XHxB5I qIpTl/v7Xl08qBB//dFeW9qQiZg10YrYLnfyQrgDRfQ
-> ssh-ed25519 ofQnlg w1RFmJnfOSpKu9tiVvPy3WdLVGO1vUdPW1exb+M7xEM -> ssh-ed25519 ofQnlg 9/vSN3V25ysXBOvS4UJQEzm0734zqO0gXjhgzX63tTs
jk6/yzZMJCvzW1/5T+DKze+PxduLcWDrBGcVN6k5Vfo AH9Q1lWr+RgICfW3h+D2SgCTFr+azI0x3J3eFnaz/XA
-> ssh-ed25519 COspvA DEBQL0y8GQpdib3WUkj1a/FVLVF8aMAZ77MdxLqJkVE -> ssh-ed25519 COspvA IB1nWOMaVZVcvEog6UaqCak2fcKxIUN2yXvvRSTDxGw
V96fUeVJD3v2/V1H5GLo5YIKlIU7fuyYBr7F48gzJ60 Ti7JuBgU6phlI+oXfDDvx42dRu95kTwesRUKu4QsXZ4
-> ssh-ed25519 2XrTgw ixdrdSfgH9Ch1Y4aflWP1QG6khhKN8mD1jFyOXhDTyA -> ssh-ed25519 2XrTgw 7S9ZhJvUFMw9tDCc0HvkRsRqjvmn47GFGVg/jkxIy1I
Kd8QfZ1IqWqiaAY4C8+J/AE6vqIRNAZtU6jbIjRYvCA cj27gqqihSZG3Jcab9h9FyNJ1J8FjlUiyVlDot+sbWQ
-> ssh-ed25519 1MUEqQ Mwda57DHcYYsBJr0L6q9IcO4xyr6NvfTlXyRK/sfjWk -> ssh-ed25519 1MUEqQ l9mVTLD9rZXisBEz0sU2AdFNrJQ/+zuFTiIod5R/HCI
WX2CsIJBJL1Q9ZMsLzLS2s2L1b+7Mm0WXF+PqRVh1p4 2q3csSEvMW5vtzqGHYTtZ1nZ0J1vT23bjhuj9HTsdWk
-> ssh-ed25519 ChtTUw trZu9wftz3Hjd2xTKf8TYM9oLpNBcwQX47Pfi/cetjE -> ssh-ed25519 kXy85Q BCrDvkPZLvx2Kvgapa3BT+AmpS6Fa5kpkgBnRVso2BE
5F1McxV1iLHyIVYdPDeR2twB5aq1fz9g/nrjAF5ys2w ZBi+x/2ilJIzhzGipdZQJoGOjSqCuAttsqCDVFlYJ8Y
--- 7p/n8TyrrtmVay+dPSX+bdlEqzFByuWk/6FyKFKh758 --- iWtseKyfUMBkQTUl9QzwXXLQcodEJeZt1Wuj5sR18yY
I€BãUÕ3M:ƶ,²<>‡¿?-{ü7Ðhý3²#7Œ§ãö'Ôg”~L&ƒ)˜=<3D>bB:9hËA¿TO +2,エ ゚恝Jrメィ><7F>z?ホi<EFBE8E><69><EFBFBD>x<EFBFBD>0z<30>ヤ智メ劬呱^ゥネコ食・濤礫+1」ァ<EFBDA3>

View file

@ -1,18 +1,18 @@
age-encryption.org/v1 age-encryption.org/v1
-> ssh-ed25519 Jpc21A vsNSibhHXdlRVArHkFqPy2vapvpo+lfs6QNESfZHk0c -> ssh-ed25519 Jpc21A BfHJN3vILbsfY91kEjSQ+STrn6vQfn83Fx3cBCNshRQ
ArMZEQCONAIGQwyEh/QkJ3m5Bnru2/A1fQdJNtPraII 0O8GJYfF8WFS4Xsgj5v1cly4JP1MgSN40OgRdW/i0rA
-> ssh-ed25519 BAs8QA 7vfPIUymPXpfX7vhUyNVqBmTllXgJ99gCSHOgWH66HA -> ssh-ed25519 BAs8QA Ue0NLMpmZDSTGvwZ8lhzes7pcmit9F6uwzeT4XhiwC0
gaueu0eHyqY+VAkNIzPb/aLQ1VG13kSpth2tJfhK7sU jsvvuOW344i8GR4B139SX0LwTqzKQEgBvsy8oRppqBU
-> ssh-ed25519 ofQnlg iaJY3mcaKyLjTAqNVnzyivIVRwXxxFzP0ru35s/TU3Q -> ssh-ed25519 ofQnlg 9iSMQeTJn1OUqTF+M2sHpp69lblb8E6TVbgZs7vgD2U
mfKliFvPT+hEOpOPtkdR/UEmEadXZGpQ8+iWg+S/Q8c uMQI1gTTMvYW7ea9xBAln118JEeNvv3nqbq32zJoat8
-> ssh-ed25519 COspvA +LC5rnZIS2R5DA3mIyeo2hR45mcBwNUjRS051qN+q2w -> ssh-ed25519 COspvA YxCyfe0li23JoI2q4XFVUx4vrWApLwSnJD31PHXuPBg
yLYl5g8o29ApSCn+H4Df8P8y+eFv2Hbj6b/nHrzFMdA 8xuT9+W2mnTag9tm6F6LXzHkIh2Nou/8lgxd64OpvWk
-> ssh-ed25519 2XrTgw dG9hmRFpaCBgaoHIkWmJM1Ls/mBqnV5gueGjCTEmRE0 -> ssh-ed25519 2XrTgw jEzw0A9Wd1b1Zoryzp/W/QZ6bd99E7sySnr/W2xcnDs
YkIQDWAwpr3pjjFozGEa3+4+WqJan0KQzUeYNxRjUPc IyMrojJ3AChS6lhj599caNM+02i16qtpc6cocln14b4
-> ssh-ed25519 1MUEqQ 0Mtf2NGpVP3TYuFGrTPyQM+h6PjpgJNwW9amz1w7h0w -> ssh-ed25519 1MUEqQ haiI/5EkuTZ2YHxsqSVlqfM0VVR24DIDrMS3RmXwAhU
J8RM+vl/e8JifUP3dqwH5L9AUqu24pALv6wqxaNhy3g qVIAvLp2qG4A3f3OKUqAKqH1eOicJz54nfblPSUKrSw
-> ssh-ed25519 dgBsjw 9Y1n4J8E5T022V8QCApLykKoX56Zto8eLiy5KZvPuR4 -> ssh-ed25519 dgBsjw /vCnznu73U99onCWcM0aQlW0azscyUe4BB2kKeZvtHs
3piVQigR7rFry43YTTHmXkBSDIAFa/ife1Vuq6/3ubk MPnvXR/WVsl/tJ1YPoc7nk2Ls2x9bbtJdNp3CQTuuWI
--- 5Mr3Xe9RF1mneoWBno4SVkNqHx76EilFG0UvsHbqRQo --- OzkqKlw4xu3McMk20orQN0h+VPYfUUSDC+DsgRU1tSw
çì&­mu°.ÄåNêäã:%œ…<C593>žPî  ]`L<<3C>Î ­ ìÜñÅ]÷ÏÂe/T(s"a×Å<C397>½-ýû$MA¿%LÄÉœv ü^@ÃmŽÚé`B˜³#{¡Ÿ‚ GUu´|¹Á œ¡ rÚïjb¥:Ô“d²ù] GØÎ©¦ú²-«ÂMÁ³ŸÜálÙ3mÌí)½š@¢—±e?¯ªêe¤üZ
óm”‡@+9£¼¿÷%oa/¹K*³å& Y}ÿ!fÐ

Binary file not shown.

Binary file not shown.