yum-mirror/VkFFT

git clone https://git.yummers.dev/yum-mirror/VkFFT

Tolmachev DmitriiMetal support in VkFFTba7001c

develop
20.4 KiB621 linesraw
1//-------------------------------------------------------------------------------------------------------------------------------------------------------------
2//
3// Metal/MTLLibrary.hpp
4//
5// Copyright 2020-2021 Apple Inc.
6//
7// Licensed under the Apache License, Version 2.0 (the "License");
8// you may not use this file except in compliance with the License.
9// You may obtain a copy of the License at
10//
11//     http://www.apache.org/licenses/LICENSE-2.0
12//
13// Unless required by applicable law or agreed to in writing, software
14// distributed under the License is distributed on an "AS IS" BASIS,
15// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16// See the License for the specific language governing permissions and
17// limitations under the License.
18//
19//-------------------------------------------------------------------------------------------------------------------------------------------------------------
20
21#pragma once
22
23#include "MTLDefines.hpp"
24#include "MTLHeaderBridge.hpp"
25#include "MTLPrivate.hpp"
26
27#include <Foundation/Foundation.hpp>
28
29#include "MTLArgument.hpp"
30#include "MTLFunctionDescriptor.hpp"
31#include "MTLLibrary.hpp"
32#include <functional>
33
34namespace MTL
35{
36_MTL_ENUM(NS::UInteger, PatchType) {
37    PatchTypeNone = 0,
38    PatchTypeTriangle = 1,
39    PatchTypeQuad = 2,
40};
41
42class VertexAttribute : public NS::Referencing<VertexAttribute>
43{
44public:
45    static class VertexAttribute* alloc();
46
47    class VertexAttribute*        init();
48
49    NS::String*                   name() const;
50
51    NS::UInteger                  attributeIndex() const;
52
53    MTL::DataType                 attributeType() const;
54
55    bool                          active() const;
56
57    bool                          patchData() const;
58
59    bool                          patchControlPointData() const;
60};
61
62class Attribute : public NS::Referencing<Attribute>
63{
64public:
65    static class Attribute* alloc();
66
67    class Attribute*        init();
68
69    NS::String*             name() const;
70
71    NS::UInteger            attributeIndex() const;
72
73    MTL::DataType           attributeType() const;
74
75    bool                    active() const;
76
77    bool                    patchData() const;
78
79    bool                    patchControlPointData() const;
80};
81
82_MTL_ENUM(NS::UInteger, FunctionType) {
83    FunctionTypeVertex = 1,
84    FunctionTypeFragment = 2,
85    FunctionTypeKernel = 3,
86    FunctionTypeVisible = 5,
87    FunctionTypeIntersection = 6,
88};
89
90class FunctionConstant : public NS::Referencing<FunctionConstant>
91{
92public:
93    static class FunctionConstant* alloc();
94
95    class FunctionConstant*        init();
96
97    NS::String*                    name() const;
98
99    MTL::DataType                  type() const;
100
101    NS::UInteger                   index() const;
102
103    bool                           required() const;
104};
105
106using AutoreleasedArgument = class Argument*;
107
108class Function : public NS::Referencing<Function>
109{
110public:
111    NS::String*            label() const;
112    void                   setLabel(const NS::String* label);
113
114    class Device*          device() const;
115
116    MTL::FunctionType      functionType() const;
117
118    MTL::PatchType         patchType() const;
119
120    NS::Integer            patchControlPointCount() const;
121
122    NS::Array*             vertexAttributes() const;
123
124    NS::Array*             stageInputAttributes() const;
125
126    NS::String*            name() const;
127
128    NS::Dictionary*        functionConstantsDictionary() const;
129
130    class ArgumentEncoder* newArgumentEncoder(NS::UInteger bufferIndex);
131
132    class ArgumentEncoder* newArgumentEncoder(NS::UInteger bufferIndex, const MTL::AutoreleasedArgument* reflection);
133
134    MTL::FunctionOptions   options() const;
135};
136
137_MTL_ENUM(NS::UInteger, LanguageVersion) {
138    LanguageVersion1_0 = 65536,
139    LanguageVersion1_1 = 65537,
140    LanguageVersion1_2 = 65538,
141    LanguageVersion2_0 = 131072,
142    LanguageVersion2_1 = 131073,
143    LanguageVersion2_2 = 131074,
144    LanguageVersion2_3 = 131075,
145    LanguageVersion2_4 = 131076,
146};
147
148_MTL_ENUM(NS::Integer, LibraryType) {
149    LibraryTypeExecutable = 0,
150    LibraryTypeDynamic = 1,
151};
152
153class CompileOptions : public NS::Copying<CompileOptions>
154{
155public:
156    static class CompileOptions* alloc();
157
158    class CompileOptions*        init();
159
160    NS::Dictionary*              preprocessorMacros() const;
161    void                         setPreprocessorMacros(const NS::Dictionary* preprocessorMacros);
162
163    bool                         fastMathEnabled() const;
164    void                         setFastMathEnabled(bool fastMathEnabled);
165
166    MTL::LanguageVersion         languageVersion() const;
167    void                         setLanguageVersion(MTL::LanguageVersion languageVersion);
168
169    MTL::LibraryType             libraryType() const;
170    void                         setLibraryType(MTL::LibraryType libraryType);
171
172    NS::String*                  installName() const;
173    void                         setInstallName(const NS::String* installName);
174
175    NS::Array*                   libraries() const;
176    void                         setLibraries(const NS::Array* libraries);
177
178    bool                         preserveInvariance() const;
179    void                         setPreserveInvariance(bool preserveInvariance);
180};
181
182_MTL_ENUM(NS::UInteger, LibraryError) {
183    LibraryErrorUnsupported = 1,
184    LibraryErrorCompileFailure = 3,
185    LibraryErrorCompileWarning = 4,
186    LibraryErrorFunctionNotFound = 5,
187    LibraryErrorFileNotFound = 6,
188};
189
190class Library : public NS::Referencing<Library>
191{
192public:
193    void             newFunction(const NS::String* pFunctionName, const class FunctionConstantValues* pConstantValues, const std::function<void(Function* pFunction, NS::Error* pError)>& completionHandler);
194
195    void             newFunction(const class FunctionDescriptor* pDescriptor, const std::function<void(Function* pFunction, NS::Error* pError)>& completionHandler);
196
197    void             newIntersectionFunction(const class IntersectionFunctionDescriptor* pDescriptor, const std::function<void(Function* pFunction, NS::Error* pError)>& completionHandler);
198
199    NS::String*      label() const;
200    void             setLabel(const NS::String* label);
201
202    class Device*    device() const;
203
204    class Function*  newFunction(const NS::String* functionName);
205
206    class Function*  newFunction(const NS::String* name, const class FunctionConstantValues* constantValues, NS::Error** error);
207
208    void             newFunction(const NS::String* name, const class FunctionConstantValues* constantValues, void (^completionHandler)(MTL::Function*, NS::Error*));
209
210    void             newFunction(const class FunctionDescriptor* descriptor, void (^completionHandler)(MTL::Function*, NS::Error*));
211
212    class Function*  newFunction(const class FunctionDescriptor* descriptor, NS::Error** error);
213
214    void             newIntersectionFunction(const class IntersectionFunctionDescriptor* descriptor, void (^completionHandler)(MTL::Function*, NS::Error*));
215
216    class Function*  newIntersectionFunction(const class IntersectionFunctionDescriptor* descriptor, NS::Error** error);
217
218    NS::Array*       functionNames() const;
219
220    MTL::LibraryType type() const;
221
222    NS::String*      installName() const;
223};
224
225}
226
227// static method: alloc
228_MTL_INLINE MTL::VertexAttribute* MTL::VertexAttribute::alloc()
229{
230    return NS::Object::alloc<MTL::VertexAttribute>(_MTL_PRIVATE_CLS(MTLVertexAttribute));
231}
232
233// method: init
234_MTL_INLINE MTL::VertexAttribute* MTL::VertexAttribute::init()
235{
236    return NS::Object::init<MTL::VertexAttribute>();
237}
238
239// property: name
240_MTL_INLINE NS::String* MTL::VertexAttribute::name() const
241{
242    return Object::sendMessage<NS::String*>(this, _MTL_PRIVATE_SEL(name));
243}
244
245// property: attributeIndex
246_MTL_INLINE NS::UInteger MTL::VertexAttribute::attributeIndex() const
247{
248    return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(attributeIndex));
249}
250
251// property: attributeType
252_MTL_INLINE MTL::DataType MTL::VertexAttribute::attributeType() const
253{
254    return Object::sendMessage<MTL::DataType>(this, _MTL_PRIVATE_SEL(attributeType));
255}
256
257// property: active
258_MTL_INLINE bool MTL::VertexAttribute::active() const
259{
260    return Object::sendMessage<bool>(this, _MTL_PRIVATE_SEL(isActive));
261}
262
263// property: patchData
264_MTL_INLINE bool MTL::VertexAttribute::patchData() const
265{
266    return Object::sendMessage<bool>(this, _MTL_PRIVATE_SEL(isPatchData));
267}
268
269// property: patchControlPointData
270_MTL_INLINE bool MTL::VertexAttribute::patchControlPointData() const
271{
272    return Object::sendMessage<bool>(this, _MTL_PRIVATE_SEL(isPatchControlPointData));
273}
274
275// static method: alloc
276_MTL_INLINE MTL::Attribute* MTL::Attribute::alloc()
277{
278    return NS::Object::alloc<MTL::Attribute>(_MTL_PRIVATE_CLS(MTLAttribute));
279}
280
281// method: init
282_MTL_INLINE MTL::Attribute* MTL::Attribute::init()
283{
284    return NS::Object::init<MTL::Attribute>();
285}
286
287// property: name
288_MTL_INLINE NS::String* MTL::Attribute::name() const
289{
290    return Object::sendMessage<NS::String*>(this, _MTL_PRIVATE_SEL(name));
291}
292
293// property: attributeIndex
294_MTL_INLINE NS::UInteger MTL::Attribute::attributeIndex() const
295{
296    return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(attributeIndex));
297}
298
299// property: attributeType
300_MTL_INLINE MTL::DataType MTL::Attribute::attributeType() const
301{
302    return Object::sendMessage<MTL::DataType>(this, _MTL_PRIVATE_SEL(attributeType));
303}
304
305// property: active
306_MTL_INLINE bool MTL::Attribute::active() const
307{
308    return Object::sendMessage<bool>(this, _MTL_PRIVATE_SEL(isActive));
309}
310
311// property: patchData
312_MTL_INLINE bool MTL::Attribute::patchData() const
313{
314    return Object::sendMessage<bool>(this, _MTL_PRIVATE_SEL(isPatchData));
315}
316
317// property: patchControlPointData
318_MTL_INLINE bool MTL::Attribute::patchControlPointData() const
319{
320    return Object::sendMessage<bool>(this, _MTL_PRIVATE_SEL(isPatchControlPointData));
321}
322
323// static method: alloc
324_MTL_INLINE MTL::FunctionConstant* MTL::FunctionConstant::alloc()
325{
326    return NS::Object::alloc<MTL::FunctionConstant>(_MTL_PRIVATE_CLS(MTLFunctionConstant));
327}
328
329// method: init
330_MTL_INLINE MTL::FunctionConstant* MTL::FunctionConstant::init()
331{
332    return NS::Object::init<MTL::FunctionConstant>();
333}
334
335// property: name
336_MTL_INLINE NS::String* MTL::FunctionConstant::name() const
337{
338    return Object::sendMessage<NS::String*>(this, _MTL_PRIVATE_SEL(name));
339}
340
341// property: type
342_MTL_INLINE MTL::DataType MTL::FunctionConstant::type() const
343{
344    return Object::sendMessage<MTL::DataType>(this, _MTL_PRIVATE_SEL(type));
345}
346
347// property: index
348_MTL_INLINE NS::UInteger MTL::FunctionConstant::index() const
349{
350    return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(index));
351}
352
353// property: required
354_MTL_INLINE bool MTL::FunctionConstant::required() const
355{
356    return Object::sendMessage<bool>(this, _MTL_PRIVATE_SEL(required));
357}
358
359// property: label
360_MTL_INLINE NS::String* MTL::Function::label() const
361{
362    return Object::sendMessage<NS::String*>(this, _MTL_PRIVATE_SEL(label));
363}
364
365_MTL_INLINE void MTL::Function::setLabel(const NS::String* label)
366{
367    Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(setLabel_), label);
368}
369
370// property: device
371_MTL_INLINE MTL::Device* MTL::Function::device() const
372{
373    return Object::sendMessage<MTL::Device*>(this, _MTL_PRIVATE_SEL(device));
374}
375
376// property: functionType
377_MTL_INLINE MTL::FunctionType MTL::Function::functionType() const
378{
379    return Object::sendMessage<MTL::FunctionType>(this, _MTL_PRIVATE_SEL(functionType));
380}
381
382// property: patchType
383_MTL_INLINE MTL::PatchType MTL::Function::patchType() const
384{
385    return Object::sendMessage<MTL::PatchType>(this, _MTL_PRIVATE_SEL(patchType));
386}
387
388// property: patchControlPointCount
389_MTL_INLINE NS::Integer MTL::Function::patchControlPointCount() const
390{
391    return Object::sendMessage<NS::Integer>(this, _MTL_PRIVATE_SEL(patchControlPointCount));
392}
393
394// property: vertexAttributes
395_MTL_INLINE NS::Array* MTL::Function::vertexAttributes() const
396{
397    return Object::sendMessage<NS::Array*>(this, _MTL_PRIVATE_SEL(vertexAttributes));
398}
399
400// property: stageInputAttributes
401_MTL_INLINE NS::Array* MTL::Function::stageInputAttributes() const
402{
403    return Object::sendMessage<NS::Array*>(this, _MTL_PRIVATE_SEL(stageInputAttributes));
404}
405
406// property: name
407_MTL_INLINE NS::String* MTL::Function::name() const
408{
409    return Object::sendMessage<NS::String*>(this, _MTL_PRIVATE_SEL(name));
410}
411
412// property: functionConstantsDictionary
413_MTL_INLINE NS::Dictionary* MTL::Function::functionConstantsDictionary() const
414{
415    return Object::sendMessage<NS::Dictionary*>(this, _MTL_PRIVATE_SEL(functionConstantsDictionary));
416}
417
418// method: newArgumentEncoderWithBufferIndex:
419_MTL_INLINE MTL::ArgumentEncoder* MTL::Function::newArgumentEncoder(NS::UInteger bufferIndex)
420{
421    return Object::sendMessage<MTL::ArgumentEncoder*>(this, _MTL_PRIVATE_SEL(newArgumentEncoderWithBufferIndex_), bufferIndex);
422}
423
424// method: newArgumentEncoderWithBufferIndex:reflection:
425_MTL_INLINE MTL::ArgumentEncoder* MTL::Function::newArgumentEncoder(NS::UInteger bufferIndex, const MTL::AutoreleasedArgument* reflection)
426{
427    return Object::sendMessage<MTL::ArgumentEncoder*>(this, _MTL_PRIVATE_SEL(newArgumentEncoderWithBufferIndex_reflection_), bufferIndex, reflection);
428}
429
430// property: options
431_MTL_INLINE MTL::FunctionOptions MTL::Function::options() const
432{
433    return Object::sendMessage<MTL::FunctionOptions>(this, _MTL_PRIVATE_SEL(options));
434}
435
436// static method: alloc
437_MTL_INLINE MTL::CompileOptions* MTL::CompileOptions::alloc()
438{
439    return NS::Object::alloc<MTL::CompileOptions>(_MTL_PRIVATE_CLS(MTLCompileOptions));
440}
441
442// method: init
443_MTL_INLINE MTL::CompileOptions* MTL::CompileOptions::init()
444{
445    return NS::Object::init<MTL::CompileOptions>();
446}
447
448// property: preprocessorMacros
449_MTL_INLINE NS::Dictionary* MTL::CompileOptions::preprocessorMacros() const
450{
451    return Object::sendMessage<NS::Dictionary*>(this, _MTL_PRIVATE_SEL(preprocessorMacros));
452}
453
454_MTL_INLINE void MTL::CompileOptions::setPreprocessorMacros(const NS::Dictionary* preprocessorMacros)
455{
456    Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(setPreprocessorMacros_), preprocessorMacros);
457}
458
459// property: fastMathEnabled
460_MTL_INLINE bool MTL::CompileOptions::fastMathEnabled() const
461{
462    return Object::sendMessage<bool>(this, _MTL_PRIVATE_SEL(fastMathEnabled));
463}
464
465_MTL_INLINE void MTL::CompileOptions::setFastMathEnabled(bool fastMathEnabled)
466{
467    Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(setFastMathEnabled_), fastMathEnabled);
468}
469
470// property: languageVersion
471_MTL_INLINE MTL::LanguageVersion MTL::CompileOptions::languageVersion() const
472{
473    return Object::sendMessage<MTL::LanguageVersion>(this, _MTL_PRIVATE_SEL(languageVersion));
474}
475
476_MTL_INLINE void MTL::CompileOptions::setLanguageVersion(MTL::LanguageVersion languageVersion)
477{
478    Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(setLanguageVersion_), languageVersion);
479}
480
481// property: libraryType
482_MTL_INLINE MTL::LibraryType MTL::CompileOptions::libraryType() const
483{
484    return Object::sendMessage<MTL::LibraryType>(this, _MTL_PRIVATE_SEL(libraryType));
485}
486
487_MTL_INLINE void MTL::CompileOptions::setLibraryType(MTL::LibraryType libraryType)
488{
489    Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(setLibraryType_), libraryType);
490}
491
492// property: installName
493_MTL_INLINE NS::String* MTL::CompileOptions::installName() const
494{
495    return Object::sendMessage<NS::String*>(this, _MTL_PRIVATE_SEL(installName));
496}
497
498_MTL_INLINE void MTL::CompileOptions::setInstallName(const NS::String* installName)
499{
500    Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(setInstallName_), installName);
501}
502
503// property: libraries
504_MTL_INLINE NS::Array* MTL::CompileOptions::libraries() const
505{
506    return Object::sendMessage<NS::Array*>(this, _MTL_PRIVATE_SEL(libraries));
507}
508
509_MTL_INLINE void MTL::CompileOptions::setLibraries(const NS::Array* libraries)
510{
511    Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(setLibraries_), libraries);
512}
513
514// property: preserveInvariance
515_MTL_INLINE bool MTL::CompileOptions::preserveInvariance() const
516{
517    return Object::sendMessage<bool>(this, _MTL_PRIVATE_SEL(preserveInvariance));
518}
519
520_MTL_INLINE void MTL::CompileOptions::setPreserveInvariance(bool preserveInvariance)
521{
522    Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(setPreserveInvariance_), preserveInvariance);
523}
524
525_MTL_INLINE void MTL::Library::newFunction(const NS::String* pFunctionName, const FunctionConstantValues* pConstantValues, const std::function<void(Function* pFunction, NS::Error* pError)>& completionHandler)
526{
527    __block std::function<void(Function * pFunction, NS::Error * pError)> blockCompletionHandler = completionHandler;
528
529    newFunction(pFunctionName, pConstantValues, ^(Function* pFunction, NS::Error* pError) { blockCompletionHandler(pFunction, pError); });
530}
531
532_MTL_INLINE void MTL::Library::newFunction(const FunctionDescriptor* pDescriptor, const std::function<void(Function* pFunction, NS::Error* pError)>& completionHandler)
533{
534    __block std::function<void(Function * pFunction, NS::Error * pError)> blockCompletionHandler = completionHandler;
535
536    newFunction(pDescriptor, ^(Function* pFunction, NS::Error* pError) { blockCompletionHandler(pFunction, pError); });
537}
538
539_MTL_INLINE void MTL::Library::newIntersectionFunction(const IntersectionFunctionDescriptor* pDescriptor, const std::function<void(Function* pFunction, NS::Error* pError)>& completionHandler)
540{
541    __block std::function<void(Function * pFunction, NS::Error * pError)> blockCompletionHandler = completionHandler;
542
543    newIntersectionFunction(pDescriptor, ^(Function* pFunction, NS::Error* pError) { blockCompletionHandler(pFunction, pError); });
544}
545
546// property: label
547_MTL_INLINE NS::String* MTL::Library::label() const
548{
549    return Object::sendMessage<NS::String*>(this, _MTL_PRIVATE_SEL(label));
550}
551
552_MTL_INLINE void MTL::Library::setLabel(const NS::String* label)
553{
554    Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(setLabel_), label);
555}
556
557// property: device
558_MTL_INLINE MTL::Device* MTL::Library::device() const
559{
560    return Object::sendMessage<MTL::Device*>(this, _MTL_PRIVATE_SEL(device));
561}
562
563// method: newFunctionWithName:
564_MTL_INLINE MTL::Function* MTL::Library::newFunction(const NS::String* functionName)
565{
566    return Object::sendMessage<MTL::Function*>(this, _MTL_PRIVATE_SEL(newFunctionWithName_), functionName);
567}
568
569// method: newFunctionWithName:constantValues:error:
570_MTL_INLINE MTL::Function* MTL::Library::newFunction(const NS::String* name, const MTL::FunctionConstantValues* constantValues, NS::Error** error)
571{
572    return Object::sendMessage<MTL::Function*>(this, _MTL_PRIVATE_SEL(newFunctionWithName_constantValues_error_), name, constantValues, error);
573}
574
575// method: newFunctionWithName:constantValues:completionHandler:
576_MTL_INLINE void MTL::Library::newFunction(const NS::String* name, const MTL::FunctionConstantValues* constantValues, void (^completionHandler)(MTL::Function*, NS::Error*))
577{
578    Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(newFunctionWithName_constantValues_completionHandler_), name, constantValues, completionHandler);
579}
580
581// method: newFunctionWithDescriptor:completionHandler:
582_MTL_INLINE void MTL::Library::newFunction(const MTL::FunctionDescriptor* descriptor, void (^completionHandler)(MTL::Function*, NS::Error*))
583{
584    Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(newFunctionWithDescriptor_completionHandler_), descriptor, completionHandler);
585}
586
587// method: newFunctionWithDescriptor:error:
588_MTL_INLINE MTL::Function* MTL::Library::newFunction(const MTL::FunctionDescriptor* descriptor, NS::Error** error)
589{
590    return Object::sendMessage<MTL::Function*>(this, _MTL_PRIVATE_SEL(newFunctionWithDescriptor_error_), descriptor, error);
591}
592
593// method: newIntersectionFunctionWithDescriptor:completionHandler:
594_MTL_INLINE void MTL::Library::newIntersectionFunction(const MTL::IntersectionFunctionDescriptor* descriptor, void (^completionHandler)(MTL::Function*, NS::Error*))
595{
596    Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(newIntersectionFunctionWithDescriptor_completionHandler_), descriptor, completionHandler);
597}
598
599// method: newIntersectionFunctionWithDescriptor:error:
600_MTL_INLINE MTL::Function* MTL::Library::newIntersectionFunction(const MTL::IntersectionFunctionDescriptor* descriptor, NS::Error** error)
601{
602    return Object::sendMessage<MTL::Function*>(this, _MTL_PRIVATE_SEL(newIntersectionFunctionWithDescriptor_error_), descriptor, error);
603}
604
605// property: functionNames
606_MTL_INLINE NS::Array* MTL::Library::functionNames() const
607{
608    return Object::sendMessage<NS::Array*>(this, _MTL_PRIVATE_SEL(functionNames));
609}
610
611// property: type
612_MTL_INLINE MTL::LibraryType MTL::Library::type() const
613{
614    return Object::sendMessage<MTL::LibraryType>(this, _MTL_PRIVATE_SEL(type));
615}
616
617// property: installName
618_MTL_INLINE NS::String* MTL::Library::installName() const
619{
620    return Object::sendMessage<NS::String*>(this, _MTL_PRIVATE_SEL(installName));
621}