nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1{ lib, stdenv, fetchurl, fetchpatch
2, bzip2
3, expat
4, libffi
5, gdbm
6, xz
7, mailcap, mimetypesSupport ? true
8, ncurses
9, openssl
10, readline
11, sqlite
12, tcl ? null, tk ? null, tix ? null, libX11 ? null, xorgproto ? null, x11Support ? false
13, bluez ? null, bluezSupport ? false
14, zlib
15, tzdata ? null
16, self
17, configd
18, autoreconfHook
19, autoconf-archive
20, pkg-config
21, python-setup-hook
22, nukeReferences
23# For the Python package set
24, packageOverrides ? (self: super: {})
25, pkgsBuildBuild
26, pkgsBuildHost
27, pkgsBuildTarget
28, pkgsHostHost
29, pkgsTargetTarget
30, sourceVersion
31, sha256
32, passthruFun
33, bash
34, stripConfig ? false
35, stripIdlelib ? false
36, stripTests ? false
37, stripTkinter ? false
38, rebuildBytecode ? true
39, stripBytecode ? true
40, includeSiteCustomize ? true
41, static ? stdenv.hostPlatform.isStatic
42, enableOptimizations ? false
43# enableNoSemanticInterposition is a subset of the enableOptimizations flag that doesn't harm reproducibility.
44# clang starts supporting `-fno-sematic-interposition` with version 10
45, enableNoSemanticInterposition ? (!stdenv.cc.isClang || (stdenv.cc.isClang && lib.versionAtLeast stdenv.cc.version "10"))
46# enableLTO is a subset of the enableOptimizations flag that doesn't harm reproducibility.
47# enabling LTO on 32bit arch causes downstream packages to fail when linking
48# enabling LTO on *-darwin causes python3 to fail when linking.
49, enableLTO ? stdenv.is64bit && stdenv.isLinux
50, reproducibleBuild ? false
51, pythonAttr ? "python${sourceVersion.major}${sourceVersion.minor}"
52} @ inputs:
53
54# Note: this package is used for bootstrapping fetchurl, and thus
55# cannot use fetchpatch! All mutable patches (generated by GitHub or
56# cgit) that are needed here should be included directly in Nixpkgs as
57# files.
58
59assert x11Support -> tcl != null
60 && tk != null
61 && xorgproto != null
62 && libX11 != null;
63
64assert bluezSupport -> bluez != null;
65
66assert lib.assertMsg (enableOptimizations -> (!stdenv.cc.isClang))
67 "Optimizations with clang are not supported. configure: error: llvm-profdata is required for a --enable-optimizations build but could not be found.";
68
69assert lib.assertMsg (reproducibleBuild -> stripBytecode)
70 "Deterministic builds require stripping bytecode.";
71
72assert lib.assertMsg (reproducibleBuild -> (!enableOptimizations))
73 "Deterministic builds are not achieved when optimizations are enabled.";
74
75assert lib.assertMsg (reproducibleBuild -> (!rebuildBytecode))
76 "Deterministic builds are not achieved when (default unoptimized) bytecode is created.";
77
78with lib;
79
80let
81 buildPackages = pkgsBuildHost;
82 inherit (passthru) pythonForBuild;
83
84 tzdataSupport = tzdata != null && passthru.pythonAtLeast "3.9";
85
86 passthru = let
87 # When we override the interpreter we also need to override the spliced versions of the interpreter
88 inputs' = lib.filterAttrs (_: v: ! lib.isDerivation v) inputs;
89 override = attr: let python = attr.override (inputs' // { self = python; }); in python;
90 in passthruFun rec {
91 inherit self sourceVersion packageOverrides;
92 implementation = "cpython";
93 libPrefix = "python${pythonVersion}";
94 executable = libPrefix;
95 pythonVersion = with sourceVersion; "${major}.${minor}";
96 sitePackages = "lib/${libPrefix}/site-packages";
97 inherit hasDistutilsCxxPatch;
98 pythonOnBuildForBuild = override pkgsBuildBuild.${pythonAttr};
99 pythonOnBuildForHost = override pkgsBuildHost.${pythonAttr};
100 pythonOnBuildForTarget = override pkgsBuildTarget.${pythonAttr};
101 pythonOnHostForHost = override pkgsHostHost.${pythonAttr};
102 pythonOnTargetForTarget = if lib.hasAttr pythonAttr pkgsTargetTarget then (override pkgsTargetTarget.${pythonAttr}) else {};
103 };
104
105 version = with sourceVersion; "${major}.${minor}.${patch}${suffix}";
106
107 strictDeps = true;
108
109 nativeBuildInputs = optionals (!stdenv.isDarwin) [
110 autoreconfHook
111 pkg-config
112 autoconf-archive # needed for AX_CHECK_COMPILE_FLAG
113 ] ++ [
114 nukeReferences
115 ] ++ optionals (stdenv.hostPlatform != stdenv.buildPlatform) [
116 buildPackages.stdenv.cc
117 pythonForBuild
118 ] ++ optionals (stdenv.cc.isClang && enableLTO) [
119 stdenv.cc.cc.libllvm.out
120 ];
121
122 buildInputs = filter (p: p != null) ([
123 zlib bzip2 expat xz libffi gdbm sqlite readline ncurses openssl ]
124 ++ optionals x11Support [ tcl tk libX11 xorgproto ]
125 ++ optionals (bluezSupport && stdenv.isLinux) [ bluez ]
126 ++ optionals stdenv.isDarwin [ configd ])
127 ++ optionals tzdataSupport [ tzdata ]; # `zoneinfo` module
128
129 hasDistutilsCxxPatch = !(stdenv.cc.isGNU or false);
130
131 pythonForBuildInterpreter = if stdenv.hostPlatform == stdenv.buildPlatform then
132 "$out/bin/python"
133 else pythonForBuild.interpreter;
134
135 # The CPython interpreter contains a _sysconfigdata_<platform specific suffix>
136 # module that is imported by the sysconfig and distutils.sysconfig modules.
137 # The sysconfigdata module is generated at build time and contains settings
138 # required for building Python extension modules, such as include paths and
139 # other compiler flags. By default, the sysconfigdata module is loaded from
140 # the currently running interpreter (ie. the build platform interpreter), but
141 # when cross-compiling we want to load it from the host platform interpreter.
142 # This can be done using the _PYTHON_SYSCONFIGDATA_NAME environment variable.
143 # The _PYTHON_HOST_PLATFORM variable also needs to be set to get the correct
144 # platform suffix on extension modules. The correct values for these variables
145 # are not documented, and must be derived from the configure script (see links
146 # below).
147 sysconfigdataHook = with stdenv.hostPlatform; with passthru; let
148 # https://github.com/python/cpython/blob/e488e300f5c01289c10906c2e53a8e43d6de32d8/configure.ac#L428
149 # The configure script uses "arm" as the CPU name for all 32-bit ARM
150 # variants when cross-compiling, but native builds include the version
151 # suffix, so we do the same.
152 pythonHostPlatform = "${parsed.kernel.name}-${parsed.cpu.name}";
153
154 # https://github.com/python/cpython/blob/e488e300f5c01289c10906c2e53a8e43d6de32d8/configure.ac#L724
155 multiarchCpu =
156 if isAarch32 then
157 if parsed.cpu.significantByte.name == "littleEndian" then "arm" else "armeb"
158 else if isx86_32 then "i386"
159 else parsed.cpu.name;
160 pythonAbiName =
161 # python's build doesn't differentiate between musl and glibc in its
162 # abi detection, our wrapper should match.
163 if stdenv.hostPlatform.isMusl then
164 replaceStrings [ "musl" ] [ "gnu" ] parsed.abi.name
165 else parsed.abi.name;
166 multiarch =
167 if isDarwin then "darwin"
168 else "${multiarchCpu}-${parsed.kernel.name}-${pythonAbiName}";
169
170 abiFlags = optionalString (isPy36 || isPy37) "m";
171
172 # https://github.com/python/cpython/blob/e488e300f5c01289c10906c2e53a8e43d6de32d8/configure.ac#L78
173 pythonSysconfigdataName = "_sysconfigdata_${abiFlags}_${parsed.kernel.name}_${multiarch}";
174 in ''
175 sysconfigdataHook() {
176 if [ "$1" = '${placeholder "out"}' ]; then
177 export _PYTHON_HOST_PLATFORM='${pythonHostPlatform}'
178 export _PYTHON_SYSCONFIGDATA_NAME='${pythonSysconfigdataName}'
179 fi
180 }
181
182 addEnvHooks "$hostOffset" sysconfigdataHook
183 '';
184
185in with passthru; stdenv.mkDerivation {
186 pname = "python3";
187 inherit version;
188
189 inherit buildInputs nativeBuildInputs;
190
191 src = fetchurl {
192 url = with sourceVersion; "https://www.python.org/ftp/python/${major}.${minor}.${patch}/Python-${version}.tar.xz";
193 inherit sha256;
194 };
195
196 prePatch = optionalString stdenv.isDarwin ''
197 substituteInPlace configure --replace '`/usr/bin/arch`' '"i386"'
198 '' + optionalString (pythonOlder "3.9" && stdenv.isDarwin && x11Support) ''
199 # Broken on >= 3.9; replaced with ./3.9/darwin-tcl-tk.patch
200 substituteInPlace setup.py --replace /Library/Frameworks /no-such-path
201 '';
202
203 patches = [
204 # Disable the use of ldconfig in ctypes.util.find_library (since
205 # ldconfig doesn't work on NixOS), and don't use
206 # ctypes.util.find_library during the loading of the uuid module
207 # (since it will do a futile invocation of gcc (!) to find
208 # libuuid, slowing down program startup a lot).
209 (./. + "/${sourceVersion.major}.${sourceVersion.minor}/no-ldconfig.patch")
210 # Make sure that the virtualenv activation scripts are
211 # owner-writable, so venvs can be recreated without permission
212 # errors.
213 ./virtualenv-permissions.patch
214 ] ++ optionals mimetypesSupport [
215 # Make the mimetypes module refer to the right file
216 ./mimetypes.patch
217 ] ++ optionals (isPy35 || isPy36) [
218 # Determinism: Write null timestamps when compiling python files.
219 ./3.5/force_bytecode_determinism.patch
220 ] ++ optionals isPy35 [
221 # Backports support for LD_LIBRARY_PATH from 3.6
222 ./3.5/ld_library_path.patch
223 ] ++ optionals (isPy35 || isPy36 || isPy37) [
224 # Backport a fix for discovering `rpmbuild` command when doing `python setup.py bdist_rpm` to 3.5, 3.6, 3.7.
225 # See: https://bugs.python.org/issue11122
226 ./3.7/fix-hardcoded-path-checking-for-rpmbuild.patch
227 # The workaround is for unittests on Win64, which we don't support.
228 # It does break aarch64-darwin, which we do support. See:
229 # * https://bugs.python.org/issue35523
230 # * https://github.com/python/cpython/commit/e6b247c8e524
231 ./3.7/no-win64-workaround.patch
232 ] ++ optionals (pythonAtLeast "3.7") [
233 # Fix darwin build https://bugs.python.org/issue34027
234 ./3.7/darwin-libutil.patch
235 ] ++ optionals (pythonOlder "3.8") [
236 # Backport from CPython 3.8 of a good list of tests to run for PGO.
237 (
238 if isPy36 || isPy37 then
239 ./3.6/profile-task.patch
240 else
241 ./3.5/profile-task.patch
242 )
243 ] ++ optionals (pythonAtLeast "3.9" && pythonOlder "3.11" && stdenv.isDarwin) [
244 # Stop checking for TCL/TK in global macOS locations
245 ./3.9/darwin-tcl-tk.patch
246 ] ++ optionals (isPy3k && hasDistutilsCxxPatch) [
247 # Fix for http://bugs.python.org/issue1222585
248 # Upstream distutils is calling C compiler to compile C++ code, which
249 # only works for GCC and Apple Clang. This makes distutils to call C++
250 # compiler when needed.
251 (
252 if isPy35 then
253 ./3.5/python-3.x-distutils-C++.patch
254 else if pythonAtLeast "3.7" && pythonOlder "3.11" then
255 ./3.7/python-3.x-distutils-C++.patch
256 else if pythonAtLeast "3.11" then
257 ./3.11/python-3.x-distutils-C++.patch
258 else
259 fetchpatch {
260 url = "https://bugs.python.org/file48016/python-3.x-distutils-C++.patch";
261 sha256 = "1h18lnpx539h5lfxyk379dxwr8m2raigcjixkf133l4xy3f4bzi2";
262 }
263 )
264 ] ++ [
265 # LDSHARED now uses $CC instead of gcc. Fixes cross-compilation of extension modules.
266 ./3.8/0001-On-all-posix-systems-not-just-Darwin-set-LDSHARED-if.patch
267 # Use sysconfigdata to find headers. Fixes cross-compilation of extension modules.
268 (
269 if isPy36 then
270 ./3.6/fix-finding-headers-when-cross-compiling.patch
271 else
272 ./3.7/fix-finding-headers-when-cross-compiling.patch
273 )
274 ] ++ optionals (isPy36) [
275 # Backport a fix for ctypes.util.find_library.
276 ./3.6/find_library.patch
277 ];
278
279 postPatch = ''
280 substituteInPlace Lib/subprocess.py \
281 --replace "'/bin/sh'" "'${bash}/bin/sh'"
282 '' + optionalString mimetypesSupport ''
283 substituteInPlace Lib/mimetypes.py \
284 --replace "@mime-types@" "${mailcap}"
285 '' + optionalString (x11Support && (tix != null)) ''
286 substituteInPlace "Lib/tkinter/tix.py" --replace "os.environ.get('TIX_LIBRARY')" "os.environ.get('TIX_LIBRARY') or '${tix}/lib'"
287 '';
288
289 CPPFLAGS = concatStringsSep " " (map (p: "-I${getDev p}/include") buildInputs);
290 LDFLAGS = concatStringsSep " " (map (p: "-L${getLib p}/lib") buildInputs);
291 LIBS = "${optionalString (!stdenv.isDarwin) "-lcrypt"}";
292 NIX_LDFLAGS = lib.optionalString (stdenv.cc.isGNU && !stdenv.hostPlatform.isStatic) ({
293 "glibc" = "-lgcc_s";
294 "musl" = "-lgcc_eh";
295 }."${stdenv.hostPlatform.libc}" or "");
296 # Determinism: We fix the hashes of str, bytes and datetime objects.
297 PYTHONHASHSEED=0;
298
299 configureFlags = [
300 "--without-ensurepip"
301 "--with-system-expat"
302 "--with-system-ffi"
303 ] ++ optionals (!static) [
304 "--enable-shared"
305 ] ++ optionals enableOptimizations [
306 "--enable-optimizations"
307 ] ++ optionals enableLTO [
308 "--with-lto"
309 ] ++ optionals (pythonOlder "3.7") [
310 # This is unconditionally true starting in CPython 3.7.
311 "--with-threads"
312 ] ++ optionals (sqlite != null && isPy3k) [
313 "--enable-loadable-sqlite-extensions"
314 ] ++ optionals (openssl != null) [
315 "--with-openssl=${openssl.dev}"
316 ] ++ optionals (stdenv.hostPlatform != stdenv.buildPlatform) [
317 "ac_cv_buggy_getaddrinfo=no"
318 # Assume little-endian IEEE 754 floating point when cross compiling
319 "ac_cv_little_endian_double=yes"
320 "ac_cv_big_endian_double=no"
321 "ac_cv_mixed_endian_double=no"
322 "ac_cv_x87_double_rounding=yes"
323 "ac_cv_tanh_preserves_zero_sign=yes"
324 # Generally assume that things are present and work
325 "ac_cv_posix_semaphores_enabled=yes"
326 "ac_cv_broken_sem_getvalue=no"
327 "ac_cv_wchar_t_signed=yes"
328 "ac_cv_rshift_extends_sign=yes"
329 "ac_cv_broken_nice=no"
330 "ac_cv_broken_poll=no"
331 "ac_cv_working_tzset=yes"
332 "ac_cv_have_long_long_format=yes"
333 "ac_cv_have_size_t_format=yes"
334 "ac_cv_computed_gotos=yes"
335 "ac_cv_file__dev_ptmx=yes"
336 "ac_cv_file__dev_ptc=yes"
337 ] ++ optionals stdenv.hostPlatform.isLinux [
338 # Never even try to use lchmod on linux,
339 # don't rely on detecting glibc-isms.
340 "ac_cv_func_lchmod=no"
341 ] ++ optionals tzdataSupport [
342 "--with-tzpath=${tzdata}/share/zoneinfo"
343 ] ++ optional static "LDFLAGS=-static";
344
345 preConfigure = ''
346 for i in /usr /sw /opt /pkg; do # improve purity
347 substituteInPlace ./setup.py --replace $i /no-such-path
348 done
349 '' + optionalString stdenv.isDarwin ''
350 # Override the auto-detection in setup.py, which assumes a universal build
351 export PYTHON_DECIMAL_WITH_MACHINE=${if stdenv.isAarch64 then "uint128" else "x64"}
352 '' + optionalString (isPy3k && pythonOlder "3.7") ''
353 # Determinism: The interpreter is patched to write null timestamps when compiling Python files
354 # so Python doesn't try to update the bytecode when seeing frozen timestamps in Nix's store.
355 export DETERMINISTIC_BUILD=1;
356 '' + optionalString stdenv.hostPlatform.isMusl ''
357 export NIX_CFLAGS_COMPILE+=" -DTHREAD_STACK_SIZE=0x100000"
358 '' +
359
360 # enableNoSemanticInterposition essentially sets that CFLAG -fno-semantic-interposition
361 # which changes how symbols are looked up. This essentially means we can't override
362 # libpython symbols via LD_PRELOAD anymore. This is common enough as every build
363 # that uses --enable-optimizations has the same "issue".
364 #
365 # The Fedora wiki has a good article about their journey towards enabling this flag:
366 # https://fedoraproject.org/wiki/Changes/PythonNoSemanticInterpositionSpeedup
367 optionalString enableNoSemanticInterposition ''
368 export CFLAGS_NODIST="-fno-semantic-interposition"
369 '';
370
371 setupHook = python-setup-hook sitePackages;
372
373 postInstall = let
374 # References *not* to nuke from (sys)config files
375 keep-references = concatMapStringsSep " " (val: "-e ${val}") ([
376 (placeholder "out")
377 ] ++ optionals tzdataSupport [
378 tzdata
379 ]);
380 in ''
381 # needed for some packages, especially packages that backport functionality
382 # to 2.x from 3.x
383 for item in $out/lib/${libPrefix}/test/*; do
384 if [[ "$item" != */test_support.py*
385 && "$item" != */test/support
386 && "$item" != */test/libregrtest
387 && "$item" != */test/regrtest.py* ]]; then
388 rm -rf "$item"
389 else
390 echo $item
391 fi
392 done
393 touch $out/lib/${libPrefix}/test/__init__.py
394
395 ln -s "$out/include/${executable}m" "$out/include/${executable}"
396
397 # Determinism: Windows installers were not deterministic.
398 # We're also not interested in building Windows installers.
399 find "$out" -name 'wininst*.exe' | xargs -r rm -f
400
401 # Use Python3 as default python
402 ln -s "$out/bin/idle3" "$out/bin/idle"
403 ln -s "$out/bin/pydoc3" "$out/bin/pydoc"
404 ln -s "$out/bin/python3" "$out/bin/python"
405 ln -s "$out/bin/python3-config" "$out/bin/python-config"
406 ln -s "$out/lib/pkgconfig/python3.pc" "$out/lib/pkgconfig/python.pc"
407
408 # Get rid of retained dependencies on -dev packages, and remove
409 # some $TMPDIR references to improve binary reproducibility.
410 # Note that the .pyc file of _sysconfigdata.py should be regenerated!
411 for i in $out/lib/${libPrefix}/_sysconfigdata*.py $out/lib/${libPrefix}/config-${sourceVersion.major}${sourceVersion.minor}*/Makefile; do
412 sed -i $i -e "s|$TMPDIR|/no-such-path|g"
413 done
414
415 # Further get rid of references. https://github.com/NixOS/nixpkgs/issues/51668
416 find $out/lib/python*/config-* -type f -print -exec nuke-refs ${keep-references} '{}' +
417 find $out/lib -name '_sysconfigdata*.py*' -print -exec nuke-refs ${keep-references} '{}' +
418
419 # Make the sysconfigdata module accessible on PYTHONPATH
420 # This allows build Python to import host Python's sysconfigdata
421 mkdir -p "$out/${sitePackages}"
422 ln -s "$out/lib/${libPrefix}/"_sysconfigdata*.py "$out/${sitePackages}/"
423
424 # debug info can't be separated from a static library and would otherwise be
425 # left in place by a separateDebugInfo build. force its removal here to save
426 # space in output.
427 $STRIP -S $out/lib/${libPrefix}/config-*/libpython*.a || true
428 '' + optionalString stripConfig ''
429 rm -R $out/bin/python*-config $out/lib/python*/config-*
430 '' + optionalString stripIdlelib ''
431 # Strip IDLE (and turtledemo, which uses it)
432 rm -R $out/bin/idle* $out/lib/python*/{idlelib,turtledemo}
433 '' + optionalString stripTkinter ''
434 rm -R $out/lib/python*/tkinter
435 '' + optionalString stripTests ''
436 # Strip tests
437 rm -R $out/lib/python*/test $out/lib/python*/**/test{,s}
438 '' + optionalString includeSiteCustomize ''
439 # Include a sitecustomize.py file
440 cp ${../sitecustomize.py} $out/${sitePackages}/sitecustomize.py
441
442 '' + optionalString stripBytecode ''
443 # Determinism: deterministic bytecode
444 # First we delete all old bytecode.
445 find $out -type d -name __pycache__ -print0 | xargs -0 -I {} rm -rf "{}"
446 '' + optionalString rebuildBytecode ''
447 # Python 3.7 implements PEP 552, introducing support for deterministic bytecode.
448 # compileall uses the therein introduced checked-hash method by default when
449 # `SOURCE_DATE_EPOCH` is set.
450 # We exclude lib2to3 because that's Python 2 code which fails
451 # We build 3 levels of optimized bytecode. Note the default level, without optimizations,
452 # is not reproducible yet. https://bugs.python.org/issue29708
453 # Not creating bytecode will result in a large performance loss however, so we do build it.
454 find $out -name "*.py" | ${pythonForBuildInterpreter} -m compileall -q -f -x "lib2to3" -i -
455 find $out -name "*.py" | ${pythonForBuildInterpreter} -O -m compileall -q -f -x "lib2to3" -i -
456 find $out -name "*.py" | ${pythonForBuildInterpreter} -OO -m compileall -q -f -x "lib2to3" -i -
457 '' + ''
458 # *strip* shebang from libpython gdb script - it should be dual-syntax and
459 # interpretable by whatever python the gdb in question is using, which may
460 # not even match the major version of this python. doing this after the
461 # bytecode compilations for the same reason - we don't want bytecode generated.
462 mkdir -p $out/share/gdb
463 sed '/^#!/d' Tools/gdb/libpython.py > $out/share/gdb/libpython.py
464 '';
465
466 preFixup = lib.optionalString (stdenv.hostPlatform != stdenv.buildPlatform) ''
467 # Ensure patch-shebangs uses shebangs of host interpreter.
468 export PATH=${lib.makeBinPath [ "$out" bash ]}:$PATH
469 '';
470
471 # Add CPython specific setup-hook that configures distutils.sysconfig to
472 # always load sysconfigdata from host Python.
473 postFixup = lib.optionalString (!stdenv.hostPlatform.isDarwin) ''
474 cat << "EOF" >> "$out/nix-support/setup-hook"
475 ${sysconfigdataHook}
476 EOF
477 '';
478
479 # Enforce that we don't have references to the OpenSSL -dev package, which we
480 # explicitly specify in our configure flags above.
481 disallowedReferences =
482 lib.optionals (openssl != null && !static) [ openssl.dev ]
483 ++ lib.optionals (stdenv.hostPlatform != stdenv.buildPlatform) [
484 # Ensure we don't have references to build-time packages.
485 # These typically end up in shebangs.
486 pythonForBuild buildPackages.bash
487 ];
488
489 separateDebugInfo = true;
490
491 inherit passthru;
492
493 enableParallelBuilding = true;
494
495 meta = {
496 homepage = "http://python.org";
497 description = "A high-level dynamically-typed programming language";
498 longDescription = ''
499 Python is a remarkably powerful dynamic programming language that
500 is used in a wide variety of application domains. Some of its key
501 distinguishing features include: clear, readable syntax; strong
502 introspection capabilities; intuitive object orientation; natural
503 expression of procedural code; full modularity, supporting
504 hierarchical packages; exception-based error handling; and very
505 high level dynamic data types.
506 '';
507 license = licenses.psfl;
508 platforms = with platforms; linux ++ darwin;
509 maintainers = with maintainers; [ fridh ];
510 };
511}