+25
-25
flake.lock
+25
-25
flake.lock
···
8
8
"systems": "systems"
9
9
},
10
10
"locked": {
11
-
"lastModified": 1747575206,
12
-
"narHash": "sha256-NwmAFuDUO/PFcgaGGr4j3ozG9Pe5hZ/ogitWhY+D81k=",
11
+
"lastModified": 1750173260,
12
+
"narHash": "sha256-9P1FziAwl5+3edkfFcr5HeGtQUtrSdk/MksX39GieoA=",
13
13
"owner": "ryantm",
14
14
"repo": "agenix",
15
-
"rev": "4835b1dc898959d8547a871ef484930675cb47f1",
15
+
"rev": "531beac616433bac6f9e2a19feb8e99a22a66baf",
16
16
"type": "github"
17
17
},
18
18
"original": {
···
26
26
"nixpkgs": "nixpkgs_2"
27
27
},
28
28
"locked": {
29
-
"lastModified": 1750013871,
30
-
"narHash": "sha256-UQx3rC3QDjD/sIen51+5Juk1rqN3y/sTeMY1WinmhqQ=",
29
+
"lastModified": 1751021896,
30
+
"narHash": "sha256-L9u68mNPPiuW7+OV5BKbXaj/AENTiiuEx8+QnMBjRlU=",
31
31
"owner": "catppuccin",
32
32
"repo": "nix",
33
-
"rev": "fe78fa558d6603481c03eb03a946eadb970d1801",
33
+
"rev": "a6b0e34d083c79f08efabb1fd6ccf12b882daae6",
34
34
"type": "github"
35
35
},
36
36
"original": {
···
158
158
]
159
159
},
160
160
"locked": {
161
-
"lastModified": 1750127463,
162
-
"narHash": "sha256-K2xFtlD3PcKAZriOE3LaBLYmVfGQu+rIF4Jr1RFYR0Q=",
161
+
"lastModified": 1751384836,
162
+
"narHash": "sha256-7xRbl/VLXxE5DzJmk1wdKWJmPx8rAfNC/a6mXtqp5cc=",
163
163
"owner": "nix-community",
164
164
"repo": "home-manager",
165
-
"rev": "28eef8722d1af18ca13e687dbf485e1c653a0402",
165
+
"rev": "479f8889675770881033878a1c114fbfc6de7a4d",
166
166
"type": "github"
167
167
},
168
168
"original": {
···
236
236
"spectrum": "spectrum"
237
237
},
238
238
"locked": {
239
-
"lastModified": 1750196518,
240
-
"narHash": "sha256-HJYnJg3TvzFZjVgYHZgH3NtwqkqKiGVCJXpZlO4Y4EE=",
239
+
"lastModified": 1750358184,
240
+
"narHash": "sha256-17EYMeY5v8KRk9HW6Z4dExY8Wg4y/zM2eM2wbbx+vMs=",
241
241
"owner": "astro",
242
242
"repo": "microvm.nix",
243
-
"rev": "094da86a3e68f2f0d93b654e97b5d42398ead67d",
243
+
"rev": "fd9f5dba1ffee5ad6f29394b2a9e4c66c1ce77dc",
244
244
"type": "github"
245
245
},
246
246
"original": {
···
251
251
},
252
252
"nixos-hardware": {
253
253
"locked": {
254
-
"lastModified": 1750083401,
255
-
"narHash": "sha256-ynqbgIYrg7P1fAKYqe8I/PMiLABBcNDYG9YaAP/d/C4=",
254
+
"lastModified": 1751393906,
255
+
"narHash": "sha256-I1x6K61ZcdFlqc07weRBy3erCAB0lVkX10i0c9eXjDI=",
256
256
"owner": "nixos",
257
257
"repo": "nixos-hardware",
258
-
"rev": "61837d2a33ccc1582c5fabb7bf9130d39fee59ad",
258
+
"rev": "f49bb3b4107a0917ee144337bb02d311033ee1ba",
259
259
"type": "github"
260
260
},
261
261
"original": {
···
299
299
},
300
300
"nixpkgs_3": {
301
301
"locked": {
302
-
"lastModified": 1750005367,
303
-
"narHash": "sha256-h/aac1dGLhS3qpaD2aZt25NdKY7b+JT0ZIP2WuGsJMU=",
302
+
"lastModified": 1751271578,
303
+
"narHash": "sha256-P/SQmKDu06x8yv7i0s8bvnnuJYkxVGBWLWHaU+tt4YY=",
304
304
"owner": "nixos",
305
305
"repo": "nixpkgs",
306
-
"rev": "6c64dabd3aa85e0c02ef1cdcb6e1213de64baee3",
306
+
"rev": "3016b4b15d13f3089db8a41ef937b13a9e33a8df",
307
307
"type": "github"
308
308
},
309
309
"original": {
310
310
"owner": "nixos",
311
-
"ref": "nixos-25.05",
311
+
"ref": "nixos-unstable",
312
312
"repo": "nixpkgs",
313
313
"type": "github"
314
314
}
···
422
422
"nixpkgs": "nixpkgs_4"
423
423
},
424
424
"locked": {
425
-
"lastModified": 1729422940,
426
-
"narHash": "sha256-DlvJv33ml5UTKgu4b0HauOfFIoDx6QXtbqUF3vWeRCY=",
425
+
"lastModified": 1750353031,
426
+
"narHash": "sha256-Bx7DOPLhkr8Z60U9Qw4l0OidzHoqLDKQH5rDV5ef59A=",
427
427
"owner": "nix-community",
428
428
"repo": "nixos-vscode-server",
429
-
"rev": "8b6db451de46ecf9b4ab3d01ef76e59957ff549f",
429
+
"rev": "4ec4859b12129c0436b0a471ed1ea6dd8a317993",
430
430
"type": "github"
431
431
},
432
432
"original": {
···
443
443
]
444
444
},
445
445
"locked": {
446
-
"lastModified": 1750091187,
447
-
"narHash": "sha256-mjAol6qR+onnZwLUdYjmuBr/tnyozUBXz75tSePVU00=",
446
+
"lastModified": 1751383329,
447
+
"narHash": "sha256-52dUY8jEkuXEIZINYb+AVsrmw6FxMhBAG3K9J/2qiSo=",
448
448
"owner": "0xc000022070",
449
449
"repo": "zen-browser-flake",
450
-
"rev": "cfdf98dac59a42e1642c533a5dbfb5bb242903b3",
450
+
"rev": "f29a4fece3b76c3e4579d67e2cf0cb8037f6a351",
451
451
"type": "github"
452
452
},
453
453
"original": {
+3
-1
flake.nix
+3
-1
flake.nix
···
1
1
# flake.nix
2
2
{
3
3
inputs = {
4
-
nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05";
4
+
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
5
5
nixos-hardware.url = "github:nixos/nixos-hardware/master";
6
6
7
7
lix-module = {
···
64
64
system = "x86_64-linux";
65
65
};
66
66
}
67
+
68
+
{ imports = builtins.attrValues nixosModules; }
67
69
];
68
70
};
69
71
+1
home/regent/home.nix
+1
home/regent/home.nix
-3
hosts/buer/default.nix
-3
hosts/buer/default.nix
+6
hosts/focalor/default.nix
+6
hosts/focalor/default.nix
···
29
29
../../host-secrets.nix
30
30
];
31
31
32
+
modules.syncthing = {
33
+
enable = true;
34
+
openDefaultPorts = true;
35
+
disableDefaultFolder = true;
36
+
};
37
+
32
38
# =============================================================================
33
39
# SYSTEM CONFIGURATION
34
40
# =============================================================================
+229
modules/headscale/default.nix
+229
modules/headscale/default.nix
···
1
+
{ config, lib, pkgs, ... }:
2
+
3
+
with lib;
4
+
let
5
+
cfg = config.modules.headscale;
6
+
in
7
+
{
8
+
options = {
9
+
modules = {
10
+
headscale = {
11
+
enable = mkEnableOption "Deploy headscale";
12
+
13
+
oidcClientSecretPath = mkOption {
14
+
type = types.str;
15
+
default = "/etc/headscale/oidc_client_secret.key";
16
+
description = "Path to OIDC client secret file";
17
+
example = "config.age.secrets.headscale-oidc-key.path";
18
+
};
19
+
20
+
litestream = {
21
+
enable = mkEnableOption "Enable litestream for headscale database backups";
22
+
23
+
replicas = mkOption {
24
+
type = types.listOf (types.attrsOf types.anything);
25
+
default = [];
26
+
description = "List of litestream replica configurations";
27
+
example = [
28
+
{
29
+
url = "s3://your-backup-bucket/headscale/db";
30
+
access-key-id = "$LITESTREAM_ACCESS_KEY_ID";
31
+
secret-access-key = "$LITESTREAM_SECRET_ACCESS_KEY";
32
+
region = "us-east-1";
33
+
}
34
+
];
35
+
};
36
+
37
+
backupPath = mkOption {
38
+
type = types.nullOr types.str;
39
+
default = null;
40
+
description = "Local backup path (alternative to S3)";
41
+
example = "/backup/headscale";
42
+
};
43
+
44
+
syncInterval = mkOption {
45
+
type = types.str;
46
+
default = "1s";
47
+
description = "How often to sync to replicas";
48
+
};
49
+
50
+
retention = mkOption {
51
+
type = types.str;
52
+
default = "72h";
53
+
description = "How long to retain snapshots";
54
+
};
55
+
56
+
environmentFile = mkOption {
57
+
type = types.nullOr types.path;
58
+
default = null;
59
+
description = "Environment file containing S3 credentials (can be agenix secret)";
60
+
example = "config.age.secrets.litestream-env.path";
61
+
};
62
+
};
63
+
};
64
+
};
65
+
};
66
+
67
+
config = mkIf cfg.enable {
68
+
services.headscale = {
69
+
enable = true;
70
+
address = "0.0.0.0";
71
+
port = 8080;
72
+
73
+
settings = {
74
+
server_url = "https://headscale.nekomimi.pet";
75
+
76
+
# Metrics and gRPC
77
+
metrics_listen_addr = "127.0.0.1:9090";
78
+
grpc_listen_addr = "127.0.0.1:50443";
79
+
grpc_allow_insecure = false;
80
+
81
+
# Prefixes
82
+
prefixes = {
83
+
v4 = "100.64.0.0/10";
84
+
v6 = "fd7a:115c:a1e0::/48";
85
+
allocation = "sequential";
86
+
};
87
+
88
+
# Database
89
+
database = {
90
+
type = "sqlite";
91
+
sqlite = {
92
+
path = "/var/lib/headscale/db.sqlite";
93
+
write_ahead_log = true;
94
+
};
95
+
};
96
+
97
+
# Noise
98
+
noise = {
99
+
private_key_path = "/var/lib/headscale/noise_private.key";
100
+
};
101
+
102
+
# DERP
103
+
derp = {
104
+
urls = [
105
+
"https://controlplane.tailscale.com/derpmap/default"
106
+
];
107
+
paths = [];
108
+
auto_update_enabled = true;
109
+
update_frequency = "24h";
110
+
server = {
111
+
enabled = false;
112
+
region_id = 999;
113
+
region_code = "headscale";
114
+
region_name = "Headscale Embedded DERP";
115
+
stun_listen_addr = "0.0.0.0:3478";
116
+
private_key_path = "/var/lib/headscale/derp_server_private.key";
117
+
automatically_add_embedded_derp_region = true;
118
+
ipv4 = "1.2.3.4";
119
+
ipv6 = "2001:db8::1";
120
+
};
121
+
};
122
+
123
+
# DNS
124
+
dns = {
125
+
magic_dns = true;
126
+
base_domain = "dns.sharkgirl.pet";
127
+
nameservers = {
128
+
global = [
129
+
"100.64.0.7"
130
+
"1.1.1.1"
131
+
"1.0.0.1"
132
+
"2606:4700:4700::1111"
133
+
"2606:4700:4700::1001"
134
+
];
135
+
};
136
+
search_domains = [];
137
+
};
138
+
139
+
# OIDC with configurable secret path
140
+
oidc = {
141
+
only_start_if_oidc_is_available = true;
142
+
issuer = "https://pocketid.nekomimi.pet";
143
+
client_id = "f345acad-3eac-45b7-9d91-57f388987a57";
144
+
client_secret_path = cfg.oidcClientSecretPath;
145
+
pkce = {
146
+
enabled = true;
147
+
method = "S256";
148
+
};
149
+
};
150
+
151
+
# Policy
152
+
policy = {
153
+
mode = "database";
154
+
};
155
+
156
+
# TLS/ACME
157
+
acme_url = "https://acme-v02.api.letsencrypt.org/directory";
158
+
acme_email = "";
159
+
tls_letsencrypt_hostname = "";
160
+
tls_letsencrypt_cache_dir = "/var/lib/headscale/cache";
161
+
tls_letsencrypt_challenge_type = "HTTP-01";
162
+
tls_letsencrypt_listen = ":http";
163
+
tls_cert_path = "";
164
+
tls_key_path = "";
165
+
166
+
# Logging
167
+
log = {
168
+
format = "text";
169
+
level = "info";
170
+
};
171
+
172
+
# Misc settings
173
+
disable_check_updates = false;
174
+
ephemeral_node_inactivity_timeout = "30m";
175
+
unix_socket = "/var/run/headscale/headscale.sock";
176
+
unix_socket_permission = "0770";
177
+
logtail = {
178
+
enabled = false;
179
+
};
180
+
randomize_client_port = false;
181
+
};
182
+
};
183
+
184
+
# Configurable Litestream for SQLite database backups
185
+
services.litestream = mkIf cfg.litestream.enable {
186
+
enable = true;
187
+
settings = {
188
+
dbs = [
189
+
{
190
+
path = "/var/lib/headscale/db.sqlite";
191
+
sync-interval = cfg.litestream.syncInterval;
192
+
retention = cfg.litestream.retention;
193
+
replicas =
194
+
# Use custom replicas if provided
195
+
if cfg.litestream.replicas != [] then
196
+
cfg.litestream.replicas
197
+
# Otherwise use local backup if path is provided
198
+
else if cfg.litestream.backupPath != null then
199
+
[{ path = cfg.litestream.backupPath; }]
200
+
# Default empty (user must configure)
201
+
else
202
+
[];
203
+
}
204
+
];
205
+
};
206
+
};
207
+
208
+
# Configure systemd service to use agenix secrets
209
+
systemd.services.headscale.serviceConfig = mkMerge [
210
+
{
211
+
SupplementaryGroups = [ "headscale-secrets" ];
212
+
}
213
+
# Add environment file for litestream if specified
214
+
(mkIf (cfg.litestream.enable && cfg.litestream.environmentFile != null) {
215
+
EnvironmentFile = cfg.litestream.environmentFile;
216
+
})
217
+
];
218
+
219
+
# Configure litestream service with environment file if specified
220
+
systemd.services.litestream = mkIf (cfg.litestream.enable && cfg.litestream.environmentFile != null) {
221
+
serviceConfig = {
222
+
EnvironmentFile = cfg.litestream.environmentFile;
223
+
};
224
+
};
225
+
226
+
# Create a group for accessing secrets
227
+
users.groups.headscale-secrets = {};
228
+
};
229
+
}
+257
modules/syncthing/default.nix
+257
modules/syncthing/default.nix
···
1
+
{ config, lib, pkgs, ... }:
2
+
3
+
with lib;
4
+
let
5
+
cfg = config.modules.syncthing;
6
+
7
+
# Helper function to create a serviceConfig entry if the condition is met
8
+
mkServiceConfigOption = name: value: mkIf (value != null) { "${name}" = value; };
9
+
10
+
# Construct the settings object for Syncthing
11
+
syncthingSettings = mkMerge [
12
+
# GUI configuration
13
+
(mkIf cfg.gui.enable {
14
+
gui = mkMerge [
15
+
(mkIf (cfg.gui.user != null) {
16
+
user = cfg.gui.user;
17
+
})
18
+
];
19
+
})
20
+
21
+
# Devices configuration
22
+
(mkIf (cfg.devices != {}) {
23
+
devices = mapAttrs (name: device: {
24
+
id = device.id;
25
+
} // optionalAttrs (device.name != null) {
26
+
name = device.name;
27
+
} // optionalAttrs (device.addresses != []) {
28
+
addresses = device.addresses;
29
+
}) cfg.devices;
30
+
})
31
+
32
+
# Folders configuration
33
+
(mkIf (cfg.folders != {}) {
34
+
folders = mapAttrs (name: folder: {
35
+
path = folder.path;
36
+
devices = folder.devices;
37
+
} // optionalAttrs (folder.ignorePerms != null) {
38
+
ignorePerms = folder.ignorePerms;
39
+
} // optionalAttrs (folder.type != null) {
40
+
type = folder.type;
41
+
} // optionalAttrs (folder.rescanIntervalS != null) {
42
+
rescanIntervalS = folder.rescanIntervalS;
43
+
} // optionalAttrs (folder.versioning != null) {
44
+
versioning = folder.versioning;
45
+
}) cfg.folders;
46
+
})
47
+
48
+
# Extra options
49
+
cfg.extraOptions
50
+
];
51
+
in
52
+
{
53
+
options = {
54
+
modules.syncthing = {
55
+
enable = mkEnableOption "Deploy syncthing";
56
+
57
+
openDefaultPorts = mkOption {
58
+
type = types.bool;
59
+
default = true;
60
+
description = "Open ports in the firewall for Syncthing";
61
+
};
62
+
63
+
disableDefaultFolder = mkOption {
64
+
type = types.bool;
65
+
default = true;
66
+
description = "Don't create default ~/Sync folder";
67
+
};
68
+
69
+
gui = {
70
+
enable = mkEnableOption "Enable GUI configuration";
71
+
72
+
user = mkOption {
73
+
type = types.nullOr types.str;
74
+
default = null;
75
+
description = "GUI username";
76
+
example = "myuser";
77
+
};
78
+
79
+
passwordFile = mkOption {
80
+
type = types.nullOr types.path;
81
+
default = null;
82
+
description = "Path to file containing GUI password";
83
+
example = "config.age.secrets.syncthing-gui-password.path";
84
+
};
85
+
};
86
+
87
+
identity = {
88
+
keyPath = mkOption {
89
+
type = types.nullOr types.path;
90
+
default = null;
91
+
description = "Path to Syncthing private key for stable device ID";
92
+
example = "config.age.secrets.syncthing-key.path";
93
+
};
94
+
95
+
certPath = mkOption {
96
+
type = types.nullOr types.path;
97
+
default = null;
98
+
description = "Path to Syncthing certificate for stable device ID";
99
+
example = "config.age.secrets.syncthing-cert.path";
100
+
};
101
+
};
102
+
103
+
devices = mkOption {
104
+
type = types.attrsOf (types.submodule {
105
+
options = {
106
+
id = mkOption {
107
+
type = types.str;
108
+
description = "Device ID";
109
+
example = "DMWVMM6-MKEQVB4-I4UZTRH-5A6E24O-XHQTL3K-AAI5R5L-MXNMUGX-QTGRHQ2";
110
+
};
111
+
112
+
name = mkOption {
113
+
type = types.nullOr types.str;
114
+
default = null;
115
+
description = "Device name (optional)";
116
+
};
117
+
118
+
addresses = mkOption {
119
+
type = types.listOf types.str;
120
+
default = [];
121
+
description = "Device addresses";
122
+
example = [ "tcp://192.168.1.100:22000" ];
123
+
};
124
+
};
125
+
});
126
+
default = {};
127
+
description = "Syncthing devices configuration";
128
+
example = {
129
+
"laptop" = {
130
+
id = "DMWVMM6-MKEQVB4-I4UZTRH-5A6E24O-XHQTL3K-AAI5R5L-MXNMUGX-QTGRHQ2";
131
+
};
132
+
"phone" = {
133
+
id = "ANOTHER-DEVICE-ID-GOES-HERE";
134
+
addresses = [ "tcp://192.168.1.101:22000" ];
135
+
};
136
+
};
137
+
};
138
+
139
+
folders = mkOption {
140
+
type = types.attrsOf (types.submodule {
141
+
options = {
142
+
path = mkOption {
143
+
type = types.str;
144
+
description = "Local folder path";
145
+
example = "/home/myuser/Documents";
146
+
};
147
+
148
+
devices = mkOption {
149
+
type = types.listOf (types.either types.str (types.submodule {
150
+
options = {
151
+
name = mkOption {
152
+
type = types.str;
153
+
description = "Device name";
154
+
};
155
+
156
+
encryptionPasswordFile = mkOption {
157
+
type = types.path;
158
+
description = "Path to file containing encryption password";
159
+
};
160
+
};
161
+
}));
162
+
default = [];
163
+
description = "List of devices that can access this folder";
164
+
example = [ "laptop" "phone" ];
165
+
};
166
+
167
+
ignorePerms = mkOption {
168
+
type = types.nullOr types.bool;
169
+
default = null;
170
+
description = "Whether to ignore file permissions";
171
+
};
172
+
173
+
type = mkOption {
174
+
type = types.nullOr (types.enum [ "sendreceive" "sendonly" "receiveonly" ]);
175
+
default = null;
176
+
description = "Folder type";
177
+
};
178
+
179
+
rescanIntervalS = mkOption {
180
+
type = types.nullOr types.int;
181
+
default = null;
182
+
description = "Rescan interval in seconds";
183
+
};
184
+
185
+
versioning = mkOption {
186
+
type = types.nullOr (types.submodule {
187
+
options = {
188
+
type = mkOption {
189
+
type = types.enum [ "external" "simple" "staggered" "trashcan" ];
190
+
description = "Versioning type";
191
+
};
192
+
193
+
params = mkOption {
194
+
type = types.attrsOf types.str;
195
+
default = {};
196
+
description = "Versioning parameters";
197
+
};
198
+
};
199
+
});
200
+
default = null;
201
+
description = "Folder versioning configuration";
202
+
};
203
+
};
204
+
});
205
+
default = {};
206
+
description = "Syncthing folders configuration";
207
+
example = {
208
+
"Documents" = {
209
+
path = "/home/myuser/Documents";
210
+
devices = [ "laptop" "phone" ];
211
+
ignorePerms = false;
212
+
};
213
+
"Sensitive" = {
214
+
path = "/home/myuser/Sensitive";
215
+
devices = [
216
+
"laptop"
217
+
{
218
+
name = "phone";
219
+
encryptionPasswordFile = "/run/secrets/syncthing-sensitive-password";
220
+
}
221
+
];
222
+
};
223
+
};
224
+
};
225
+
226
+
extraOptions = mkOption {
227
+
type = types.attrsOf types.anything;
228
+
default = {};
229
+
description = "Additional Syncthing configuration options";
230
+
};
231
+
};
232
+
};
233
+
234
+
config = mkIf cfg.enable {
235
+
services.syncthing = {
236
+
enable = true;
237
+
openDefaultPorts = cfg.openDefaultPorts;
238
+
# Set stable identity if provided
239
+
key = mkIf (cfg.identity.keyPath != null) cfg.identity.keyPath;
240
+
cert = mkIf (cfg.identity.certPath != null) cfg.identity.certPath;
241
+
# Combine all settings
242
+
settings = syncthingSettings;
243
+
};
244
+
245
+
# Configure systemd service options collectively
246
+
systemd.services.syncthing = {
247
+
# Add environment variable to disable default folder creation
248
+
environment.STNODEFAULTFOLDER = mkIf cfg.disableDefaultFolder "true";
249
+
250
+
# Add supplementary groups for secret access
251
+
serviceConfig.SupplementaryGroups = [ "syncthing-secrets" ];
252
+
};
253
+
254
+
# Create a group for accessing secrets
255
+
users.groups.syncthing-secrets = {};
256
+
};
257
+
}
+11
secrets/headscale-oidc-key.path
+11
secrets/headscale-oidc-key.path
···
1
+
age-encryption.org/v1
2
+
-> ssh-ed25519 i9wBeA DynOTJFDKsSyHKTG9XFAAcZf/T//KKyK8UG4aGgVH2c
3
+
o+ggJe/HZmPU+Ezw4u4m+l9bQ1furG7G4Oo7xS8PMAs
4
+
-> ssh-ed25519 UbxDgg b1XiosrWXL9WI1B7YnNSw16l1p4oa3zjDCCgkU/FxiU
5
+
MY8oubHMth/wDKn9kNOUkaY9ODvrKIn7DeZTuGxj4/g
6
+
-> ssh-ed25519 YYzA7Q 6ql+gutJfteQM75WL6ywEDA1+fIcYSpLPaTSKhqE1ic
7
+
tbwXx/feysvpOrxwpDi5B5PveSIbFH0qSsV6/xmo4hk
8
+
-> ssh-ed25519 3RWqPQ hNVnobsB1OB9woXtn1T1tXJL+1Dbasc9N2tjZdXa0Bw
9
+
9HlWIX7aroc8kTUW3rPlxvMSTSGJXbMcOEipdoQqnbw
10
+
--- h8toQGhp/wUgMkJ+RU0bV7E6pHRUM8mKLPcrDmbZ5NQ
11
+
!Ŵ�j֖n$�Z���$s9f���ωk�.ro�`�CU>˻�R�F;H;�}J�(�0��� U�YP