svf-lib 1.0.1585 → 1.0.1587

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -217,9 +217,9 @@ public:
217
217
  this->totalKind = totalKind;
218
218
  }
219
219
 
220
- std::string extractKindStrFromSymbolStr(const std::string symbolStr) const;
220
+ std::string extractKindStrFromSymbolStr(const std::string& symbolStr) const;
221
221
 
222
- std::string extractAttributeStrFromSymbolStr(const std::string symbolStr) const;
222
+ std::string extractAttributeStrFromSymbolStr(const std::string& symbolStr) const;
223
223
 
224
224
  void setRawProductions(SymbolMap<Symbol, Productions>& rawProductions);
225
225
 
@@ -429,6 +429,7 @@ private:
429
429
  cJSON* toJson(const SVFLoopAndDomInfo* ldInfo); // Only owned by SVFFunction
430
430
  cJSON* toJson(const StInfo* stInfo);
431
431
 
432
+ // No need for 'toJson(short)' because of promotion to int
432
433
  static cJSON* toJson(bool flag);
433
434
  static cJSON* toJson(unsigned number);
434
435
  static cJSON* toJson(int number);
@@ -1044,6 +1045,7 @@ public:
1044
1045
  static void readJson(const cJSON* obj, bool& flag);
1045
1046
  static void readJson(const cJSON* obj, unsigned& val);
1046
1047
  static void readJson(const cJSON* obj, int& val);
1048
+ static void readJson(const cJSON* obj, short& val);
1047
1049
  static void readJson(const cJSON* obj, float& val);
1048
1050
  static void readJson(const cJSON* obj, unsigned long& val);
1049
1051
  static void readJson(const cJSON* obj, long long& val);
@@ -282,11 +282,11 @@ public:
282
282
  return kind;
283
283
  }
284
284
 
285
- /// Note: Use `os<<svfType` or `svfType.print(os)` when possible to avoid
285
+ /// \note Use `os<<svfType` or `svfType.print(os)` when possible to avoid
286
286
  /// string concatenation.
287
287
  std::string toString() const;
288
288
 
289
- virtual void print(std::ostream& OS) const = 0;
289
+ virtual void print(std::ostream& os) const = 0;
290
290
 
291
291
  inline void setPointerTo(const SVFPointerType* ty)
292
292
  {
@@ -327,7 +327,7 @@ public:
327
327
  }
328
328
  };
329
329
 
330
- std::ostream& operator<<(std::ostream& OS, const SVFType& type);
330
+ std::ostream& operator<<(std::ostream& os, const SVFType& type);
331
331
 
332
332
  class SVFPointerType : public SVFType
333
333
  {
@@ -351,11 +351,17 @@ public:
351
351
  return ptrElementType;
352
352
  }
353
353
 
354
- void print(std::ostream& OS) const override;
354
+ void print(std::ostream& os) const override;
355
355
  };
356
356
 
357
357
  class SVFIntegerType : public SVFType
358
358
  {
359
+ friend class SVFIRWriter;
360
+ friend class SVFIRReader;
361
+
362
+ private:
363
+ short signAndWidth; ///< For printing
364
+
359
365
  public:
360
366
  SVFIntegerType() : SVFType(true, SVFIntegerTy) {}
361
367
  static inline bool classof(const SVFType* node)
@@ -363,7 +369,17 @@ public:
363
369
  return node->getKind() == SVFIntegerTy;
364
370
  }
365
371
 
366
- void print(std::ostream& OS) const override;
372
+ void print(std::ostream& os) const override;
373
+
374
+ void setSignAndWidth(short sw)
375
+ {
376
+ signAndWidth = sw;
377
+ }
378
+
379
+ bool isSigned() const
380
+ {
381
+ return signAndWidth < 0;
382
+ }
367
383
  };
368
384
 
369
385
  class SVFFunctionType : public SVFType
@@ -388,7 +404,7 @@ public:
388
404
  return retTy;
389
405
  }
390
406
 
391
- void print(std::ostream& OS) const override;
407
+ void print(std::ostream& os) const override;
392
408
  };
393
409
 
394
410
  class SVFStructType : public SVFType
@@ -397,6 +413,7 @@ class SVFStructType : public SVFType
397
413
  friend class SVFIRReader;
