2021-06-03 11:26:17 +00:00
|
|
|
{{- /*
|
|
|
|
--------------------------------------------------------------------------------
|
2022-07-26 15:46:44 +00:00
|
|
|
Template file for use with tools/src/cmd/gen to generate the wgsl files in the
|
2022-06-02 14:36:10 +00:00
|
|
|
./literal/... and ./var/... subdirectories
|
2021-06-03 11:26:17 +00:00
|
|
|
|
|
|
|
See:
|
2022-07-26 15:46:44 +00:00
|
|
|
* tools/src/cmd/gen for structures used by this template
|
2021-06-03 11:26:17 +00:00
|
|
|
* https://golang.org/pkg/text/template/ for documentation on the template syntax
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
*/ -}}
|
|
|
|
|
2022-05-10 09:05:54 +00:00
|
|
|
{{- /* For each permutation of each overload of each function... */ -}}
|
2022-07-26 15:46:44 +00:00
|
|
|
{{- range Sem.Builtins -}}
|
2021-06-03 11:26:17 +00:00
|
|
|
{{- range .Overloads -}}
|
|
|
|
{{- range Permute . -}}
|
2022-07-29 11:41:51 +00:00
|
|
|
{{- /* TODO(crbug.com/tint/1502): Remove the bodge below and emit "enable f16;" after
|
|
|
|
getting ready for F16 end-to-end tests. */ -}}
|
|
|
|
{{- if not (OverloadUsesF16 .Overload) -}}
|
|
|
|
{{- /* Generate a ./literal/<function>/<permuataion-hash>.wgsl file using
|
|
|
|
the Permutation macro defined below */ -}}
|
|
|
|
{{- $file := printf "./literal/%v/%v.wgsl" .Intrinsic.Name .Hash -}}
|
|
|
|
{{- $content := Eval "Permutation" "Overload" . "Mode" "literal" -}}
|
|
|
|
{{- WriteFile $file $content -}}
|
|
|
|
{{- /* Generate a ./var/<function>/<permuataion-hash>.wgsl file using
|
|
|
|
the Permutation macro defined below */ -}}
|
|
|
|
{{- $file := printf "./var/%v/%v.wgsl" .Intrinsic.Name .Hash -}}
|
|
|
|
{{- $content := Eval "Permutation" "Overload" . "Mode" "var" -}}
|
|
|
|
{{- WriteFile $file $content -}}
|
|
|
|
{{- end }}
|
2021-06-03 11:26:17 +00:00
|
|
|
{{- end }}
|
|
|
|
{{- end }}
|
|
|
|
{{- end }}
|
|
|
|
|
|
|
|
{{- /* ------------------------------------------------------------------ */ -}}
|
|
|
|
{{- define "Permutation" -}}
|
|
|
|
{{- /* Emits the body of the intrinsic permuation .wgsl file */ -}}
|
|
|
|
{{- /* ------------------------------------------------------------------ */ -}}
|
2022-06-02 14:36:10 +00:00
|
|
|
{{- $overload := .Overload -}}
|
|
|
|
{{- $mode := .Mode -}}
|
|
|
|
{{- $builtin := $overload.Intrinsic.Name -}}
|
|
|
|
{{- $permutation := printf "%v_%v" $builtin $overload.Hash -}}
|
2021-06-03 11:26:17 +00:00
|
|
|
{{- $args := Map -}}
|
|
|
|
|
2022-07-27 13:27:56 +00:00
|
|
|
{{- /* Generate enable directives */ -}}
|
|
|
|
{{- template "EnableDirectives" $overload -}}
|
|
|
|
|
2021-06-18 18:56:13 +00:00
|
|
|
{{- /* Generate RW storage buffer parameters */ -}}
|
2022-06-02 14:36:10 +00:00
|
|
|
{{- $sb_rw_fields := Eval "EmitBufferFields" "overload" $overload
|
2021-06-18 18:56:13 +00:00
|
|
|
"var_name" "sb_rw"
|
|
|
|
"storage" "storage"
|
|
|
|
"access" "read_write"
|
|
|
|
"args" $args -}}
|
|
|
|
{{- if $sb_rw_fields -}}
|
|
|
|
struct SB_RW {
|
|
|
|
{{- $sb_rw_fields -}}
|
|
|
|
};
|
2022-01-19 22:46:57 +00:00
|
|
|
@group(0) @binding(0) var<storage, read_write> sb_rw : SB_RW;
|
2021-06-18 18:56:13 +00:00
|
|
|
{{ end -}}
|
|
|
|
|
|
|
|
{{- /* Generate RO storage buffer parameters */ -}}
|
2022-06-02 14:36:10 +00:00
|
|
|
{{- $sb_ro_fields := Eval "EmitBufferFields" "overload" $overload
|
2021-06-18 18:56:13 +00:00
|
|
|
"var_name" "sb_ro"
|
|
|
|
"storage" "storage"
|
|
|
|
"access" "read"
|
|
|
|
"args" $args -}}
|
|
|
|
{{- if $sb_ro_fields -}}
|
|
|
|
struct SB_RO {
|
|
|
|
{{- $sb_ro_fields -}}
|
2021-06-03 11:26:17 +00:00
|
|
|
};
|
2022-01-19 22:46:57 +00:00
|
|
|
@group(0) @binding(1) var<storage, read> sb_ro : SB_RO;
|
2021-06-03 11:26:17 +00:00
|
|
|
{{ end -}}
|
|
|
|
|
2021-06-18 18:56:13 +00:00
|
|
|
{{- /* Generate uniform buffer parameters */ -}}
|
2022-06-02 14:36:10 +00:00
|
|
|
{{- $ub_fields := Eval "EmitBufferFields" "overload" $overload
|
2021-06-18 18:56:13 +00:00
|
|
|
"var_name" "ub"
|
|
|
|
"storage" "uniform"
|
|
|
|
"access" "read"
|
|
|
|
"args" $args -}}
|
|
|
|
{{- if $ub_fields -}}
|
|
|
|
struct UB {
|
|
|
|
{{- $ub_fields -}}
|
|
|
|
};
|
2022-01-19 22:46:57 +00:00
|
|
|
@group(0) @binding(1) var<uniform> ub : UB;
|
2021-06-18 18:56:13 +00:00
|
|
|
{{ end -}}
|
|
|
|
|
|
|
|
{{- /* Generate module-scoped handle variables */ -}}
|
2022-06-02 14:36:10 +00:00
|
|
|
{{- range $i, $p := $overload.Parameters }}
|
2021-06-03 11:26:17 +00:00
|
|
|
{{- $class := Eval "StorageClass" $p.Type -}}
|
2021-06-18 18:56:13 +00:00
|
|
|
{{- if eq "ptr" $p.Type.Target.Name -}}
|
|
|
|
{{- $el_type := Eval "Type" (index $p.Type.TemplateArguments 1)}}
|
|
|
|
{{- if eq "handle" $class -}}
|
2022-01-19 22:46:57 +00:00
|
|
|
@group(1) @binding({{$i}}) var arg_{{$i}}: {{$el_type}};
|
2021-06-18 18:56:13 +00:00
|
|
|
{{ $args.Put $i (printf "&arg_%v" $i) -}}
|
|
|
|
{{- else if eq "workgroup" $class -}}
|
|
|
|
var<workgroup> arg_{{$i}}: {{$el_type}};
|
|
|
|
{{ $args.Put $i (printf "&arg_%v" $i) -}}
|
|
|
|
{{- else if eq "private" $class -}}
|
|
|
|
var<private> arg_{{$i}}: {{$el_type}};
|
|
|
|
{{ $args.Put $i (printf "&arg_%v" $i) -}}
|
|
|
|
{{- end -}}
|
|
|
|
{{- else -}}
|
|
|
|
{{- $type := Eval "Type" $p.Type}}
|
|
|
|
{{- if eq "handle" $class -}}
|
2022-01-19 22:46:57 +00:00
|
|
|
@group(1) @binding({{$i}}) var arg_{{$i}}: {{$type}};
|
2021-06-18 18:56:13 +00:00
|
|
|
{{ $args.Put $i (printf "arg_%v" $i) -}}
|
|
|
|
{{- else if eq "workgroup" $class -}}
|
|
|
|
var<workgroup> arg_{{$i}}: {{$type}};
|
|
|
|
{{ $args.Put $i (printf "arg_%v" $i) -}}
|
|
|
|
{{- else if eq "private" $class -}}
|
|
|
|
var<private> arg_{{$i}}: {{$type}};
|
|
|
|
{{ $args.Put $i (printf "arg_%v" $i) -}}
|
|
|
|
{{- end -}}
|
2021-06-03 11:26:17 +00:00
|
|
|
{{- end -}}
|
|
|
|
{{- end -}}
|
|
|
|
|
|
|
|
{{- /* Generate the function that calls the intrinsic */ -}}
|
2021-06-17 20:04:45 +00:00
|
|
|
{{- /*newline*/}}
|
|
|
|
// {{$.Overload}}
|
2021-06-03 11:26:17 +00:00
|
|
|
fn {{$permutation}}() {
|
|
|
|
{{/* Build the parameters either as 'var' or inline values */ -}}
|
2022-06-02 14:36:10 +00:00
|
|
|
{{- range $i, $p := $overload.Parameters -}}
|
2022-07-26 14:27:25 +00:00
|
|
|
{{- $class := Eval "StorageClass" $p.Type -}}
|
2022-07-27 19:36:49 +00:00
|
|
|
{{- $is_abstract := DeepestElementType $p.Type | IsAbstract -}}
|
2021-06-18 18:56:13 +00:00
|
|
|
{{- if eq "function" $class -}}
|
2021-06-03 11:26:17 +00:00
|
|
|
{{- if eq "ptr" $p.Type.Target.Name -}}
|
2022-07-26 14:27:25 +00:00
|
|
|
{{template "Type" index $p.Type.TemplateArguments 1}};
|
2021-06-03 11:26:17 +00:00
|
|
|
{{- /*indent*/}} var arg_{{$i}}: {{template "Type" index $p.Type.TemplateArguments 1}};
|
|
|
|
{{ $args.Put $i (printf "&arg_%v" $i) -}}
|
2022-06-02 14:36:10 +00:00
|
|
|
{{- else if and (not $p.IsConst) (eq "var" $mode) -}}
|
2022-07-26 14:27:25 +00:00
|
|
|
{{- if $is_abstract }} const arg_{{$i}} = {{Eval "ArgumentValue" $p}};
|
|
|
|
{{ else }} var arg_{{$i}} = {{Eval "ArgumentValue" $p}};
|
|
|
|
{{ end }}
|
|
|
|
{{- $args.Put $i (printf "arg_%v" $i) -}}
|
2021-06-03 11:26:17 +00:00
|
|
|
{{- else -}}
|
2021-07-08 21:04:53 +00:00
|
|
|
{{- $args.Put $i (Eval "ArgumentValue" $p) -}}
|
2021-06-03 11:26:17 +00:00
|
|
|
{{- end -}}
|
|
|
|
{{- end -}}
|
|
|
|
{{- end -}}
|
|
|
|
|
|
|
|
{{- /* Make the call to the intrinsic */ -}}
|
|
|
|
{{- /*indent*/}} {{/*indent*/ -}}
|
2022-06-02 14:36:10 +00:00
|
|
|
{{- if $overload.ReturnType -}}
|
|
|
|
var res{{if IsDeclarable $overload.ReturnType}}: {{template "Type" $overload.ReturnType}}{{end}} = {{/* preserve space after = */ -}}
|
2021-06-03 11:26:17 +00:00
|
|
|
{{- end -}}
|
2022-05-09 18:08:23 +00:00
|
|
|
{{$builtin}}(
|
2022-06-02 14:36:10 +00:00
|
|
|
{{- range $i, $p := $overload.Parameters -}}
|
2021-06-03 11:26:17 +00:00
|
|
|
{{- if $i -}}, {{end}}{{$args.Get $i -}}
|
|
|
|
{{- end -}}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
{{/*new line*/ -}}
|
|
|
|
|
2022-06-02 14:36:10 +00:00
|
|
|
{{- if $overload.CanBeUsedInStage.Vertex }}
|
2022-06-07 13:55:34 +00:00
|
|
|
@vertex
|
2022-01-19 22:46:57 +00:00
|
|
|
fn vertex_main() -> @builtin(position) vec4<f32> {
|
2021-06-03 11:26:17 +00:00
|
|
|
{{$permutation}}();
|
2021-06-04 17:31:48 +00:00
|
|
|
return vec4<f32>();
|
2021-06-03 11:26:17 +00:00
|
|
|
}
|
|
|
|
{{ end -}}
|
|
|
|
|
2022-06-02 14:36:10 +00:00
|
|
|
{{- if $overload.CanBeUsedInStage.Fragment }}
|
2022-06-07 13:55:34 +00:00
|
|
|
@fragment
|
2021-06-03 11:26:17 +00:00
|
|
|
fn fragment_main() {
|
|
|
|
{{$permutation}}();
|
|
|
|
}
|
|
|
|
{{ end -}}
|
|
|
|
|
2022-06-02 14:36:10 +00:00
|
|
|
{{- if $overload.CanBeUsedInStage.Compute }}
|
2022-06-07 13:55:34 +00:00
|
|
|
@compute @workgroup_size(1)
|
2021-06-03 11:26:17 +00:00
|
|
|
fn compute_main() {
|
|
|
|
{{$permutation}}();
|
|
|
|
}
|
|
|
|
{{ end -}}
|
|
|
|
|
|
|
|
{{- end -}}
|
|
|
|
|
2022-07-27 13:27:56 +00:00
|
|
|
{{- /* ------------------------------------------------------------------ */ -}}
|
|
|
|
{{- define "EnableDirectives" -}}
|
|
|
|
{{- /* Emits the required enable directives for a given overload */ -}}
|
|
|
|
{{- /* ------------------------------------------------------------------ */ -}}
|
|
|
|
{{- $overload := . -}}
|
|
|
|
{{- $builtin_name := $overload.Intrinsic.Name -}}
|
|
|
|
|
|
|
|
{{- /* Check and emit chromium_experimental_dp4a */ -}}
|
|
|
|
{{- if or (eq "dot4I8Packed" $builtin_name) (eq "dot4U8Packed" $builtin_name)}}
|
|
|
|
enable chromium_experimental_dp4a;
|
|
|
|
{{ end -}}
|
|
|
|
|
|
|
|
{{- end -}}
|
|
|
|
|
2021-06-03 11:26:17 +00:00
|
|
|
|
|
|
|
{{- /* ------------------------------------------------------------------ */ -}}
|
2021-06-18 18:56:13 +00:00
|
|
|
{{- define "EmitBufferFields" -}}
|
|
|
|
{{- /* Emits a struct with the fields that match the given storage class */ -}}
|
|
|
|
{{- /* and access. */ -}}
|
|
|
|
{{- /* Argument is a map with the following expected keys: */ -}}
|
|
|
|
{{- /* 'overload' - the current overload */ -}}
|
|
|
|
{{- /* 'var_name' - name of the variable of the structure type */ -}}
|
|
|
|
{{- /* 'storage' - filtered storage class */ -}}
|
|
|
|
{{- /* 'access' - filtered access */ -}}
|
|
|
|
{{- /* 'args' - argument map that's populated with the fields */ -}}
|
2021-06-03 11:26:17 +00:00
|
|
|
{{- /* ------------------------------------------------------------------ */ -}}
|
2021-06-18 18:56:13 +00:00
|
|
|
{{- $overload := .Get "overload" -}}
|
|
|
|
{{- $var_name := .Get "var_name" -}}
|
|
|
|
{{- $filter_storage := .Get "storage" -}}
|
|
|
|
{{- $filter_access := .Get "access" -}}
|
|
|
|
{{- $args := .Get "args" -}}
|
|
|
|
{{- range $i, $p := $overload.Parameters }}
|
|
|
|
{{- $storage := Eval "StorageClass" $p.Type -}}
|
|
|
|
{{- $access := Eval "Access" $p.Type -}}
|
|
|
|
{{- if and (eq $filter_storage $storage) (eq $filter_access $access) }}
|
|
|
|
{{- if eq "ptr" $p.Type.Target.Name }}
|
2022-03-30 17:57:39 +00:00
|
|
|
arg_{{$i}}: {{template "Type" (index $p.Type.TemplateArguments 1)}},
|
2021-06-18 18:56:13 +00:00
|
|
|
{{ $args.Put $i (printf "&%v.arg_%v" $var_name $i) -}}
|
|
|
|
{{- else }}
|
2022-03-30 17:57:39 +00:00
|
|
|
arg_{{$i}}: {{template "Type" $p.Type}},
|
2021-06-18 18:56:13 +00:00
|
|
|
{{ $args.Put $i (printf "%v.arg_%v" $var_name $i) -}}
|
|
|
|
{{- end -}}
|
|
|
|
{{- end -}}
|
|
|
|
{{- end -}}
|
|
|
|
{{ end -}}
|
|
|
|
|
2022-07-26 14:27:25 +00:00
|
|
|
|
2021-06-18 18:56:13 +00:00
|
|
|
{{- /* ------------------------------------------------------------------ */ -}}
|
|
|
|
{{- define "StorageClass" -}}
|
|
|
|
{{- /* Returns the storage class for the given Fully Qualified Name */ -}}
|
|
|
|
{{- /* ------------------------------------------------------------------ */ -}}
|
|
|
|
{{- $name := .Target.Name -}}
|
|
|
|
{{- if eq $name "array" -}}storage
|
|
|
|
{{- else if HasPrefix $name "texture" -}}handle
|
|
|
|
{{- else if HasPrefix $name "sampler" -}}handle
|
|
|
|
{{- else if eq $name "ptr" -}}{{(index .TemplateArguments 0).Target.Name}}
|
|
|
|
{{- else -}}function
|
2021-06-03 11:26:17 +00:00
|
|
|
{{- end -}}
|
|
|
|
{{- end -}}
|
|
|
|
|
|
|
|
|
|
|
|
{{- /* ------------------------------------------------------------------ */ -}}
|
2021-06-18 18:56:13 +00:00
|
|
|
{{- define "Access" -}}
|
|
|
|
{{- /* Returns the access for the given Fully Qualified Name */ -}}
|
2021-06-03 11:26:17 +00:00
|
|
|
{{- /* ------------------------------------------------------------------ */ -}}
|
|
|
|
{{- $name := .Target.Name -}}
|
2021-06-18 18:56:13 +00:00
|
|
|
{{- if eq $name "ptr" -}}{{(index .TemplateArguments 2).Target.Name}}
|
|
|
|
{{- else -}}
|
|
|
|
{{- /* Emit the default for the storage class */ -}}
|
|
|
|
{{- /* https://gpuweb.github.io/gpuweb/wgsl/#storage-class */ -}}
|
|
|
|
{{- $storage := Eval "StorageClass" . -}}
|
2022-07-26 14:27:25 +00:00
|
|
|
{{- if eq $storage "function" -}}read_write
|
|
|
|
{{- else if eq $storage "private" -}}read_write
|
2021-06-18 18:56:13 +00:00
|
|
|
{{- else if eq $storage "workgroup" -}}read_write
|
2022-07-26 14:27:25 +00:00
|
|
|
{{- else if eq $storage "uniform" -}}read
|
|
|
|
{{- else if eq $storage "storage" -}}read
|
|
|
|
{{- else if eq $storage "handle" -}}read
|
2021-06-18 18:56:13 +00:00
|
|
|
{{- end -}}
|
2021-06-03 11:26:17 +00:00
|
|
|
{{- end -}}
|
|
|
|
{{- end -}}
|
|
|
|
|
|
|
|
|
|
|
|
{{- /* ------------------------------------------------------------------ */ -}}
|
2021-07-08 21:04:53 +00:00
|
|
|
{{- define "ArgumentValue" -}}
|
|
|
|
{{- /* Returns a value that can be used for the parameter argument */ -}}
|
2021-06-03 11:26:17 +00:00
|
|
|
{{- /* ------------------------------------------------------------------ */ -}}
|
2021-07-08 21:04:53 +00:00
|
|
|
{{- $ty := .Type -}}
|
|
|
|
{{- if eq $ty.Target.Name "i32" -}}
|
|
|
|
{{- /* If the parameter has the name 'level', then use '0' as the value. */ -}}
|
|
|
|
{{- /* Some texture arguments require the level parameter to be 0, and */ -}}
|
|
|
|
{{- /* constraint is not described in the definition file. */ -}}
|
|
|
|
{{- if eq .Name "level" -}}0
|
|
|
|
{{- else -}}1
|
|
|
|
{{- end -}}
|
2022-07-26 14:27:25 +00:00
|
|
|
{{- else if eq $ty.Target.Name "u32" -}}1u
|
|
|
|
{{- else if eq $ty.Target.Name "f32" -}}1.f
|
|
|
|
{{- else if eq $ty.Target.Name "fa" -}}1
|
|
|
|
{{- else if eq $ty.Target.Name "ia" -}}1.0
|
|
|
|
{{- else if eq $ty.Target.Name "bool" -}}true
|
|
|
|
{{- else if eq $ty.Target.Name "vec" -}}
|
2022-07-27 19:36:49 +00:00
|
|
|
{{- $el := Eval "ArgumentValue" "Type" (ElementType .Type) "Name" ""}}
|
2022-07-26 14:27:25 +00:00
|
|
|
{{- template "Type" $ty}}({{$el}})
|
|
|
|
{{- else if eq $ty.Target.Name "mat" -}}{{template "Type" $ty}}(
|
2022-07-27 19:36:49 +00:00
|
|
|
{{- $el := Eval "ArgumentValue" "Type" (ElementType .Type) "Name" ""}}
|
2022-07-26 14:27:25 +00:00
|
|
|
{{- range $col := Iterate (index $ty.TemplateArguments 0) }}
|
|
|
|
{{- range $row := Iterate (index $ty.TemplateArguments 1) }}
|
|
|
|
{{- if or $col $row -}}, {{end}}{{$el}}
|
|
|
|
{{- end -}}
|
|
|
|
{{- end -}})
|
|
|
|
{{- else -}}{{template "Type" $ty}}()
|
|
|
|
{{- end -}}
|
2021-06-03 11:26:17 +00:00
|
|
|
{{- end -}}
|
|
|
|
|
|
|
|
|
|
|
|
{{- /* ------------------------------------------------------------------ */ -}}
|
|
|
|
{{- define "Type" -}}
|
|
|
|
{{- /* Emits the WGSL for the Fully Qualified Name argument */ -}}
|
|
|
|
{{- /* ------------------------------------------------------------------ */ -}}
|
|
|
|
{{- if IsType .Target -}}
|
2022-07-27 19:36:49 +00:00
|
|
|
{{- if DeepestElementType . | IsAbstract -}}
|
2022-07-26 14:27:25 +00:00
|
|
|
{{- if eq .Target.Name "vec" -}}vec{{index .TemplateArguments 0}}
|
|
|
|
{{- else if eq .Target.Name "mat" -}}mat{{index .TemplateArguments 0}}x{{index .TemplateArguments 1}}
|
|
|
|
{{- else -}}
|
|
|
|
{{- end -}}
|
2022-07-27 19:36:49 +00:00
|
|
|
{{- else if eq .Target.Name "vec" -}}vec{{index .TemplateArguments 0}}<{{template "Type" (ElementType .)}}>
|
|
|
|
{{- else if eq .Target.Name "mat" -}}mat{{index .TemplateArguments 0}}x{{index .TemplateArguments 1}}<{{template "Type" (ElementType .)}}>
|
2021-06-03 11:26:17 +00:00
|
|
|
{{- else -}}{{.Target.Name}}{{template "TemplateArguments" .TemplateArguments}}
|
|
|
|
{{- end -}}
|
|
|
|
{{- else if IsEnumEntry .Target -}}{{.Target.Name}}
|
|
|
|
{{- else if IsEnumMatcher .Target -}}{{(index .Target.Options 0).Name}}
|
|
|
|
{{- else -}}<unhandled-fully-qualified-name-target={{- printf "%T" .Target -}}>
|
|
|
|
{{- end -}}
|
|
|
|
{{- end -}}
|
|
|
|
|
|
|
|
|
|
|
|
{{- /* ------------------------------------------------------------------ */ -}}
|
|
|
|
{{- define "TemplateArguments" -}}
|
|
|
|
{{- /* Emits the WGSL for the template argument list */ -}}
|
|
|
|
{{- /* ------------------------------------------------------------------ */ -}}
|
|
|
|
{{- if . -}}
|
|
|
|
<
|
|
|
|
{{- range $i, $a := . -}}
|
|
|
|
{{- if $i -}}, {{ end -}}
|
|
|
|
{{- if IsInt $a -}}{{- . -}}
|
|
|
|
{{- else -}}{{- template "Type" $a -}}
|
|
|
|
{{- end -}}
|
|
|
|
{{- end -}}
|
|
|
|
>
|
|
|
|
{{- end -}}
|
2022-07-29 11:41:51 +00:00
|
|
|
{{- end -}}
|