diff --git a/build.zig.zon b/build.zig.zon index 5aa0d6aea..1939767fe 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -10,7 +10,7 @@ // nix flake update --commit-lock-file // ``` // If you do not use Nix, a ZLS maintainer can take care of this. - .minimum_zig_version = "0.18.0-dev.897+117fd40fb", + .minimum_zig_version = "0.18.0-dev.1005+75d48dfff", // Must be kept in sync with the `deps.nix` for the Nix flake. // If you do not use Nix, a ZLS maintainer can take care of this. .dependencies = .{ diff --git a/flake.lock b/flake.lock index 57ed38ed0..41eaa719f 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1793865203, - "narHash": "sha256-/cpdPHaySDIyCgZI6EWngiM6jK3YLUNzv1b7lTzy6Bk=", + "lastModified": 1794165970, + "narHash": "sha256-XuAV2cUwaod3Bt4XFVqiXz3v1w2ex16W6Sv4S7EWres=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "c56a87d8e41ce69bd2af57eb35dcc117a9dfca33", + "rev": "ac588ef1c914865dad517b337ea0eb9694a4021c", "type": "github" }, "original": { @@ -29,11 +29,11 @@ ] }, "locked": { - "lastModified": 1794077684, - "narHash": "sha256-ahaUJnLCPHgUzPQbNpsCl9cHJnrr3GifNbgJREytNHA=", + "lastModified": 1794400348, + "narHash": "sha256-ge/Hg9mrl90G8qBWrX0XjV1t0XVRduCg8vT63KVJEPo=", "owner": "silversquirl", "repo": "zig-flake", - "rev": "a8f437885740ed8a1541f4cb87e0d3b65848ae9c", + "rev": "a16d0a105ba8f33a35b04ef67194e35784022a66", "type": "github" }, "original": { diff --git a/src/DocumentScope.zig b/src/DocumentScope.zig index 9de594101..d24f24cf7 100644 --- a/src/DocumentScope.zig +++ b/src/DocumentScope.zig @@ -241,11 +241,11 @@ pub const Scope = struct { } }; - pub const Data = packed union { + pub const Data = bitpack union { ast_node: Ast.Node.Index, }; - pub const SmallLoc = packed struct { + pub const SmallLoc = bitpack struct { start: u32, end: u32, }; @@ -270,7 +270,7 @@ pub const Scope = struct { }, }; - data: packed struct(u64) { + data: bitpack struct(u64) { tag: Tag, is_child_scopes_small: bool, is_child_decls_small: bool, diff --git a/src/TrigramStore.zig b/src/TrigramStore.zig index 637baaf0f..982579cbf 100644 --- a/src/TrigramStore.zig +++ b/src/TrigramStore.zig @@ -517,7 +517,7 @@ const CuckooFilter = struct { index_2: BucketIndex, pub fn initFromTrigram(trigram: Trigram, len: u32) Triplet { - const split: packed struct { + const split: bitpack struct { fingerprint: Fingerprint, padding: u24, index_1: u32, diff --git a/src/analyser/InternPool.zig b/src/analyser/InternPool.zig index 1cef0eeaf..e050203cc 100644 --- a/src/analyser/InternPool.zig +++ b/src/analyser/InternPool.zig @@ -74,7 +74,7 @@ pub const Key = union(enum) { flags: Flags, packed_offset: PackedOffset = .{ .bit_offset = 0, .host_size = 0 }, - pub const Flags = packed struct(u32) { + pub const Flags = bitpack struct(u32) { size: std.lang.Type.Pointer.Size, is_const: bool = false, is_volatile: bool = false, @@ -84,7 +84,7 @@ pub const Key = union(enum) { alignment: u16 = 0, }; - pub const PackedOffset = packed struct(u32) { + pub const PackedOffset = bitpack struct(u32) { bit_offset: u16, host_size: u16, }; @@ -123,7 +123,7 @@ pub const Key = union(enum) { return_type: Index, flags: Flags = .{}, - pub const Flags = packed struct(u32) { + pub const Flags = bitpack struct(u32) { calling_convention: std.lang.CallingConvention.Tag = .auto, is_generic: bool = false, is_var_args: bool = false, @@ -197,7 +197,7 @@ pub const Key = union(enum) { } }; - const F64Value = packed struct { + const F64Value = bitpack struct { a: u32, b: u32, @@ -210,7 +210,7 @@ pub const Key = union(enum) { } }; - const F80Value = packed struct { + const F80Value = bitpack struct { a: u32, b: u32, c: u32, @@ -226,7 +226,7 @@ pub const Key = union(enum) { } }; - const F128Value = packed struct { + const F128Value = bitpack struct { a: u32, b: u32, c: u32, @@ -3307,7 +3307,7 @@ pub fn isUnsignedInt(ip: *InternPool, ty: Index, target: std.Target) bool { }; } -/// Asserts the type is an integer, enum, error set, packed struct, or vector of one of them. +/// Asserts the type is an integer, enum, error set, bitpack struct, or vector of one of them. pub fn intInfo(ip: *InternPool, ty: Index, target: std.Target) std.lang.Type.Int { var index = ty; while (true) switch (index) { @@ -3349,7 +3349,7 @@ pub fn intInfo(ip: *InternPool, ty: Index, target: std.Target) std.lang.Type.Int }, .struct_type => |struct_index| { const struct_info = ip.getStruct(struct_index); - assert(struct_info.layout == .@"packed"); + assert(struct_info.layout == .@"bitpack"); index = struct_info.backing_int_ty; }, // TODO revisit this when error sets support custom int types (comment taken from zig codebase) diff --git a/src/configuration.zig b/src/configuration.zig index bf09947eb..dc8edf60b 100644 --- a/src/configuration.zig +++ b/src/configuration.zig @@ -638,9 +638,9 @@ pub const UnresolvedConfig = blk: { break :blk @Struct(.auto, null, struct_info.field_names, &field_types, &field_attrs); }; -/// A packed struct where every field name is copied from `Config` but the field type is `bool`. +/// A bitpack struct where every field name is copied from `Config` but the field type is `bool`. pub const DidConfigChange = @Struct( - .@"packed", + .@"bitpack", null, @typeInfo(Config).@"struct".field_names, &@splat(bool), diff --git a/src/features/semantic_tokens.zig b/src/features/semantic_tokens.zig index 149348a94..81cebdab2 100644 --- a/src/features/semantic_tokens.zig +++ b/src/features/semantic_tokens.zig @@ -46,7 +46,7 @@ pub const TokenType = enum(u32) { keywordLiteral, }; -pub const TokenModifiers = packed struct(u16) { +pub const TokenModifiers = bitpack struct(u16) { declaration: bool = false, definition: bool = false, readonly: bool = false, diff --git a/src/tools/langref.html.in b/src/tools/langref.html.in index 19f9d8322..52ef64297 100644 --- a/src/tools/langref.html.in +++ b/src/tools/langref.html.in @@ -755,12 +755,21 @@
\u{NNNNNN}Note that the maximum valid Unicode scalar value is {#syntax#}0x10ffff{#endsyntax#}.
+
+ Note that the highest Unicode code point is {#syntax#}0x10ffff{#endsyntax#}. Character
+ literals are integers ({#syntax#}'A'{#endsyntax#} = {#syntax#}65{#endsyntax#} and
+ {#syntax#}'\u{10000}'{#endsyntax#} = {#syntax#}0x10000{#endsyntax#} = {#syntax#}65536{#endsyntax#}),
+ and \u escapes in string literals are encoded as UTF-8
+ ({#syntax#}"A"{#endsyntax#} = {#syntax#}"\u{41}"{#endsyntax#} = {#syntax#}"\x41"{#endsyntax#}
+ and {#syntax#}"\u{10000}"{#endsyntax#} = {#syntax#}"\xF0\x90\x80\x80"{#endsyntax#}).
+ \u escapes can be used for surrogate code points, which are not Unicode
+ scalar values or technically allowed in UTF-8 as defined by the Unicode standard, but can be useful in practice.
+
@@ -1681,7 +1690,7 @@ try value == 5678{#endsyntax#}
+ Zig features partial operator precedence: not every operator has a defined precedence with + every other operator. Mixing operators with ambiguous precedence is prohibited and parentheses + are mandatory. Consequently, valid code is typically auto-descriptive; when reading and + writing Zig code, there are very few precedence rules you'll need to remember. +
+ + {#code|operator_precedence.zig#} + + {#code|ambiguous_precedence_orelse.zig#} + ++ There is a set of operators (prefix operators, suffix operators, etc) that have unambiguously + higher precedence than all other operators. That set of operators has the following precedence table: +
+{#syntax#}x() x[] x.y x.* x.?
a!b
x{}
!x -x -%x ~x &x ?x try
-* / % *% *| ||
-+ - ++ +% -% +| -|
-<< >> <<|
-& ^ | orelse catch
+// lower precedence operators omitted{#endsyntax#}
+
+ + For the other operators, simplified operator precedence tables are provided below, each containing only + the information that you'll need to know when reading/writing code that uses that particular category of operators. + The operators that have ambiguous precedence or semantic errors with the relevant operators have been omitted, + as have the operators with higher precedence (those shown above). +
+ ++ For arithmetic operators: +
+ +{#syntax#}* / *% *| %
++ - +% -% +| -|
+== != < > <= >=
+and or{#endsyntax#}
+
+ + For bitwise operators: +
+ +{#syntax#}<< <<| >> & ^ |
== != < > <= >=
-and
-or
-= *= *%= *|= /= %= += +%= +|= -= -%= -|= <<= <<|= >>= &= ^= |={#endsyntax#}
+and or{#endsyntax#}
+
+ + For null and error recovery operators: +
+ +{#syntax#}catch orelse{#endsyntax#}
+
+ + For error set operators: +
+ +{#syntax#}||{#endsyntax#}
+
+ + For array concatenation operators: +
+ +{#syntax#}++{#endsyntax#}
+
+ + The full precedence rules can be found in the {#link|Grammar#}, which also includes an {#link|Operator Precedence Flowchart#}. +
+ {#header_close#} {#header_close#} + {#header_open|Arrays#} {#code|test_arrays.zig#} @@ -2261,20 +2327,20 @@ or the C ABI for the target.If well-defined in-memory layout is not required, {#link|struct#} is a better choice because it places fewer restrictions on the compiler.
-See {#link|packed struct#} for a struct that has the ABI of its backing integer, +
See {#link|bitpack struct#} for a struct that has the ABI of its backing integer, which can be useful for modeling flags.
{#see_also|extern union|extern enum#} {#header_close#} - {#header_open|packed struct#} + {#header_open|bitpack struct#}- {#syntax#}packed{#endsyntax#} structs, like {#syntax#}enum{#endsyntax#}, are based on the concept - of interpreting integers differently. All packed structs have a backing integer, + {#syntax#}bitpack{#endsyntax#} structs, like {#syntax#}enum{#endsyntax#}, are based on the concept + of interpreting integers differently. All bitpack structs have a backing integer, which is implicitly determined by the total bit count of fields, or explicitly specified. - Packed structs have well-defined memory layout - exactly the same ABI as their backing integer. + Bitpack structs have well-defined memory layout - exactly the same ABI as their backing integer.
- Each field of a packed struct is interpreted as a logical sequence of bits, arranged from + Each field of a bitpack struct is interpreted as a logical sequence of bits, arranged from least to most significant. Allowed field types:
- This means that a {#syntax#}packed struct{#endsyntax#} can participate + This means that a {#syntax#}bitpack struct{#endsyntax#} can participate in a {#link|@bitCast#} or a {#link|@ptrCast#} to reinterpret memory. This even works at {#link|comptime#}:
- {#code|test_packed_structs.zig#} + {#code|test_bitpack_structs.zig#}The backing integer can be inferred or explicitly provided. When @@ -2300,13 +2366,13 @@ or will be enforced at compile time to exactly match the total bit width of the fields:
- {#code|test_missized_packed_struct.zig#} + {#code|test_missized_bitpack_struct.zig#}- A {#syntax#}packed struct{#endsyntax#} can be converted to and from its backing + A {#syntax#}bitpack struct{#endsyntax#} can be converted to and from its backing integer using {#link|@backingInt#} and {#link|@fromBackingInt#}:
- {#code|test_packed_struct_backing_int.zig#} + {#code|test_bitpack_struct_backing_int.zig#}Zig allows the address to be taken of a non-byte-aligned field: @@ -2326,7 +2392,7 @@ or
Pointers to non-ABI-aligned fields share the same address as the other fields within their host integer:
- {#code|test_packed_struct_field_address.zig#} + {#code|test_bitpack_struct_field_address.zig#}This can be observed with {#link|@bitOffsetOf#} and {#link|offsetOf#}: @@ -2334,10 +2400,10 @@ or {#code|test_bitOffsetOf_offsetOf.zig#}
- Packed structs have the same alignment as their backing integer, however, overaligned - pointers to packed structs can override this: + Bitpack structs have the same alignment as their backing integer, however, overaligned + pointers to bitpack structs can override this:
- {#code|test_overaligned_packed_struct.zig#} + {#code|test_overaligned_bitpack_struct.zig#}It's also possible to set alignment of struct fields: @@ -2345,10 +2411,10 @@ or {#code|test_aligned_struct_fields.zig#}
- Equating packed structs results in a comparison of the backing integer, + Equating bitpack structs results in a comparison of the backing integer, and only works for the {#syntax#}=={#endsyntax#} and {#syntax#}!={#endsyntax#} {#link|Operators#}.
- {#code|test_packed_struct_equality.zig#} + {#code|test_bitpack_struct_equality.zig#}Field access and assignment can be understood as shorthand for bitshifts @@ -2357,7 +2423,7 @@ or input-output (MMIO). Instead of field access on {#link|volatile#} {#link|Pointers#}, construct a fully-formed new value first, then write that value to the volatile pointer.
- {#code|packed_struct_mmio.zig#} + {#code|bitpack_struct_mmio.zig#} {#header_close#} {#header_open|Struct Naming#} @@ -2477,7 +2543,7 @@ or can be as a list of fields. Only one field can be active at a time. The in-memory representation of bare unions is not guaranteed. Bare unions cannot be used to reinterpret memory. For that, use {#link|@ptrCast#}, - or use an {#link|extern union#} or a {#link|packed union#} which have + or use an {#link|extern union#} or a {#link|bitpack union#} which have guaranteed in-memory layout. {#link|Accessing the non-active field|Wrong Union Field Access#} is safety-checked {#link|Illegal Behavior#}: @@ -2489,7 +2555,7 @@ orIn order to use {#link|switch#} with a union, it must be a {#link|tagged union|Tagged union#} - or a {#link|packed union#}. + or a {#link|bitpack union#}.
To initialize a union when the tag is a {#link|comptime#}-known name, see {#link|@unionInit#}. @@ -2538,16 +2604,16 @@ or {#see_also|extern struct#} {#header_close#} - {#header_open|packed union#} -
A {#syntax#}packed union{#endsyntax#} has well-defined in-memory layout and is eligible - to be in a {#link|packed struct#}.
-All fields in a packed union must have the same {#link|@bitSizeOf#}.
+ {#header_open|bitpack union#} +A {#syntax#}bitpack union{#endsyntax#} has well-defined in-memory layout and is eligible + to be in a {#link|bitpack struct#}.
+All fields in a bitpack union must have the same {#link|@bitSizeOf#}.
- Equating packed unions results in a comparison of the backing integer, + Equating bitpack unions results in a comparison of the backing integer, and only works for the {#syntax#}=={#endsyntax#} and {#syntax#}!={#endsyntax#} {#link|Operators#}.
- {#code|test_packed_union_equality.zig#} + {#code|test_bitpack_union_equality.zig#} {#see_also|@backingInt|@fromBackingInt#} {#header_close#} @@ -3621,14 +3687,14 @@ void do_a_thing(struct Foo *foo) {{#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float, - an integer, an enum, or a packed struct. + an integer, an enum, or a bitpack struct.
{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").lang.AtomicOrder{#endsyntax#}.
{#see_also|@atomicStore|@atomicRmw||@cmpxchgWeak|@cmpxchgStrong#} @@ -4447,7 +4513,7 @@ comptime {{#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float, - an integer, an enum, or a packed struct. + an integer, an enum, or a bitpack struct.
{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").lang.AtomicOrder{#endsyntax#}.
{#syntax#}AtomicRmwOp{#endsyntax#} can be found with {#syntax#}@import("std").lang.AtomicRmwOp{#endsyntax#}.
@@ -4461,7 +4527,7 @@ comptime {{#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float, - an integer, an enum, or a packed struct. + an integer, an enum, or a bitpack struct.
{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").lang.AtomicOrder{#endsyntax#}.
{#see_also|@atomicLoad|@atomicRmw|@cmpxchgWeak|@cmpxchgStrong#} @@ -4470,7 +4536,7 @@ comptime { {#header_open|@backingInt#}{#syntax#}@backingInt(enum_or_bitpack: T) BackingInt(T){#endsyntax#}
- Converts an {#link|enum#}, a {#link|packed struct#} or a {#link|packed union#} value + Converts an {#link|enum#}, a {#link|bitpack struct#} or a {#link|bitpack union#} value to its backing integer.
@@ -4519,8 +4585,8 @@ comptime { Returns the bit offset of a field relative to its containing struct.
- For non {#link|packed structs|packed struct#}, this will always be divisible by {#syntax#}8{#endsyntax#}. - For packed structs, non-byte-aligned fields will share a byte offset, but they will have different + For non {#link|bitpack structs|bitpack struct#}, this will always be divisible by {#syntax#}8{#endsyntax#}. + For bitpack structs, non-byte-aligned fields will share a byte offset, but they will have different bit offsets.
{#see_also|@offsetOf#} @@ -4530,7 +4596,7 @@ comptime {{#syntax#}@bitSizeOf(comptime T: type) comptime_int{#endsyntax#}
This function returns the number of bits it takes to store {#syntax#}T{#endsyntax#} in memory if the type - were a field in a packed struct/union. + were a field in a bitpack struct/union. The result is a target-specific compile time constant.
@@ -4657,7 +4723,7 @@ comptime {
{#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, - an integer, an enum, or a packed struct. + an integer, an enum, or a bitpack struct.
{#syntax#}@typeInfo(@TypeOf(ptr)).pointer.alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}
{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").lang.AtomicOrder{#endsyntax#}.
@@ -4689,7 +4755,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val{#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, - an integer, an enum, or a packed struct. + an integer, an enum, or a bitpack struct.
{#syntax#}@typeInfo(@TypeOf(ptr)).pointer.alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}
{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").lang.AtomicOrder{#endsyntax#}.
@@ -5016,8 +5082,8 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val {#header_open|@fromBackingInt#}{#syntax#}@fromBackingInt(backing_int: BackingInt(T)) T{#endsyntax#}
- Converts an integer into a {#link|enum#}, a {#link|packed struct#} or a - {#link|packed union#} value. The return type is the inferred result type. + Converts an integer into a {#link|enum#}, a {#link|bitpack struct#} or a + {#link|bitpack union#} value. The return type is the inferred result type.
Attempting to convert an integer with no corresponding tag value to an @@ -5582,7 +5648,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
Produces an array or vector where each element is the value {#syntax#}element{#endsyntax#}. The return type, including the number of - elements, is inferred. + elements, is inferred. If the result type is a scalar, `element` is returned.
{#code|test_splat_builtin.zig#} {#see_also|Vectors|Arrays|@shuffle#} @@ -5599,13 +5665,12 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val Not every operator is available for every vector element type:Note that {#syntax#}.Add{#endsyntax#} and {#syntax#}.Mul{#endsyntax#} @@ -6364,7 +6429,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val {#code|runtime_wrong_union_field_access.zig#}
- This safety is not available for {#syntax#}extern{#endsyntax#} or {#syntax#}packed{#endsyntax#} unions. + This safety is not available for {#syntax#}extern{#endsyntax#} or {#syntax#}bitpack{#endsyntax#} unions.
To change the active field of a union, assign the entire union, like this: @@ -7410,6 +7475,18 @@ fn readU32Be() u32 {}
{#syntax#}bitpack{#endsyntax#}
+ {#syntax#}break{#endsyntax#}
@@ -7690,18 +7767,6 @@ fn readU32Be() u32 {}
{#syntax#}packed{#endsyntax#}
- {#syntax#}pub{#endsyntax#}
@@ -7870,6 +7935,42 @@ fn readU32Be() u32 {}
{#header_open|Appendix#}
{#header_open|Grammar#}
{#grammar#}
+ {#header_open|Operator Precedence Flowchart#}
+ + To help understand the grammar, this flowchart is provided for the operator precedence. + The bottom represents any location where an expression may occur and the topmost row represents + a parenthesized expression. An operator will have a higher precedence (and therefore be the parent) to + another node if it is strictly lower on the tree (having a directed path from one to another). This is inverted from classical precedence, but + is closer to how a recursive descent parser views the grammar. +
+
+ ┏━━━━━━━━━━━━━━━━━━━┓
+ ┃(expr) ┃
+ ┃x() x[] x.y x.* x.?┃
+ ┃E!T ┃
+ ┃x{} ┃
+ ┃!x -x -%x ~x &x ?x ┃
+ ┗━━━━━━━━━▲━━━━━━━━━┛
+ ┌─────────────┬──────┴───────┬───────┬──┬──┬─┐
+ │ │ │ │ │ │ │
+ ┏━━━━━━┷━━━━━┓╭Non╌Chaining╮ ╭Non╌Chaining╮┏┷┓┏┷┓┏┷┓│
+ ┃* *% *| / ||┃╎ % ╎ ╎ << <<| >> ╎┃&┃┃^┃┃|┃│
+ ┗━━━━━━▲━━━━━┛╰╌╌╌╌╌╌▲╌╌╌╌╌╯ ╰╌╌╌╌╌╌▲╌╌╌╌╌╯┗▲┛┗▲┛┗▲┛│
+ ┏━━┷━━━━━━━━━━━━━┷━┓ ┌────┴───────┴──┴──┘ │
+ ┃+ - +% -% +| -| ++┃ │ │
+ ┗━━━━━━━━━━━▲━━━━━━┛ │ │
+ ╭┴╌Non-Chaining╌┴╮ │
+ ╎== != < <= >= >╎ │
+ ╰╌╌╌▲╌╌╌╌▲╌╌╌╌╌╌╌╯ ┌──────┬─────┘
+ ┏━┷━┓┏━┷━┓ ┏━━━┷━━┓┏━━┷━━┓
+ ┃and┃┃or ┃ ┃orelse┃┃catch┃
+ ┗━▲━┛┗━▲━┛ ┗━━━▲━━┛┗━━▲━━┛
+ ╭╌╌┴╌╌╌╌┴╌╌╌╌╌╌╌╌╌╌╌╌╌╌┴╌╌╌╌╌╌┴╌╮
+ ╎ Any expression location ╎
+ ╰╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╯
+
+
+ {#header_close#}
{#header_close#}
{#header_open|Zen#}