398
414
 
399
415
  private:
416
+ /// @brief Field for printing & debugging
400
417
  std::string name;
401
418
 
402
419
  public:
@@ -407,12 +424,20 @@ public:
407
424
  return node->getKind() == SVFStructTy;
408
425
  }
409
426
 
410
- void print(std::ostream& OS) const override;
427
+ void print(std::ostream& os) const override;
411
428
 
412
- std::string& getName()
429
+ const std::string& getName()
413
430
  {
414
431
  return name;
415
432
  }
433
+ void setName(const std::string& structName)
434
+ {
435
+ name = structName;
436
+ }
437
+ void setName(std::string&& structName)
438
+ {
439
+ name = std::move(structName);
440
+ }
416
441
  };
417
442
 
418
443
  class SVFArrayType : public SVFType
@@ -421,8 +446,8 @@ class SVFArrayType : public SVFType
421
446
  friend class SVFIRReader;
422
447
 
423
448
  private:
424
- unsigned numOfElement; /// For printing
425
- SVFType* typeOfElement; /// For printing
449
+ unsigned numOfElement; /// For printing & debugging
450
+ const SVFType* typeOfElement; /// For printing & debugging
426
451
 
427
452
  public:
428
453
  SVFArrayType()
@@ -435,9 +460,9 @@ public:
435
460
  return node->getKind() == SVFArrayTy;
436
461
  }
437
462
 
438
- void print(std::ostream& OS) const override;
463
+ void print(std::ostream& os) const override;
439
464
 
440
- void setTypeOfElement(SVFType* elemType)
465
+ void setTypeOfElement(const SVFType* elemType)
441
466
  {
442
467
  typeOfElement = elemType;
443
468
  }
@@ -464,12 +489,22 @@ public:
464
489
  return node->getKind() == SVFOtherTy;
465
490
  }
466
491
 
467
- std::string& getRepr()
492
+ const std::string& getRepr()
468
493
  {
469
494
  return repr;
470
495
  }
471
496
 
472
- void print(std::ostream& OS) const override;
497
+ void setRepr(std::string&& r)
498
+ {
499
+ repr = std::move(r);
500
+ }
501
+
502
+ void setRepr(const std::string& r)
503
+ {
504
+ repr = r;
505
+ }
506
+
507
+ void print(std::ostream& os) const override;
473
508
  };
474
509
 
475
510
  /// [FOR DEBUG ONLY, DON'T USE IT UNSIDE `svf`!]
@@ -183,17 +183,17 @@ private:
183
183
 
184
184
  protected:
185
185
  const SVFType* type; ///< Type of this SVFValue
186
- std::string name; ///< Short name of this value for debugging
186
+ std::string name; ///< Short name of value for printing & debugging
187
187
  std::string sourceLoc; ///< Source code information of this value
188
- /// Constructor
189
- SVFValue(const std::string& val, const SVFType* ty, SVFValKind k)
188
+ /// Constructor without name
189
+ SVFValue(const SVFType* ty, SVFValKind k)
190
190
  : kind(k), ptrInUncalledFun(false),
191
- constDataOrAggData(SVFConstData == k), type(ty), name(val),
192
- sourceLoc("No source code Info")
191
+ constDataOrAggData(SVFConstData == k), type(ty), sourceLoc("NoLoc")
193
192
  {
194
193
  }
195
194
 
196
- ///@{ attributes to be set only through Module builders e.g., LLVMModule
195
+ ///@{ attributes to be set only through Module builders e.g.,
196
+ /// LLVMModule
197
197
  inline void setConstDataOrAggData()
198
198
  {
199
199
  constDataOrAggData = true;
@@ -213,14 +213,17 @@ public:
213
213
  return kind;
214
214
  }
215
215
 
216
- // TODO: (Optimization) Returns `const std::string&`?
217
- inline virtual const std::string getName() const
216
+ inline const std::string &getName() const
218
217
  {
219
218
  return name;
220
219
  }
221
- inline virtual void setName(const std::string& valueName)
220
+ inline void setName(const std::string& n)
221
+ {
222
+ name = n;
223
+ }
224
+ inline void setName(std::string&& n)
222
225
  {
223
- name = valueName;
226
+ name = std::move(n);
224
227
  }
225
228
 
