| author | |
| committer | |
| log | df507edffe6c1087b5f4786cb64ccaffd02b6848 |
| tree | 2134ba2f867db8bf4fbfab2b1aaed0f5759c0db9 |
| parent | 79757f233d9bfc646caa13d20243266a19bbdf91 |
| parent | b6ce0cce69e4bf37509f99040abda4ca92bec6cb |
| signature |
Fixes link-tests and `atomicSymLink` on Windows13 files changed, 88 insertions(+), 79 deletions(-)
ci/azure/pipelines.yml+1-1| ... | @@ -103,7 +103,7 @@ jobs: | ... | @@ -103,7 +103,7 @@ jobs: |
| 103 | #& "$ZIGINSTALLDIR\bin\zig.exe" test "..\test\behavior.zig" -fno-stage1 -fLLVM -I "..\test" 2>&1 | 103 | #& "$ZIGINSTALLDIR\bin\zig.exe" test "..\test\behavior.zig" -fno-stage1 -fLLVM -I "..\test" 2>&1 |
| 104 | #CheckLastExitCode | 104 | #CheckLastExitCode |
| 105 | 105 | ||
| 106 | & "$ZIGINSTALLDIR\bin\zig.exe" build test-toolchain -Dskip-non-native -Dskip-stage2-tests 2>&1 | 106 | & "$ZIGINSTALLDIR\bin\zig.exe" build test-toolchain -Dskip-non-native -Dskip-stage2-tests -Domit-stage2 2>&1 |
| 107 | CheckLastExitCode | 107 | CheckLastExitCode |
| 108 | & "$ZIGINSTALLDIR\bin\zig.exe" build test-std -Dskip-non-native 2>&1 | 108 | & "$ZIGINSTALLDIR\bin\zig.exe" build test-std -Dskip-non-native 2>&1 |
| 109 | CheckLastExitCode | 109 | CheckLastExitCode |
lib/std/os.zig+1| ... | @@ -2651,6 +2651,7 @@ pub fn renameatW( | ... | @@ -2651,6 +2651,7 @@ pub fn renameatW( |
| 2651 | .creation = windows.FILE_OPEN, | 2651 | .creation = windows.FILE_OPEN, |
| 2652 | .io_mode = .blocking, | 2652 | .io_mode = .blocking, |
| 2653 | .filter = .any, // This function is supposed to rename both files and directories. | 2653 | .filter = .any, // This function is supposed to rename both files and directories. |
| 2654 | .follow_symlinks = false, | ||
| 2654 | }) catch |err| switch (err) { | 2655 | }) catch |err| switch (err) { |
| 2655 | error.WouldBlock => unreachable, // Not possible without `.share_access_nonblocking = true`. | 2656 | error.WouldBlock => unreachable, // Not possible without `.share_access_nonblocking = true`. |
| 2656 | else => |e| return e, | 2657 | else => |e| return e, |
test/link.zig+30-30| ... | @@ -3,11 +3,6 @@ const builtin = @import("builtin"); | ... | @@ -3,11 +3,6 @@ const builtin = @import("builtin"); |
| 3 | const tests = @import("tests.zig"); | 3 | const tests = @import("tests.zig"); |
| 4 | 4 | ||
| 5 | pub fn addCases(cases: *tests.StandaloneContext) void { | 5 | pub fn addCases(cases: *tests.StandaloneContext) void { |
| 6 | if (builtin.os.tag == .windows) { | ||
| 7 | // https://github.com/ziglang/zig/issues/12421 | ||
| 8 | return; | ||
| 9 | } | ||
| 10 | |||
| 11 | cases.addBuildFile("test/link/bss/build.zig", .{ | 6 | cases.addBuildFile("test/link/bss/build.zig", .{ |
| 12 | .build_modes = false, // we only guarantee zerofill for undefined in Debug | 7 | .build_modes = false, // we only guarantee zerofill for undefined in Debug |
| 13 | }); | 8 | }); |
| ... | @@ -28,11 +23,12 @@ pub fn addCases(cases: *tests.StandaloneContext) void { | ... | @@ -28,11 +23,12 @@ pub fn addCases(cases: *tests.StandaloneContext) void { |
| 28 | .build_modes = true, | 23 | .build_modes = true, |
| 29 | }); | 24 | }); |
| 30 | 25 | ||
| 31 | cases.addBuildFile("test/link/tls/build.zig", .{ | 26 | addWasmCases(cases); |
| 32 | .build_modes = true, | 27 | addMachOCases(cases); |
| 33 | }); | 28 | } |
| 34 | 29 | ||
| 35 | cases.addBuildFile("test/link/wasm/type/build.zig", .{ | 30 | fn addWasmCases(cases: *tests.StandaloneContext) void { |
| 31 | cases.addBuildFile("test/link/wasm/bss/build.zig", .{ | ||
| 36 | .build_modes = true, | 32 | .build_modes = true, |
| 37 | .requires_stage2 = true, | 33 | .requires_stage2 = true, |
| 38 | }); | 34 | }); |
| ... | @@ -47,23 +43,13 @@ pub fn addCases(cases: *tests.StandaloneContext) void { | ... | @@ -47,23 +43,13 @@ pub fn addCases(cases: *tests.StandaloneContext) void { |
| 47 | .requires_stage2 = true, | 43 | .requires_stage2 = true, |
| 48 | }); | 44 | }); |
| 49 | 45 | ||
| 50 | cases.addBuildFile("test/link/wasm/bss/build.zig", .{ | 46 | cases.addBuildFile("test/link/wasm/type/build.zig", .{ |
| 51 | .build_modes = true, | 47 | .build_modes = true, |
| 52 | .requires_stage2 = true, | 48 | .requires_stage2 = true, |
| 53 | }); | 49 | }); |
| 50 | } | ||
| 54 | 51 | ||
| 55 | cases.addBuildFile("test/link/macho/entry/build.zig", .{ | 52 | fn addMachOCases(cases: *tests.StandaloneContext) void { |
| 56 | .build_modes = true, | ||
| 57 | }); | ||
| 58 | |||
| 59 | cases.addBuildFile("test/link/macho/pagezero/build.zig", .{ | ||
| 60 | .build_modes = false, | ||
| 61 | }); | ||
| 62 | |||
| 63 | cases.addBuildFile("test/link/macho/dylib/build.zig", .{ | ||
| 64 | .build_modes = true, | ||
| 65 | }); | ||
| 66 | |||
| 67 | cases.addBuildFile("test/link/macho/dead_strip/build.zig", .{ | 53 | cases.addBuildFile("test/link/macho/dead_strip/build.zig", .{ |
| 68 | .build_modes = false, | 54 | .build_modes = false, |
| 69 | }); | 55 | }); |
| ... | @@ -73,45 +59,59 @@ pub fn addCases(cases: *tests.StandaloneContext) void { | ... | @@ -73,45 +59,59 @@ pub fn addCases(cases: *tests.StandaloneContext) void { |
| 73 | .requires_macos_sdk = true, | 59 | .requires_macos_sdk = true, |
| 74 | }); | 60 | }); |
| 75 | 61 | ||
| 76 | cases.addBuildFile("test/link/macho/needed_library/build.zig", .{ | 62 | cases.addBuildFile("test/link/macho/dylib/build.zig", .{ |
| 77 | .build_modes = true, | 63 | .build_modes = true, |
| 78 | }); | 64 | }); |
| 79 | 65 | ||
| 80 | cases.addBuildFile("test/link/macho/weak_library/build.zig", .{ | 66 | cases.addBuildFile("test/link/macho/entry/build.zig", .{ |
| 81 | .build_modes = true, | 67 | .build_modes = true, |
| 82 | }); | 68 | }); |
| 83 | 69 | ||
| 84 | cases.addBuildFile("test/link/macho/needed_framework/build.zig", .{ | 70 | cases.addBuildFile("test/link/macho/headerpad/build.zig", .{ |
| 85 | .build_modes = true, | 71 | .build_modes = true, |
| 86 | .requires_macos_sdk = true, | 72 | .requires_macos_sdk = true, |
| 87 | }); | 73 | }); |
| 88 | 74 | ||
| 89 | cases.addBuildFile("test/link/macho/weak_framework/build.zig", .{ | 75 | cases.addBuildFile("test/link/macho/needed_framework/build.zig", .{ |
| 90 | .build_modes = true, | 76 | .build_modes = true, |
| 91 | .requires_macos_sdk = true, | 77 | .requires_macos_sdk = true, |
| 92 | }); | 78 | }); |
| 93 | 79 | ||
| 94 | // Try to build and run an Objective-C executable. | 80 | cases.addBuildFile("test/link/macho/needed_library/build.zig", .{ |
| 81 | .build_modes = true, | ||
| 82 | }); | ||
| 83 | |||
| 95 | cases.addBuildFile("test/link/macho/objc/build.zig", .{ | 84 | cases.addBuildFile("test/link/macho/objc/build.zig", .{ |
| 96 | .build_modes = true, | 85 | .build_modes = true, |
| 97 | .requires_macos_sdk = true, | 86 | .requires_macos_sdk = true, |
| 98 | }); | 87 | }); |
| 99 | 88 | ||
| 100 | // Try to build and run an Objective-C++ executable. | ||
| 101 | cases.addBuildFile("test/link/macho/objcpp/build.zig", .{ | 89 | cases.addBuildFile("test/link/macho/objcpp/build.zig", .{ |
| 102 | .build_modes = true, | 90 | .build_modes = true, |
| 103 | .requires_macos_sdk = true, | 91 | .requires_macos_sdk = true, |
| 104 | }); | 92 | }); |
| 105 | 93 | ||
| 94 | cases.addBuildFile("test/link/macho/pagezero/build.zig", .{ | ||
| 95 | .build_modes = false, | ||
| 96 | }); | ||
| 97 | |||
| 98 | cases.addBuildFile("test/link/macho/search_strategy/build.zig", .{ | ||
| 99 | .build_modes = true, | ||
| 100 | }); | ||
| 101 | |||
| 106 | cases.addBuildFile("test/link/macho/stack_size/build.zig", .{ | 102 | cases.addBuildFile("test/link/macho/stack_size/build.zig", .{ |
| 107 | .build_modes = true, | 103 | .build_modes = true, |
| 108 | }); | 104 | }); |
| 109 | 105 | ||
| 110 | cases.addBuildFile("test/link/macho/search_strategy/build.zig", .{ | 106 | cases.addBuildFile("test/link/macho/tls/build.zig", .{ |
| 111 | .build_modes = true, | 107 | .build_modes = true, |
| 112 | }); | 108 | }); |
| 113 | 109 | ||
| 114 | cases.addBuildFile("test/link/macho/headerpad/build.zig", .{ | 110 | cases.addBuildFile("test/link/macho/weak_library/build.zig", .{ |
| 111 | .build_modes = true, | ||
| 112 | }); | ||
| 113 | |||
| 114 | cases.addBuildFile("test/link/macho/weak_framework/build.zig", .{ | ||
| 115 | .build_modes = true, | 115 | .build_modes = true, |
| 116 | .requires_macos_sdk = true, | 116 | .requires_macos_sdk = true, |
| 117 | }); | 117 | }); |
test/link/macho/dead_strip/build.zig+5-3| ... | @@ -4,13 +4,14 @@ const LibExeObjectStep = std.build.LibExeObjStep; | ... | @@ -4,13 +4,14 @@ const LibExeObjectStep = std.build.LibExeObjStep; |
| 4 | 4 | ||
| 5 | pub fn build(b: *Builder) void { | 5 | pub fn build(b: *Builder) void { |
| 6 | const mode = b.standardReleaseOptions(); | 6 | const mode = b.standardReleaseOptions(); |
| 7 | const target: std.zig.CrossTarget = .{ .os_tag = .macos }; | ||
| 7 | 8 | ||
| 8 | const test_step = b.step("test", "Test the program"); | 9 | const test_step = b.step("test", "Test the program"); |
| 9 | test_step.dependOn(b.getInstallStep()); | 10 | test_step.dependOn(b.getInstallStep()); |
| 10 | 11 | ||
| 11 | { | 12 | { |
| 12 | // Without -dead_strip, we expect `iAmUnused` symbol present | 13 | // Without -dead_strip, we expect `iAmUnused` symbol present |
| 13 | const exe = createScenario(b, mode); | 14 | const exe = createScenario(b, mode, target); |
| 14 | 15 | ||
| 15 | const check = exe.checkObject(.macho); | 16 | const check = exe.checkObject(.macho); |
| 16 | check.checkInSymtab(); | 17 | check.checkInSymtab(); |
| ... | @@ -23,7 +24,7 @@ pub fn build(b: *Builder) void { | ... | @@ -23,7 +24,7 @@ pub fn build(b: *Builder) void { |
| 23 | 24 | ||
| 24 | { | 25 | { |
| 25 | // With -dead_strip, no `iAmUnused` symbol should be present | 26 | // With -dead_strip, no `iAmUnused` symbol should be present |
| 26 | const exe = createScenario(b, mode); | 27 | const exe = createScenario(b, mode, target); |
| 27 | exe.link_gc_sections = true; | 28 | exe.link_gc_sections = true; |
| 28 | 29 | ||
| 29 | const check = exe.checkObject(.macho); | 30 | const check = exe.checkObject(.macho); |
| ... | @@ -36,10 +37,11 @@ pub fn build(b: *Builder) void { | ... | @@ -36,10 +37,11 @@ pub fn build(b: *Builder) void { |
| 36 | } | 37 | } |
| 37 | } | 38 | } |
| 38 | 39 | ||
| 39 | fn createScenario(b: *Builder, mode: std.builtin.Mode) *LibExeObjectStep { | 40 | fn createScenario(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget) *LibExeObjectStep { |
| 40 | const exe = b.addExecutable("test", null); | 41 | const exe = b.addExecutable("test", null); |
| 41 | exe.addCSourceFile("main.c", &[0][]const u8{}); | 42 | exe.addCSourceFile("main.c", &[0][]const u8{}); |
| 42 | exe.setBuildMode(mode); | 43 | exe.setBuildMode(mode); |
| 44 | exe.setTarget(target); | ||
| 43 | exe.linkLibC(); | 45 | exe.linkLibC(); |
| 44 | return exe; | 46 | return exe; |
| 45 | } | 47 | } |
test/link/macho/pagezero/build.zig+3-2| ... | @@ -3,13 +3,14 @@ const Builder = std.build.Builder; | ... | @@ -3,13 +3,14 @@ const Builder = std.build.Builder; |
| 3 | 3 | ||
| 4 | pub fn build(b: *Builder) void { | 4 | pub fn build(b: *Builder) void { |
| 5 | const mode = b.standardReleaseOptions(); | 5 | const mode = b.standardReleaseOptions(); |
| 6 | const target: std.zig.CrossTarget = .{ .os_tag = .macos }; | ||
| 6 | 7 | ||
| 7 | const test_step = b.step("test", "Test"); | 8 | const test_step = b.step("test", "Test"); |
| 8 | test_step.dependOn(b.getInstallStep()); | 9 | test_step.dependOn(b.getInstallStep()); |
| 9 | 10 | ||
| 10 | { | 11 | { |
| 11 | const exe = b.addExecutable("pagezero", null); | 12 | const exe = b.addExecutable("pagezero", null); |
| 12 | exe.setTarget(.{ .os_tag = .macos }); | 13 | exe.setTarget(target); |
| 13 | exe.setBuildMode(mode); | 14 | exe.setBuildMode(mode); |
| 14 | exe.addCSourceFile("main.c", &.{}); | 15 | exe.addCSourceFile("main.c", &.{}); |
| 15 | exe.linkLibC(); | 16 | exe.linkLibC(); |
| ... | @@ -29,7 +30,7 @@ pub fn build(b: *Builder) void { | ... | @@ -29,7 +30,7 @@ pub fn build(b: *Builder) void { |
| 29 | 30 | ||
| 30 | { | 31 | { |
| 31 | const exe = b.addExecutable("no_pagezero", null); | 32 | const exe = b.addExecutable("no_pagezero", null); |
| 32 | exe.setTarget(.{ .os_tag = .macos }); | 33 | exe.setTarget(target); |
| 33 | exe.setBuildMode(mode); | 34 | exe.setBuildMode(mode); |
| 34 | exe.addCSourceFile("main.c", &.{}); | 35 | exe.addCSourceFile("main.c", &.{}); |
| 35 | exe.linkLibC(); | 36 | exe.linkLibC(); |
test/link/macho/search_strategy/build.zig+4-4| ... | @@ -1,17 +1,17 @@ | ... | @@ -1,17 +1,17 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const Builder = std.build.Builder; | 2 | const Builder = std.build.Builder; |
| 3 | const LibExeObjectStep = std.build.LibExeObjStep; | 3 | const LibExeObjectStep = std.build.LibExeObjStep; |
| 4 | const target: std.zig.CrossTarget = .{ .os_tag = .macos }; | ||
| 5 | 4 | ||
| 6 | pub fn build(b: *Builder) void { | 5 | pub fn build(b: *Builder) void { |
| 7 | const mode = b.standardReleaseOptions(); | 6 | const mode = b.standardReleaseOptions(); |
| 7 | const target: std.zig.CrossTarget = .{ .os_tag = .macos }; | ||
| 8 | 8 | ||
| 9 | const test_step = b.step("test", "Test"); | 9 | const test_step = b.step("test", "Test"); |
| 10 | test_step.dependOn(b.getInstallStep()); | 10 | test_step.dependOn(b.getInstallStep()); |
| 11 | 11 | ||
| 12 | { | 12 | { |
| 13 | // -search_dylibs_first | 13 | // -search_dylibs_first |
| 14 | const exe = createScenario(b, mode); | 14 | const exe = createScenario(b, mode, target); |
| 15 | exe.search_strategy = .dylibs_first; | 15 | exe.search_strategy = .dylibs_first; |
| 16 | 16 | ||
| 17 | const check = exe.checkObject(.macho); | 17 | const check = exe.checkObject(.macho); |
| ... | @@ -26,7 +26,7 @@ pub fn build(b: *Builder) void { | ... | @@ -26,7 +26,7 @@ pub fn build(b: *Builder) void { |
| 26 | 26 | ||
| 27 | { | 27 | { |
| 28 | // -search_paths_first | 28 | // -search_paths_first |
| 29 | const exe = createScenario(b, mode); | 29 | const exe = createScenario(b, mode, target); |
| 30 | exe.search_strategy = .paths_first; | 30 | exe.search_strategy = .paths_first; |
| 31 | 31 | ||
| 32 | const run = std.build.EmulatableRunStep.create(b, "run", exe); | 32 | const run = std.build.EmulatableRunStep.create(b, "run", exe); |
| ... | @@ -36,7 +36,7 @@ pub fn build(b: *Builder) void { | ... | @@ -36,7 +36,7 @@ pub fn build(b: *Builder) void { |
| 36 | } | 36 | } |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | fn createScenario(b: *Builder, mode: std.builtin.Mode) *LibExeObjectStep { | 39 | fn createScenario(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget) *LibExeObjectStep { |
| 40 | const static = b.addStaticLibrary("a", null); | 40 | const static = b.addStaticLibrary("a", null); |
| 41 | static.setTarget(target); | 41 | static.setTarget(target); |
| 42 | static.setBuildMode(mode); | 42 | static.setBuildMode(mode); |
test/link/macho/stack_size/build.zig+2-1| ... | @@ -3,12 +3,13 @@ const Builder = std.build.Builder; | ... | @@ -3,12 +3,13 @@ const Builder = std.build.Builder; |
| 3 | 3 | ||
| 4 | pub fn build(b: *Builder) void { | 4 | pub fn build(b: *Builder) void { |
| 5 | const mode = b.standardReleaseOptions(); | 5 | const mode = b.standardReleaseOptions(); |
| 6 | const target: std.zig.CrossTarget = .{ .os_tag = .macos }; | ||
| 6 | 7 | ||
| 7 | const test_step = b.step("test", "Test"); | 8 | const test_step = b.step("test", "Test"); |
| 8 | test_step.dependOn(b.getInstallStep()); | 9 | test_step.dependOn(b.getInstallStep()); |
| 9 | 10 | ||
| 10 | const exe = b.addExecutable("main", null); | 11 | const exe = b.addExecutable("main", null); |
| 11 | exe.setTarget(.{ .os_tag = .macos }); | 12 | exe.setTarget(target); |
| 12 | exe.setBuildMode(mode); | 13 | exe.setBuildMode(mode); |
| 13 | exe.addCSourceFile("main.c", &.{}); | 14 | exe.addCSourceFile("main.c", &.{}); |
| 14 | exe.linkLibC(); | 15 | exe.linkLibC(); |
test/link/macho/tls/a.c created+5| ... | @@ -0,0 +1,5 @@ | ||
| 1 | _Thread_local int a; | ||
| 2 | |||
| 3 | int getA() { | ||
| 4 | return a; | ||
| 5 | } | ||
test/link/macho/tls/build.zig created+22| ... | @@ -0,0 +1,22 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const Builder = std.build.Builder; | ||
| 3 | |||
| 4 | pub fn build(b: *Builder) void { | ||
| 5 | const mode = b.standardReleaseOptions(); | ||
| 6 | const target: std.zig.CrossTarget = .{ .os_tag = .macos }; | ||
| 7 | |||
| 8 | const lib = b.addSharedLibrary("a", null, b.version(1, 0, 0)); | ||
| 9 | lib.setBuildMode(mode); | ||
| 10 | lib.setTarget(target); | ||
| 11 | lib.addCSourceFile("a.c", &.{}); | ||
| 12 | lib.linkLibC(); | ||
| 13 | |||
| 14 | const test_exe = b.addTest("main.zig"); | ||
| 15 | test_exe.setBuildMode(mode); | ||
| 16 | test_exe.setTarget(target); | ||
| 17 | test_exe.linkLibrary(lib); | ||
| 18 | test_exe.linkLibC(); | ||
| 19 | |||
| 20 | const test_step = b.step("test", "Test it"); | ||
| 21 | test_step.dependOn(&test_exe.step); | ||
| 22 | } | ||
test/link/macho/tls/main.zig created+15| ... | @@ -0,0 +1,15 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | extern threadlocal var a: i32; | ||
| 4 | extern fn getA() i32; | ||
| 5 | |||
| 6 | fn getA2() i32 { | ||
| 7 | return a; | ||
| 8 | } | ||
| 9 | |||
| 10 | test { | ||
| 11 | a = 2; | ||
| 12 | try std.testing.expect(getA() == 2); | ||
| 13 | try std.testing.expect(2 == getA2()); | ||
| 14 | try std.testing.expect(getA() == getA2()); | ||
| 15 | } | ||
test/link/tls/a.c deleted-5| ... | @@ -1,5 +0,0 @@ | ||
| 1 | _Thread_local int a; | ||
| 2 | |||
| 3 | int getA() { | ||
| 4 | return a; | ||
| 5 | } | ||
test/link/tls/build.zig deleted-18| ... | @@ -1,18 +0,0 @@ | ||
| 1 | const Builder = @import("std").build.Builder; | ||
| 2 | |||
| 3 | pub fn build(b: *Builder) void { | ||
| 4 | const mode = b.standardReleaseOptions(); | ||
| 5 | |||
| 6 | const lib = b.addSharedLibrary("a", null, b.version(1, 0, 0)); | ||
| 7 | lib.setBuildMode(mode); | ||
| 8 | lib.addCSourceFile("a.c", &.{}); | ||
| 9 | lib.linkLibC(); | ||
| 10 | |||
| 11 | const test_exe = b.addTest("main.zig"); | ||
| 12 | test_exe.setBuildMode(mode); | ||
| 13 | test_exe.linkLibrary(lib); | ||
| 14 | test_exe.linkLibC(); | ||
| 15 | |||
| 16 | const test_step = b.step("test", "Test it"); | ||
| 17 | test_step.dependOn(&test_exe.step); | ||
| 18 | } | ||
test/link/tls/main.zig deleted-15| ... | @@ -1,15 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | extern threadlocal var a: i32; | ||
| 4 | extern fn getA() i32; | ||
| 5 | |||
| 6 | fn getA2() i32 { | ||
| 7 | return a; | ||
| 8 | } | ||
| 9 | |||
| 10 | test { | ||
| 11 | a = 2; | ||
| 12 | try std.testing.expect(getA() == 2); | ||
| 13 | try std.testing.expect(2 == getA2()); | ||
| 14 | try std.testing.expect(getA() == getA2()); | ||
| 15 | } | ||