226
229
  inline virtual const SVFType* getType() const
@@ -252,15 +255,18 @@ public:
252
255
  return sourceLoc;
253
256
  }
254
257
 
255
- /// Needs to be implemented by a specific SVF front end (e.g., the implementation in LLVMUtil)
256
- virtual const std::string toString() const;
258
+ /// \note Use `os<<SVFvalue` or `svfValue.print(os)` when possible to avoid
259
+ /// string concatenation.
260
+ std::string toString() const;
261
+
262
+ virtual void print(OutStream& os) const = 0;
257
263
 
258
264
  /// Overloading operator << for dumping ICFG node ID
259
265
  //@{
260
- friend OutStream& operator<< (OutStream &o, const SVFValue &node)
266
+ friend OutStream& operator<<(OutStream &os, const SVFValue &value)
261
267
  {
262
- o << node.toString();
263
- return o;
268
+ value.print(os);
269
+ return os;
264
270
  }
265
271
  //@}
266
272
  };
@@ -291,7 +297,6 @@ private:
291
297
  std::vector<const SVFBasicBlock*> allBBs; /// all BasicBlocks of this function
292
298
  std::vector<const SVFArgument*> allArgs; /// all formal arguments of this function
293
299
 
294
-
295
300
  protected:
296
301
  ///@{ attributes to be set only through Module builders e.g., LLVMModule
297
302
  inline void addBasicBlock(const SVFBasicBlock* bb)
@@ -321,8 +326,7 @@ protected:
321
326
  /// @}
322
327
 
323
328
  public:
324
- SVFFunction(const std::string& f, const SVFType* ty,const SVFFunctionType* ft, bool declare, bool intrinsic, bool addrTaken, bool varg, SVFLoopAndDomInfo* ld);
325
- SVFFunction(const std::string& f) = delete;
329
+ SVFFunction(const SVFType* ty,const SVFFunctionType* ft, bool declare, bool intrinsic, bool addrTaken, bool varg, SVFLoopAndDomInfo* ld);
326
330
  SVFFunction(void) = delete;
327
331
  virtual ~SVFFunction();
328
332
 
@@ -331,6 +335,8 @@ public:
331
335
  return node->getKind() == SVFFunc;
332
336
  }
333
337
 
338
+ void print(OutStream& os) const override;
339
+
334
340
  inline SVFLoopAndDomInfo* getLoopAndDomInfo()
335
341
  {
336
342
  return loopAndDom;
@@ -479,7 +485,6 @@ public:
479
485
  {
480
486
  return loopAndDom->postDominate(bbKey,bbValue);
481
487
  }
482
-
483
488
  };
484
489
 
485
490
  class SVFBasicBlock : public SVFValue
@@ -517,7 +522,8 @@ protected:
517
522
  /// @}
518
523
 
519
524
  public:
520
- SVFBasicBlock(const std::string& b, const SVFType* ty, const SVFFunction* f);
525
+ /// Constructor without name
526
+ SVFBasicBlock(const SVFType* ty, const SVFFunction* f);
521
527
  SVFBasicBlock() = delete;
522
528
  ~SVFBasicBlock() override;
523
529
 
@@ -526,6 +532,8 @@ public:
526
532
  return node->getKind() == SVFBB;
527
533
  }
528
534
 
535
+ void print(OutStream& os) const override;
536
+
529
537
  inline const std::vector<const SVFInstruction*>& getInstructionList() const
530
538
  {
531
539
  return allInsts;
@@ -599,8 +607,9 @@ private:
599
607
  InstVec predInsts; /// predecessor Instructions
600
608
 
601
609
  public:
602
- SVFInstruction(const std::string& i, const SVFType* ty, const SVFBasicBlock* b, bool tm, bool isRet, SVFValKind k = SVFInst);
603
- SVFInstruction(const std::string& i) = delete;
610
+ /// Constructor without name, set name with setName()
611
+ SVFInstruction(const SVFType* ty, const SVFBasicBlock* b, bool tm,
612
+ bool isRet, SVFValKind k = SVFInst);
604
613
  SVFInstruction(void) = delete;
605
614
 
606
615
  static inline bool classof(const SVFValue *node)
@@ -610,6 +619,8 @@ public:
610
619
  node->getKind() == SVFVCall;
611
620
  }
612
621
 
622
+ void print(OutStream& os) const override;
623
+
613
624
  inline const SVFBasicBlock* getParent() const
614
625
  {
615
626
  return bb;
@@ -676,11 +687,10 @@ protected:
676
687
  /// @}
677
688
 
678
689
  public:
679
- SVFCallInst(const std::string& i, const SVFType* ty, const SVFBasicBlock* b, bool va, bool tm, SVFValKind k = SVFCall) :
680
- SVFInstruction(i, ty, b, tm, false, k), varArg(va), calledVal(nullptr)
690
+ SVFCallInst(const SVFType* ty, const SVFBasicBlock* b, bool va, bool tm, SVFValKind k = SVFCall) :
691
+ SVFInstruction(ty, b, tm, false, k), varArg(va), calledVal(nullptr)
681
692
  {
682
693
  }
683
- SVFCallInst(const std::string& i) = delete;
684
694
  SVFCallInst(void) = delete;
685
695
 
686
696
  static inline bool classof(const SVFValue *node)
@@ -752,8 +762,10 @@ protected:
752
762
  }
753
763
 
754
764
  public:
755
- SVFVirtualCallInst(const std::string& i, const SVFType* ty, const SVFBasicBlock* b, bool vararg, bool tm) :
756
- SVFCallInst(i,ty,b,vararg,tm, SVFVCall), vCallVtblPtr(nullptr), virtualFunIdx(-1), funNameOfVcall("")
765
+ SVFVirtualCallInst(const SVFType* ty, const SVFBasicBlock* b, bool vararg,
766
+ bool tm)
767
+ : SVFCallInst(ty, b, vararg, tm, SVFVCall), vCallVtblPtr(nullptr),
768
+ virtualFunIdx(-1), funNameOfVcall()
757
769
  {
758
770
  }
759
771
  inline const SVFValue* getVtablePtr() const
@@ -789,7 +801,7 @@ class SVFConstant : public SVFValue
789
801
  friend class SVFIRWriter;
790
802
  friend class SVFIRReader;
791
803
  public:
792
- SVFConstant(const std::string& _const, const SVFType* ty, SVFValKind k = SVFConst): SVFValue(_const, ty, k)
804
+ SVFConstant(const SVFType* ty, SVFValKind k = SVFConst): SVFValue(ty, k)
793
805
  {
794
806
  }
795
807
  SVFConstant() = delete;
@@ -804,6 +816,8 @@ public:
804
816
  node->getKind() == SVFNullPtr ||
805
817
  node->getKind() == SVFBlackHole;
806
818
  }
819
+
820
+ void print(OutStream& os) const override;
807
821
  };
808
822
 
809
823
  class SVFGlobalValue : public SVFConstant
@@ -822,11 +836,16 @@ protected:
822
836
  }
823
837
 
824
838
  public:
825
- SVFGlobalValue(const std::string& _gv, const SVFType* ty): SVFConstant(_gv, ty, SVFValue::SVFGlob), realDefGlobal(nullptr)
839
+ SVFGlobalValue(const SVFType* ty): SVFConstant(ty, SVFValue::SVFGlob), realDefGlobal(nullptr)
826
840
  {
827
841
  }
842
+ SVFGlobalValue(std::string&& name, const SVFType* ty) : SVFGlobalValue(ty)
843
+ {
844
+ setName(std::move(name));
845
+ }
828
846
  SVFGlobalValue() = delete;
829
847
 
848
+ void print(OutStream& os) const override;
830
849
 
831
850
  inline const SVFValue* getDefGlobalForMultipleModule() const
832
851
  {
@@ -853,11 +872,16 @@ private:
853
872
  u32_t argNo;
854
873
  bool uncalled;
855
874
  public:
856
- SVFArgument(const std::string& _arg, const SVFType* ty, const SVFFunction* _fun, u32_t _argNo, bool _uncalled): SVFValue(_arg, ty, SVFValue::SVFArg), fun(_fun), argNo(_argNo), uncalled(_uncalled)
875
+ SVFArgument(const SVFType* ty, const SVFFunction* fun, u32_t argNo,
876
+ bool uncalled)
877
+ : SVFValue(ty, SVFValue::SVFArg), fun(fun), argNo(argNo),
878
+ uncalled(uncalled)
857
879
  {
858
880
  }
859
881
  SVFArgument() = delete;
860
882
 
883
+ void print(OutStream& os) const override;
884
+
861
885
  inline const SVFFunction* getParent() const
862
886
  {
863
887
  return fun;
@@ -881,18 +905,19 @@ public:
881
905
  }
882
906
  };
883
907
 
884
-
885
-
886
908
  class SVFConstantData : public SVFConstant
887
909
  {
888
910
  friend class SVFIRWriter;
889
911
  friend class SVFIRReader;
890
912
  public:
891
- SVFConstantData(const std::string& _const, const SVFType* ty, SVFValKind k = SVFConstData): SVFConstant(_const, ty, k)
913
+ SVFConstantData(const SVFType* ty, SVFValKind k = SVFConstData)
914
+ : SVFConstant(ty, k)
892
915
  {
893
916
  }
894
917
  SVFConstantData() = delete;
895
918
 
919
+ void print(OutStream& os) const override;
920
+
896
921
  static inline bool classof(const SVFValue *node)
897
922
  {
898
923
  return node->getKind() == SVFConstData ||
@@ -911,7 +936,6 @@ public:
911
936
  }
912
937
  };
913
938
 
914
-
915
939
  class SVFConstantInt : public SVFConstantData
916
940
  {
917
941
  friend class SVFIRWriter;
@@ -920,11 +944,14 @@ private:
920
944
  u64_t zval;
921
945
  s64_t sval;
922
946
  public:
923
- SVFConstantInt(const std::string& _const, const SVFType* ty, u64_t z, s64_t s): SVFConstantData(_const, ty, SVFValue::SVFConstInt), zval(z), sval(s)
947
+ SVFConstantInt(const SVFType* ty, u64_t z, s64_t s)
948
+ : SVFConstantData(ty, SVFValue::SVFConstInt), zval(z), sval(s)
924
949
  {
925
950
  }
926
951
  SVFConstantInt() = delete;
927
952
 
953
+ void print(OutStream& os) const override;
954
+
928
955
  static inline bool classof(const SVFValue *node)
929
956
  {
930
957
  return node->getKind() == SVFConstInt;
@@ -945,7 +972,6 @@ public:
945
972
  }
946
973
  };
947
974
 
948
-
949
975
  class SVFConstantFP : public SVFConstantData
950
976
  {
951
977
  friend class SVFIRWriter;
@@ -953,11 +979,14 @@ class SVFConstantFP : public SVFConstantData
953
979
  private:
954
980
  float dval;
955
981
  public:
956
- SVFConstantFP(const std::string& _const, const SVFType* ty, double d): SVFConstantData(_const, ty, SVFValue::SVFConstFP), dval(d)
982
+ SVFConstantFP(const SVFType* ty, double d)
983
+ : SVFConstantData(ty, SVFValue::SVFConstFP), dval(d)
957
984
  {
958
985
  }
959
986
  SVFConstantFP() = delete;
960
987
 
988
+ void print(OutStream& os) const override;
989
+
961
990
  inline double getFPValue () const
962
991
  {
963
992
  return dval;
@@ -972,18 +1001,20 @@ public:
972
1001
  }
973
1002
  };
974
1003
 
975
-
976
1004
  class SVFConstantNullPtr : public SVFConstantData
977
1005
  {
978
1006
  friend class SVFIRWriter;
979
1007
  friend class SVFIRReader;
980
1008
 
981
1009
  public:
982
- SVFConstantNullPtr(const std::string& _const, const SVFType* ty): SVFConstantData(_const, ty, SVFValue::SVFNullPtr)
1010
+ SVFConstantNullPtr(const SVFType* ty)
1011
+ : SVFConstantData(ty, SVFValue::SVFNullPtr)
983
1012
  {
984
1013
  }
985
1014
  SVFConstantNullPtr() = delete;
986
1015
 
1016
+ void print(OutStream& os) const override;
1017
+
987
1018
  static inline bool classof(const SVFValue *node)
988
1019
  {
989
1020
  return node->getKind() == SVFNullPtr;
@@ -1000,11 +1031,14 @@ class SVFBlackHoleValue : public SVFConstantData
1000
1031
  friend class SVFIRReader;
1001
1032
 
1002
1033
  public:
1003
- SVFBlackHoleValue(const std::string& _const, const SVFType* ty): SVFConstantData(_const, ty, SVFValue::SVFBlackHole)
1034
+ SVFBlackHoleValue(const SVFType* ty)
1035
+ : SVFConstantData(ty, SVFValue::SVFBlackHole)
1004
1036
  {
1005
1037
  }
1006
1038
  SVFBlackHoleValue() = delete;
1007
1039
 
1040
+ void print(OutStream& os) const override;
1041
+
1008
1042
  static inline bool classof(const SVFValue *node)
1009
1043
  {
1010
1044
  return node->getKind() == SVFBlackHole;
@@ -1020,7 +1054,8 @@ class SVFOtherValue : public SVFValue
1020
1054
  friend class SVFIRWriter;
1021
1055
  friend class SVFIRReader;
1022
1056
  public:
1023
- SVFOtherValue(const std::string& other, const SVFType* ty, SVFValKind k = SVFValue::SVFOther): SVFValue(other, ty, k)
1057
+ SVFOtherValue(const SVFType* ty, SVFValKind k = SVFValue::SVFOther)
1058
+ : SVFValue(ty, k)
1024
1059
  {
1025
1060
  }
1026
1061
  SVFOtherValue() = delete;
@@ -1029,6 +1064,8 @@ public:
1029
1064
  {
1030
1065
  return node->getKind() == SVFOther || node->getKind() == SVFMetaAsValue;
1031
1066
  }
1067
+
1068
+ void print(OutStream& os) const override;
1032
1069
  };
1033
1070
 
1034
1071
  /*
@@ -1039,7 +1076,8 @@ class SVFMetadataAsValue : public SVFOtherValue
1039
1076
  friend class SVFIRWriter;
1040
1077
  friend class SVFIRReader;
1041
1078
  public:
1042
- SVFMetadataAsValue(const std::string& other, const SVFType* ty): SVFOtherValue(other, ty, SVFValue::SVFMetaAsValue)
1079
+ SVFMetadataAsValue(const SVFType* ty)
1080
+ : SVFOtherValue(ty, SVFValue::SVFMetaAsValue)
1043
1081
  {
1044
1082
  }
1045
1083
  SVFMetadataAsValue() = delete;
@@ -1052,6 +1090,8 @@ public:
1052
1090
  {
1053
1091
  return node->getKind() == SVFMetaAsValue;
1054
1092
  }
1093
+
1094
+ void print(OutStream& os) const override;
1055
1095
  };
1056
1096
 
1057
1097
 
@@ -54,13 +54,13 @@ public:
54
54
  void buildInternalMaps();
55
55
  void readInheritanceMetadataFromModule(const Module &M);
56
56
 
57
- CHNode *createNode(const std::string name);
57
+ CHNode *createNode(const std::string& name);
58
58
 
59
59
  void connectInheritEdgeViaCall(const Function* caller, const CallBase* cs);
60
60
  void connectInheritEdgeViaStore(const Function* caller, const StoreInst* store);
61
61
 
62
62
  void buildClassNameToAncestorsDescendantsMap();
63
- const CHGraph::CHNodeSetTy& getInstancesAndDescendants(const std::string className);
63
+ const CHGraph::CHNodeSetTy& getInstancesAndDescendants(const std::string& className);
64
64
 
65
65
  void analyzeVTables(const Module &M);
66
66
  void buildVirtualFunctionToIDMap();
@@ -482,6 +482,13 @@ bool VCallInCtorOrDtor(const CallBase* cs);
482
482
  bool isSameThisPtrInConstructor(const Argument* thisPtr1,
483
483
  const Value* thisPtr2);
484
484
 
485
+ template<typename T>
486
+ std::string llvmToString(const T& val)
487
+ {
488
+ std::string str;
489
+ llvm::raw_string_ostream(str) << val;
490
+ return str;
491
+ }
485
492
  } // End namespace LLVMUtil
486
493
 
487
494
  } // End namespace SVF
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svf-lib",
3
- "version": "1.0.1585",
3
+ "version": "1.0.1587",
4
4
  "description": "SVF's npm support",
5
5
  "main": "index.js",
6
6
  "scripts": {