| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626 | {  LkJSON v1.07  06 november 2009* Copyright (c) 2006,2007,2008,2009 Leonid Koninin* leon_kon@users.sourceforge.net* All rights reserved.** Redistribution and use in source and binary forms, with or without* modification, are permitted provided that the following conditions are met:*     * Redistributions of source code must retain the above copyright*       notice, this list of conditions and the following disclaimer.*     * Redistributions in binary form must reproduce the above copyright*       notice, this list of conditions and the following disclaimer in the*       documentation and/or other materials provided with the distribution.*     * Neither the name of the <organization> nor the*       names of its contributors may be used to endorse or promote products*       derived from this software without specific prior written permission.** THIS SOFTWARE IS PROVIDED BY Leonid Koninin ``AS IS'' AND ANY* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE* DISCLAIMED. IN NO EVENT SHALL Leonid Koninin BE LIABLE FOR ANY* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  changes:  v1.07 06/11/2009 * fixed a bug in js_string - thanks to Andrew G. Khodotov                   * fixed error with double-slashes - thanks to anonymous user                   * fixed a BOM bug in parser, thanks to jasper_dale  v1.06 13/03/2009 * fixed a bug in string parsing routine                   * looked routine from the Adrian M. Jones, and get some                     ideas from it; thanks a lot, Adrian!                   * checked error reported by phpop and fix it in the string                     routine; also, thanks for advice.  v1.05 26/01/2009 + added port to D2009 by Daniele Teti, thanx a lot! really,                     i haven't the 2009 version, so i can't play with it. I was                     add USE_D2009 directive below, disabled by default                   * fixed two small bugs in parsing object: errors with empty                     object and list; thanx to RSDN's delphi forum members                   * fixed "[2229135] Value deletion is broken" tracker                     issue, thanx to anonymous sender provided code for                     tree version                   * fixed js_string according to "[1917047] (much) faster                     js_string Parse" tracker issue by Joao Inacio; a lot of                     thanx, great speedup!  v1.04 05/04/2008 + a declaration of Field property moved from TlkJSONobject                     to TlkJSONbase; thanx for idea to Andrey Lukyanov; this                     improve objects use, look the bottom of SAMPLE2.DPR                   * fixed field name in TlkJSONobject to WideString  v1.03 14/03/2008 + added a code for generating readable JSON text, sended to                     me by Kusnassriyanto Saiful Bahri, thanx to him!                   * from this version, library distributed with BSD                     license, more pleasure for commercial programmers :)                   * was rewritten internal storing of objects, repacing                     hash tables with balanced trees (AA tree, by classic                     author's variant). On mine machine, with enabled fastmm,                     tree variant is about 30% slower in from-zero creation,                     but about 50% faster in parsing; also deletion of                     objects will be much faster than a hash-one.                     Hashes (old-style) can be switched on by enabling                     USE_HASH directive below  v1.02 14/09/2007 * fix mistypes in diffrent places; thanx for reports                     to Aleksandr Fedorov and Tobias Wrede  v1.01 18/05/2007 * fix small bug in new text generation routine, check                     library for leaks by fastmm4; thanx for idea and comments                     for Glynn Owen  v1.00 12/05/2007 * some fixes in new code (mistypes, mistypes...)                   * also many fixes by ideas of Henri Gourvest - big thanx                     for him again; he send me code for thread-safe initializing                     of hash table, some FPC-compatible issues (not tested by                     myself) and better code for localization in latest                     delphi versions; very, very big thanx!                   * rewritten procedure of json text generating, with wich                     work of it speeds up 4-5 times (on test) its good for                     a large objects                   * started a large work for making source code self-doc                     (not autodoc!)  v0.99 10/05/2007 + add functions to list and object:                      function getInt(idx: Integer): Integer;                      function getString(idx: Integer): String;                      function getWideString(idx: Integer):WideString;                      function getDouble(idx: Integer): Double;                      function getBoolean(idx: Integer): Boolean;                   + add overloaded functions to object:                      function getDouble(nm: String): Double; overload;                      function getInt(nm: String): Integer; overload;                      function getString(nm: String): String; overload;                      function getWideString(nm: String): WideString; overload;                      function getBoolean(nm: String): Boolean; overload;                   * changed storing mech of TlkJSONcustomlist descendants from                     dynamic array to TList; this gives us great speedup with                     lesser changes; thanx for idea to Henri Gourvest                   * also reworked hashtable to work with TList, so it also                     increase speed of work  v0.98 09/05/2007 * fix small bug in work with WideStrings(UTF8), thanx to                     IVO GELOV to description and sources  v0.97 10/04/2007 + add capabilities to work with KOL delphi projects; for                     this will define KOL variable in begin of text; of course,                     in this case object TlkJSONstreamed is not compiled.  v0.96 03/30/2007 + add TlkJSONFuncEnum and method ForEach in all                     TlkJSONcustomlist descendants                   + add property UseHash(r/o) to TlkJSONobject, and parameter                     UseHash:Boolean to object constructors; set it to false                     allow to disable using of hash-table, what can increase                     speed of work in case of objects with low number of                     methods(fields); [by default it is true]                   + added conditional compile directive DOTNET for use in .Net                     based delphi versions; remove dot in declaration below                     (thanx for idea and sample code to Tim Radford)                   + added property HashOf to TlkHashTable to allow use of                     users hash functions; on enter is widestring, on exit is                     cardinal (32 bit unsigned). Original HashOf renamed to                     DefaultHashOf                   * hash table object of TlkJSONobject wrapped by property called                     HashTable                   * fixed some minor bugs  v0.95 03/29/2007 + add object TlkJSONstreamed what descendant of TlkJSON and                     able to load/save JSON objects from/to streams/files.                   * fixed small bug in generating of unicode strings representation  v0.94 03/27/2007 + add properties NameOf and FieldByIndex to TlkJSONobject                   * fix small error in parsing unicode chars                   * small changes in hashing code (try to speed up)  v0.93 03/05/2007 + add overloaded functions to list and object                   + add enum type TlkJSONtypes                   + add functions: SelfType:TlkJSONtypes and                     SelfTypeName: String to every TlkJSONbase child                   * fix mistype 'IndefOfName' to 'IndexOfName'                   * fix mistype 'IndefOfObject' to 'IndexOfObject'  v0.92 03/02/2007 + add some fix to TlkJSON.ParseText to fix bug with parsing                     objects - object methods not always added properly                     to hash array (thanx to Chris Matheson)  ...}unit uLkJSON;{$IFDEF fpc}  {$MODE objfpc}  {$H+}  {.$DEFINE HAVE_FORMATSETTING}{$ELSE}  {$IF RTLVersion > 14.00}    {$DEFINE HAVE_FORMATSETTING}    {$IF RTLVersion > 19.00}      {$DEFINE USE_D2009}    {$IFEND}  {$IFEND}{$ENDIF}interface{.$DEFINE USE_D2009}{.$DEFINE KOL}{.$define DOTNET}{$DEFINE THREADSAFE}{$DEFINE NEW_STYLE_GENERATE}{.$DEFINE USE_HASH}{.$DEFINE TCB_EXT}uses windows,  SysUtils,{$IFNDEF KOL}  classes,{$ELSE}  kol,{$ENDIF}  variants;type  TlkJSONtypes = (jsBase, jsNumber, jsString, jsBoolean, jsNull,    jsList, jsObject);{$IFDEF DOTNET}  TlkJSONdotnetclass = class  public    constructor Create;    destructor Destroy; override;    procedure AfterConstruction; virtual;    procedure BeforeDestruction; virtual;  end;{$ENDIF DOTNET}  TlkJSONbase = class{$IFDEF DOTNET}(TlkJSONdotnetclass){$ENDIF}  protected    function GetValue: variant; virtual;    procedure SetValue(const AValue: variant); virtual;    function GetChild(idx: Integer): TlkJSONbase; virtual;    procedure SetChild(idx: Integer; const AValue: TlkJSONbase);      virtual;    function GetCount: Integer; virtual;    function GetField(AName: Variant):TlkJSONbase; virtual;  public    property Field[AName: Variant]: TlkJSONbase read GetField;    property Count: Integer read GetCount;    property Child[idx: Integer]: TlkJSONbase read GetChild write SetChild;    property Value: variant read GetValue write SetValue;    class function SelfType: TlkJSONtypes; virtual;    class function SelfTypeName: string; virtual;  end;  TlkJSONnumber = class(TlkJSONbase)  protected    FValue: extended;    function GetValue: Variant; override;    procedure SetValue(const AValue: Variant); override;  public    procedure AfterConstruction; override;    class function Generate(AValue: extended = 0): TlkJSONnumber;    class function SelfType: TlkJSONtypes; override;    class function SelfTypeName: string; override;  end;  TlkJSONstring = class(TlkJSONbase)  protected    FValue: WideString;    function GetValue: Variant; override;    procedure SetValue(const AValue: Variant); override;  public    procedure AfterConstruction; override;    class function Generate(const wsValue: WideString = ''):      TlkJSONstring;    class function SelfType: TlkJSONtypes; override;    class function SelfTypeName: string; override;  end;  TlkJSONboolean = class(TlkJSONbase)  protected    FValue: Boolean;    function GetValue: Variant; override;    procedure SetValue(const AValue: Variant); override;  public    procedure AfterConstruction; override;    class function Generate(AValue: Boolean = true): TlkJSONboolean;    class function SelfType: TlkJSONtypes; override;    class function SelfTypeName: string; override;  end;  TlkJSONnull = class(TlkJSONbase)  protected    function GetValue: Variant; override;    function Generate: TlkJSONnull;  public    class function SelfType: TlkJSONtypes; override;    class function SelfTypeName: string; override;  end;  TlkJSONFuncEnum = procedure(ElName: string; Elem: TlkJSONbase;    data: pointer; var Continue: Boolean) of object;  TlkJSONcustomlist = class(TlkJSONbase)  protected//    FValue: array of TlkJSONbase;    fList: TList;    function GetCount: Integer; override;    function GetChild(idx: Integer): TlkJSONbase; override;    procedure SetChild(idx: Integer; const AValue: TlkJSONbase);      override;    function ForEachElement(idx: Integer; var nm: string):      TlkJSONbase; virtual;    function GetField(AName: Variant):TlkJSONbase; override;    function _Add(obj: TlkJSONbase): Integer; virtual;    procedure _Delete(iIndex: Integer); virtual;    function _IndexOf(obj: TlkJSONbase): Integer; virtual;  public    procedure ForEach(fnCallBack: TlkJSONFuncEnum; pUserData:      pointer);    procedure AfterConstruction; override;    procedure BeforeDestruction; override;    function getInt(idx: Integer): Integer; virtual;    function getString(idx: Integer): string; virtual;    function getWideString(idx: Integer): WideString; virtual;    function getDouble(idx: Integer): Double; virtual;    function getBoolean(idx: Integer): Boolean; virtual;  end;  TlkJSONlist = class(TlkJSONcustomlist)  protected  public    function Add(obj: TlkJSONbase): Integer; overload;    function Add(aboolean: Boolean): Integer; overload;    function Add(nmb: double): Integer; overload;    function Add(s: string): Integer; overload;    function Add(const ws: WideString): Integer; overload;    function Add(inmb: Integer): Integer; overload;    procedure Delete(idx: Integer);    function IndexOf(obj: TlkJSONbase): Integer;    class function Generate: TlkJSONlist;    class function SelfType: TlkJSONtypes; override;    class function SelfTypeName: string; override;  end;  TlkJSONobjectmethod = class(TlkJSONbase)  protected    FValue: TlkJSONbase;    FName: WideString;    procedure SetName(const AValue: WideString);  public    property ObjValue: TlkJSONbase read FValue;    procedure AfterConstruction; override;    procedure BeforeDestruction; override;    property Name: WideString read FName write SetName;    class function Generate(const aname: WideString; aobj: TlkJSONbase):      TlkJSONobjectmethod;  end;{$IFDEF USE_HASH}  PlkHashItem = ^TlkHashItem;  TlkHashItem = packed record    hash: cardinal;    index: Integer;  end;  TlkHashFunction = function(const ws: WideString): cardinal of    object;  TlkHashTable = class  private    FParent: TObject; // TCB:parent for check chaining op.    FHashFunction: TlkHashFunction;    procedure SetHashFunction(const AValue: TlkHashFunction);  protected    a_x: array[0..255] of TList;    procedure hswap(j, k, l: Integer);    function InTable(const ws: WideString; var i, j, k: cardinal):      Boolean;  public    function counters: string;    function DefaultHashOf(const ws: WideString): cardinal;    function SimpleHashOf(const ws: WideString): cardinal;    property HashOf: TlkHashFunction read FHashFunction write      SetHashFunction;    function IndexOf(const ws: WideString): Integer;    procedure AddPair(const ws: WideString; idx: Integer);    procedure Delete(const ws: WideString);    constructor Create;    destructor Destroy; override;  end;{$ELSE}// implementation based on "Arne Andersson, Balanced Search Trees Made Simpler"  PlkBalNode = ^TlkBalNode;  TlkBalNode = packed record    left,right: PlkBalNode;    level: byte;    key: Integer;    nm: WideString;  end;  TlkBalTree = class  protected    fdeleted,flast,fbottom,froot: PlkBalNode;    procedure skew(var t:PlkBalNode);    procedure split(var t:PlkBalNode);  public    function counters: string;    procedure Clear;    function Insert(const ws: WideString; x: Integer): Boolean;    function Delete(const ws: WideString): Boolean;    function IndexOf(const ws: WideString): Integer;    constructor Create;    destructor Destroy; override;  end;{$ENDIF USE_HASH}  TlkJSONobject = class(TlkJSONcustomlist)  protected{$IFDEF USE_HASH}    ht: TlkHashTable;{$ELSE}    ht: TlkBalTree;{$ENDIF USE_HASH}    FUseHash: Boolean;    function GetFieldByIndex(idx: Integer): TlkJSONbase;    function GetNameOf(idx: Integer): WideString;    procedure SetFieldByIndex(idx: Integer; const AValue: TlkJSONbase);{$IFDEF USE_HASH}    function GetHashTable: TlkHashTable;{$ELSE}    function GetHashTable: TlkBalTree;{$ENDIF USE_HASH}    function ForEachElement(idx: Integer; var nm: string): TlkJSONbase;      override;    function GetField(AName: Variant):TlkJSONbase; override;  public    property UseHash: Boolean read FUseHash;{$IFDEF USE_HASH}    property HashTable: TlkHashTable read GetHashTable;{$ELSE}    property HashTable: TlkBalTree read GetHashTable;{$ENDIF USE_HASH}    function Add(const aname: WideString; aobj: TlkJSONbase): Integer;      overload;    function OldGetField(nm: WideString): TlkJSONbase;    procedure OldSetField(nm: WideString; const AValue: TlkJSONbase);    function Add(const aname: WideString; aboolean: Boolean): Integer; overload;    function Add(const aname: WideString; nmb: double): Integer; overload;    function Add(const aname: WideString; s: string): Integer; overload;    function Add(const aname: WideString; const ws: WideString): Integer;      overload;    function Add(const aname: WideString; inmb: Integer): Integer; overload;    procedure Delete(idx: Integer);    function IndexOfName(const aname: WideString): Integer;    function IndexOfObject(aobj: TlkJSONbase): Integer;    property Field[nm: WideString]: TlkJSONbase read OldGetField      write OldSetField; default;    constructor Create(bUseHash: Boolean = true);    destructor Destroy; override;    class function Generate(AUseHash: Boolean = true): TlkJSONobject;    class function SelfType: TlkJSONtypes; override;    class function SelfTypeName: string; override;    property FieldByIndex[idx: Integer]: TlkJSONbase read GetFieldByIndex    write SetFieldByIndex;    property NameOf[idx: Integer]: WideString read GetNameOf;    function getDouble(idx: Integer): Double; overload; override;    function getInt(idx: Integer): Integer; overload; override;    function getString(idx: Integer): string; overload; override;    function getWideString(idx: Integer): WideString; overload; override;    function getBoolean(idx: Integer): Boolean; overload; override;    function {$ifdef TCB_EXT}getDoubleFromName{$else}getDouble{$endif}      (nm: string): Double; overload;    function {$ifdef TCB_EXT}getIntFromName{$else}getInt{$endif}      (nm: string): Integer; overload;    function {$ifdef TCB_EXT}getStringFromName{$else}getString{$endif}      (nm: string): string; overload;    function {$ifdef TCB_EXT}getWideStringFromName{$else}getWideString{$endif}      (nm: string): WideString; overload;    function {$ifdef TCB_EXT}getBooleanFromName{$else}getBoolean{$endif}      (nm: string): Boolean; overload;  end;  TlkJSON = class  public    class function ParseText(const txt: string): TlkJSONbase;    class function GenerateText(obj: TlkJSONbase): string;  end;{$IFNDEF KOL}  TlkJSONstreamed = class(TlkJSON)    class function LoadFromStream(src: TStream): TlkJSONbase;    class procedure SaveToStream(obj: TlkJSONbase; dst: TStream);    class function LoadFromFile(srcname: string): TlkJSONbase;    class procedure SaveToFile(obj: TlkJSONbase; dstname: string);  end;{$ENDIF}function GenerateReadableText(vObj: TlkJSONbase; var vLevel:  Integer): string;implementationuses math,strutils;type  ElkIntException = class(Exception)  public    idx: Integer;    constructor Create(idx: Integer; msg: string);  end;// author of next two functions is Kusnassriyanto Saiful Bahrifunction Indent(vTab: Integer): string;begin  result := DupeString('  ', vTab);end;function GenerateReadableText(vObj: TlkJSONbase; var vLevel:  Integer): string;var  i: Integer;  vStr: string;  xs: TlkJSONstring;begin  vLevel := vLevel + 1;  if vObj is TlkJSONObject then    begin      vStr := '';      for i := 0 to TlkJSONobject(vObj).Count - 1 do        begin          if vStr <> '' then            begin              vStr := vStr + ','#13#10;            end;          vStr := vStr + Indent(vLevel) +            GenerateReadableText(TlkJSONobject(vObj).Child[i], vLevel);        end;      if vStr <> '' then        begin          vStr := '{'#13#10 + vStr + #13#10 + Indent(vLevel - 1) + '}';        end      else        begin          vStr := '{}';        end;      result := vStr;    end  else if vObj is TlkJSONList then    begin      vStr := '';      for i := 0 to TlkJSONList(vObj).Count - 1 do        begin          if vStr <> '' then            begin              vStr := vStr + ','#13#10;            end;          vStr := vStr + Indent(vLevel) +              GenerateReadableText(TlkJSONList(vObj).Child[i], vLevel);        end;      if vStr <> '' then        begin          vStr := '['#13#10 + vStr + #13#10 + Indent(vLevel - 1) + ']';        end      else        begin          vStr := '[]';        end;      result := vStr;    end  else if vObj is TlkJSONobjectmethod then    begin      vStr := '';      xs := TlkJSONstring.Create;      try        xs.Value := TlkJSONobjectMethod(vObj).Name;        vStr := GenerateReadableText(xs, vLevel);        vLevel := vLevel - 1;        vStr := vStr + ':' + GenerateReadableText(TlkJSONbase(          TlkJSONobjectmethod(vObj).ObjValue), vLevel);      //vStr := vStr + ':' + GenerateReadableText(TlkJSONbase(vObj), vLevel);        vLevel := vLevel + 1;        result := vStr;      finally        xs.Free;      end;    end  else    begin      if vObj is TlkJSONobjectmethod then        begin          if TlkJSONobjectMethod(vObj).Name <> '' then            begin            end;        end;      result := TlkJSON.GenerateText(vObj);    end;  vLevel := vLevel - 1;end;// author of this routine is IVO GELOVfunction code2utf(iNumber: Integer): UTF8String;begin  if iNumber < 128 then Result := chr(iNumber)  else if iNumber < 2048 then    Result := chr((iNumber shr 6) + 192) + chr((iNumber and 63) + 128)  else if iNumber < 65536 then    Result := chr((iNumber shr 12) + 224) + chr(((iNumber shr 6) and      63) + 128) + chr((iNumber and 63) + 128)  else if iNumber < 2097152 then    Result := chr((iNumber shr 18) + 240) + chr(((iNumber shr 12) and      63) + 128) + chr(((iNumber shr 6) and 63) + 128) +      chr((iNumber and 63) + 128);end;{ TlkJSONbase }function TlkJSONbase.GetChild(idx: Integer): TlkJSONbase;begin  result := nil;end;function TlkJSONbase.GetCount: Integer;begin  result := 0;end;function TlkJSONbase.GetField(AName: Variant):TlkJSONbase;begin  result := self;end;function TlkJSONbase.GetValue: variant;begin  result := variants.Null;end;class function TlkJSONbase.SelfType: TlkJSONtypes;begin  result := jsBase;end;class function TlkJSONbase.SelfTypeName: string;begin  result := 'jsBase';end;procedure TlkJSONbase.SetChild(idx: Integer; const AValue:  TlkJSONbase);beginend;procedure TlkJSONbase.SetValue(const AValue: variant);beginend;{ TlkJSONnumber }procedure TlkJSONnumber.AfterConstruction;begin  inherited;  FValue := 0;end;class function TlkJSONnumber.Generate(AValue: extended):  TlkJSONnumber;begin  result := TlkJSONnumber.Create;  result.FValue := AValue;end;function TlkJSONnumber.GetValue: Variant;begin  result := FValue;end;class function TlkJSONnumber.SelfType: TlkJSONtypes;begin  result := jsNumber;end;class function TlkJSONnumber.SelfTypeName: string;begin  result := 'jsNumber';end;procedure TlkJSONnumber.SetValue(const AValue: Variant);begin  FValue := VarAsType(AValue, varDouble);end;{ TlkJSONstring }procedure TlkJSONstring.AfterConstruction;begin  inherited;  FValue := '';end;class function TlkJSONstring.Generate(const wsValue: WideString):  TlkJSONstring;begin  result := TlkJSONstring.Create;  result.FValue := wsValue;end;function TlkJSONstring.GetValue: Variant;begin  result := FValue;end;class function TlkJSONstring.SelfType: TlkJSONtypes;begin  result := jsString;end;class function TlkJSONstring.SelfTypeName: string;begin  result := 'jsString';end;procedure TlkJSONstring.SetValue(const AValue: Variant);begin  FValue := VarToWideStr(AValue);end;{ TlkJSONboolean }procedure TlkJSONboolean.AfterConstruction;begin  FValue := false;end;class function TlkJSONboolean.Generate(AValue: Boolean):  TlkJSONboolean;begin  result := TlkJSONboolean.Create;  result.Value := AValue;end;function TlkJSONboolean.GetValue: Variant;begin  result := FValue;end;class function TlkJSONboolean.SelfType: TlkJSONtypes;begin  Result := jsBoolean;end;class function TlkJSONboolean.SelfTypeName: string;begin  Result := 'jsBoolean';end;procedure TlkJSONboolean.SetValue(const AValue: Variant);begin  FValue := boolean(AValue);end;{ TlkJSONnull }function TlkJSONnull.Generate: TlkJSONnull;begin  result := TlkJSONnull.Create;end;function TlkJSONnull.GetValue: Variant;begin  result := variants.Null;end;class function TlkJSONnull.SelfType: TlkJSONtypes;begin  result := jsNull;end;class function TlkJSONnull.SelfTypeName: string;begin  result := 'jsNull';end;{ TlkJSONcustomlist }function TlkJSONcustomlist._Add(obj: TlkJSONbase): Integer;begin  if not Assigned(obj) then    begin      result := -1;      exit;    end;  result := fList.Add(obj);end;procedure TlkJSONcustomlist.AfterConstruction;begin  inherited;  fList := TList.Create;end;procedure TlkJSONcustomlist.BeforeDestruction;var  i: Integer;begin  for i := (Count - 1) downto 0 do _Delete(i);  fList.Free;  inherited;end;// renamedprocedure TlkJSONcustomlist._Delete(iIndex: Integer);var  idx: Integer;begin  if not ((iIndex < 0) or (iIndex >= Count)) then    begin      if fList.Items[iIndex] <> nil then        TlkJSONbase(fList.Items[iIndex]).Free;      idx := pred(fList.Count);      if iIndex<idx then        begin          fList.Items[iIndex] := fList.Items[idx];          fList.Delete(idx);        end      else        begin          fList.Delete(iIndex);        end;    end;end;function TlkJSONcustomlist.GetChild(idx: Integer): TlkJSONbase;begin  if (idx < 0) or (idx >= Count) then    begin      result := nil;    end  else    begin      result := fList.Items[idx];    end;end;function TlkJSONcustomlist.GetCount: Integer;begin  result := fList.Count;end;function TlkJSONcustomlist._IndexOf(obj: TlkJSONbase): Integer;begin  result := fList.IndexOf(obj);end;procedure TlkJSONcustomlist.SetChild(idx: Integer; const AValue:  TlkJSONbase);begin  if not ((idx < 0) or (idx >= Count)) then    begin      if fList.Items[idx] <> nil then        TlkJSONbase(fList.Items[idx]).Free;      fList.Items[idx] := AValue;    end;end;procedure TlkJSONcustomlist.ForEach(fnCallBack: TlkJSONFuncEnum;  pUserData:  pointer);var  iCount: Integer;  IsContinue: Boolean;  anJSON: TlkJSONbase;  wsObject: string;begin  if not assigned(fnCallBack) then exit;  IsContinue := true;  for iCount := 0 to GetCount - 1 do    begin      anJSON := ForEachElement(iCount, wsObject);      if assigned(anJSON) then        fnCallBack(wsObject, anJSON, pUserData, IsContinue);      if not IsContinue then break;    end;end;///---- renamed to herefunction TlkJSONcustomlist.GetField(AName: Variant):TlkJSONbase;var  index: Integer;begin  if VarIsNumeric(AName) then    begin      index := integer(AName);      result := GetChild(index);    end  else    begin      result := inherited GetField(AName);    end;end;function TlkJSONcustomlist.ForEachElement(idx: Integer; var nm:  string): TlkJSONbase;begin  nm := inttostr(idx);  result := GetChild(idx);end;function TlkJSONcustomlist.getDouble(idx: Integer): Double;var  jn: TlkJSONnumber;begin  jn := Child[idx] as TlkJSONnumber;  if not assigned(jn) then result := 0  else result := jn.Value;end;function TlkJSONcustomlist.getInt(idx: Integer): Integer;var  jn: TlkJSONnumber;begin  jn := Child[idx] as TlkJSONnumber;  if not assigned(jn) then result := 0  else result := round(int(jn.Value));end;function TlkJSONcustomlist.getString(idx: Integer): string;var  js: TlkJSONstring;begin  js := Child[idx] as TlkJSONstring;  if not assigned(js) then result := ''  else result := VarToStr(js.Value);end;function TlkJSONcustomlist.getWideString(idx: Integer): WideString;var  js: TlkJSONstring;begin  js := Child[idx] as TlkJSONstring;  if not assigned(js) then result := ''  else result := VarToWideStr(js.Value);end;function TlkJSONcustomlist.getBoolean(idx: Integer): Boolean;var  jb: TlkJSONboolean;begin  jb := Child[idx] as TlkJSONboolean;  if not assigned(jb) then result := false  else result := jb.Value;end;{ TlkJSONobjectmethod }procedure TlkJSONobjectmethod.AfterConstruction;begin  inherited;  FValue := nil;  FName := '';end;procedure TlkJSONobjectmethod.BeforeDestruction;begin  FName := '';  if FValue <> nil then    begin      FValue.Free;      FValue := nil;    end;  inherited;end;class function TlkJSONobjectmethod.Generate(const aname: WideString;  aobj: TlkJSONbase): TlkJSONobjectmethod;begin  result := TlkJSONobjectmethod.Create;  result.FName := aname;  result.FValue := aobj;end;procedure TlkJSONobjectmethod.SetName(const AValue: WideString);begin  FName := AValue;end;{ TlkJSONlist }function TlkJSONlist.Add(obj: TlkJSONbase): Integer;begin  result := _Add(obj);end;function TlkJSONlist.Add(nmb: double): Integer;begin  Result := self.Add(TlkJSONnumber.Generate(nmb));end;function TlkJSONlist.Add(aboolean: Boolean): Integer;begin  Result := self.Add(TlkJSONboolean.Generate(aboolean));end;function TlkJSONlist.Add(inmb: Integer): Integer;begin  Result := self.Add(TlkJSONnumber.Generate(inmb));end;function TlkJSONlist.Add(const ws: WideString): Integer;begin  Result := self.Add(TlkJSONstring.Generate(ws));end;function TlkJSONlist.Add(s: string): Integer;begin  Result := self.Add(TlkJSONstring.Generate(s));end;procedure TlkJSONlist.Delete(idx: Integer);begin  _Delete(idx);end;class function TlkJSONlist.Generate: TlkJSONlist;begin  result := TlkJSONlist.Create;end;function TlkJSONlist.IndexOf(obj: TlkJSONbase): Integer;begin  result := _IndexOf(obj);end;class function TlkJSONlist.SelfType: TlkJSONtypes;begin  result := jsList;end;class function TlkJSONlist.SelfTypeName: string;begin  result := 'jsList';end;{ TlkJSONobject }function TlkJSONobject.Add(const aname: WideString; aobj:  TlkJSONbase):  Integer;var  mth: TlkJSONobjectmethod;begin  if not assigned(aobj) then    begin      result := -1;      exit;    end;  mth := TlkJSONobjectmethod.Create;  mth.FName := aname;  mth.FValue := aobj;  result := self._Add(mth);  if FUseHash then{$IFDEF USE_HASH}    ht.AddPair(aname, result);{$ELSE}    ht.Insert(aname, result);{$ENDIF USE_HASH}end;procedure TlkJSONobject.Delete(idx: Integer);var  i,j,k:cardinal;  mth: TlkJSONobjectmethod;begin  if (idx >= 0) and (idx < Count) then    begin//      mth := FValue[idx] as TlkJSONobjectmethod;      mth := TlkJSONobjectmethod(fList.Items[idx]);      if FUseHash then        begin          ht.Delete(mth.FName);        end;    end;  _Delete(idx);{$ifdef USE_HASH}  if (idx<Count) and (FUseHash) then    begin      mth := TlkJSONobjectmethod(fList.Items[idx]);      ht.AddPair(mth.FName,idx);    end;{$endif}end;class function TlkJSONobject.Generate(AUseHash: Boolean = true):  TlkJSONobject;begin  result := TlkJSONobject.Create(AUseHash);end;function TlkJSONobject.OldGetField(nm: WideString): TlkJSONbase;var  mth: TlkJSONobjectmethod;  i: Integer;begin  i := IndexOfName(nm);  if i = -1 then    begin      result := nil;    end  else    begin//      mth := TlkJSONobjectmethod(FValue[i]);      mth := TlkJSONobjectmethod(fList.Items[i]);      result := mth.FValue;    end;end;function TlkJSONobject.IndexOfName(const aname: WideString): Integer;var  mth: TlkJSONobjectmethod;  i: Integer;begin  if not FUseHash then    begin      result := -1;      for i := 0 to Count - 1 do        begin//          mth := TlkJSONobjectmethod(FValue[i]);          mth := TlkJSONobjectmethod(fList.Items[i]);          if mth.Name = aname then            begin              result := i;              break;            end;        end;    end  else    begin      result := ht.IndexOf(aname);    end;end;function TlkJSONobject.IndexOfObject(aobj: TlkJSONbase): Integer;var  mth: TlkJSONobjectmethod;  i: Integer;begin  result := -1;  for i := 0 to Count - 1 do    begin//      mth := TlkJSONobjectmethod(FValue[i]);      mth := TlkJSONobjectmethod(fList.Items[i]);      if mth.FValue = aobj then        begin          result := i;          break;        end;    end;end;procedure TlkJSONobject.OldSetField(nm: WideString; const AValue:  TlkJSONbase);var  mth: TlkJSONobjectmethod;  i: Integer;begin  i := IndexOfName(nm);  if i <> -1 then    begin//      mth := TlkJSONobjectmethod(FValue[i]);      mth := TlkJSONobjectmethod(fList.Items[i]);      mth.FValue := AValue;    end;end;function TlkJSONobject.Add(const aname: WideString; nmb: double):  Integer;begin  Result := self.Add(aname, TlkJSONnumber.Generate(nmb));end;function TlkJSONobject.Add(const aname: WideString; aboolean: Boolean):  Integer;begin  Result := self.Add(aname, TlkJSONboolean.Generate(aboolean));end;function TlkJSONobject.Add(const aname: WideString; s: string):  Integer;begin  Result := self.Add(aname, TlkJSONstring.Generate(s));end;function TlkJSONobject.Add(const aname: WideString; inmb: Integer):  Integer;begin  Result := self.Add(aname, TlkJSONnumber.Generate(inmb));end;function TlkJSONobject.Add(const aname, ws: WideString): Integer;begin  Result := self.Add(aname, TlkJSONstring.Generate(ws));end;class function TlkJSONobject.SelfType: TlkJSONtypes;begin  Result := jsObject;end;class function TlkJSONobject.SelfTypeName: string;begin  Result := 'jsObject';end;function TlkJSONobject.GetFieldByIndex(idx: Integer): TlkJSONbase;var  nm: WideString;begin  nm := GetNameOf(idx);  if nm <> '' then    begin      result := Field[nm];    end  else    begin      result := nil;    end;end;function TlkJSONobject.GetNameOf(idx: Integer): WideString;var  mth: TlkJSONobjectmethod;begin  if (idx < 0) or (idx >= Count) then    begin      result := '';    end  else    begin      mth := Child[idx] as TlkJSONobjectmethod;      result := mth.Name;    end;end;procedure TlkJSONobject.SetFieldByIndex(idx: Integer;  const AValue: TlkJSONbase);var  nm: WideString;begin  nm := GetNameOf(idx);  if nm <> '' then    begin      Field[nm] := AValue;    end;end;function TlkJSONobject.ForEachElement(idx: Integer;  var nm: string): TlkJSONbase;begin  nm := GetNameOf(idx);  result := GetFieldByIndex(idx);end;function TlkJSONobject.GetField(AName: Variant):TlkJSONbase;begin  if VarIsStr(AName) then    result := OldGetField(VarToWideStr(AName))  else    result := inherited GetField(AName);end;{$IFDEF USE_HASH}function TlkJSONobject.GetHashTable: TlkHashTable;{$ELSE}function TlkJSONobject.GetHashTable: TlkBalTree;{$ENDIF USE_HASH}begin  result := ht;end;constructor TlkJSONobject.Create(bUseHash: Boolean);begin  inherited Create;  FUseHash := bUseHash;{$IFDEF USE_HASH}  ht := TlkHashTable.Create;  ht.FParent := self;{$ELSE}  ht := TlkBalTree.Create;{$ENDIF}end;destructor TlkJSONobject.Destroy;begin  if assigned(ht) then FreeAndNil(ht);  inherited;end;function TlkJSONobject.getDouble(idx: Integer): Double;var  jn: TlkJSONnumber;begin  jn := FieldByIndex[idx] as TlkJSONnumber;  if not assigned(jn) then result := 0  else result := jn.Value;end;function TlkJSONobject.getInt(idx: Integer): Integer;var  jn: TlkJSONnumber;begin  jn := FieldByIndex[idx] as TlkJSONnumber;  if not assigned(jn) then result := 0  else result := round(int(jn.Value));end;function TlkJSONobject.getString(idx: Integer): string;var  js: TlkJSONstring;begin  js := FieldByIndex[idx] as TlkJSONstring;  if not assigned(js) then result := ''  else result := vartostr(js.Value);end;function TlkJSONobject.getWideString(idx: Integer): WideString;var  js: TlkJSONstring;begin  js := FieldByIndex[idx] as TlkJSONstring;  if not assigned(js) then result := ''  else result := VarToWideStr(js.Value);end;{$ifdef TCB_EXT}function TlkJSONobject.getDoubleFromName(nm: string): Double;{$else}function TlkJSONobject.getDouble(nm: string): Double;{$endif}begin  result := getDouble(IndexOfName(nm));end;{$ifdef TCB_EXT}function TlkJSONobject.getIntFromName(nm: string): Integer;{$else}function TlkJSONobject.getInt(nm: string): Integer;{$endif}begin  result := getInt(IndexOfName(nm));end;{$ifdef TCB_EXT}function TlkJSONobject.getStringFromName(nm: string): string;{$else}function TlkJSONobject.getString(nm: string): string;{$endif}begin  result := getString(IndexOfName(nm));end;{$ifdef TCB_EXT}function TlkJSONobject.getWideStringFromName(nm: string): WideString;{$else}function TlkJSONobject.getWideString(nm: string): WideString;{$endif}begin  result := getWideString(IndexOfName(nm));end;function TlkJSONobject.getBoolean(idx: Integer): Boolean;var  jb: TlkJSONboolean;begin  jb := FieldByIndex[idx] as TlkJSONboolean;  if not assigned(jb) then result := false  else result := jb.Value;end;{$ifdef TCB_EXT}function TlkJSONobject.getBooleanFromName(nm: string): Boolean;{$else}function TlkJSONobject.getBoolean(nm: string): Boolean;{$endif}begin  result := getBoolean(IndexOfName(nm));end;{ TlkJSON }class function TlkJSON.GenerateText(obj: TlkJSONbase): string;var{$IFDEF HAVE_FORMATSETTING}  fs: TFormatSettings;{$ENDIF}  pt1, pt0, pt2: PChar;  ptsz: cardinal;{$IFNDEF NEW_STYLE_GENERATE}  function gn_base(obj: TlkJSONbase): string;  var    ws: string;    i, j: Integer;    xs: TlkJSONstring;  begin    result := '';    if not assigned(obj) then exit;    if obj is TlkJSONnumber then      begin{$IFDEF HAVE_FORMATSETTING}        result := FloatToStr(TlkJSONnumber(obj).FValue, fs);{$ELSE}        result := FloatToStr(TlkJSONnumber(obj).FValue);        i := pos(DecimalSeparator, result);        if (DecimalSeparator <> '.') and (i > 0) then          result[i] := '.';{$ENDIF}      end    else if obj is TlkJSONstring then      begin        ws := UTF8Encode(TlkJSONstring(obj).FValue);        i := 1;        result := '"';        while i <= length(ws) do          begin            case ws[i] of              '/', '\', '"': result := result + '\' + ws[i];              #8: result := result + '\b';              #9: result := result + '\t';              #10: result := result + '\n';              #13: result := result + '\r';              #12: result := result + '\f';            else              if ord(ws[i]) < 32 then                result := result + '\u' + inttohex(ord(ws[i]), 4)              else                result := result + ws[i];            end;            inc(i);          end;        result := result + '"';      end    else if obj is TlkJSONboolean then      begin        if TlkJSONboolean(obj).FValue then          result := 'true'        else          result := 'false';      end    else if obj is TlkJSONnull then      begin        result := 'null';      end    else if obj is TlkJSONlist then      begin        result := '[';        j := TlkJSONobject(obj).Count - 1;        for i := 0 to j do          begin            if i > 0 then result := result + ',';            result := result + gn_base(TlkJSONlist(obj).Child[i]);          end;        result := result + ']';      end    else if obj is TlkJSONobjectmethod then      begin        try          xs := TlkJSONstring.Create;          xs.FValue := TlkJSONobjectmethod(obj).FName;          result := gn_base(TlkJSONbase(xs)) + ':';          result := result +            gn_base(TlkJSONbase(TlkJSONobjectmethod(obj).FValue));        finally          if assigned(xs) then FreeAndNil(xs);        end;      end    else if obj is TlkJSONobject then      begin        result := '{';        j := TlkJSONobject(obj).Count - 1;        for i := 0 to j do          begin            if i > 0 then result := result + ',';            result := result + gn_base(TlkJSONobject(obj).Child[i]);          end;        result := result + '}';      end;  end;{$ELSE}  procedure get_more_memory;  var    delta: cardinal;  begin    delta := 50000;    if pt0 = nil then      begin        pt0 := AllocMem(delta);        ptsz := 0;        pt1 := pt0;      end    else      begin        ReallocMem(pt0, ptsz + delta);        pt1 := pointer(cardinal(pt0) + ptsz);      end;    ptsz := ptsz + delta;    pt2 := pointer(cardinal(pt1) + delta);  end;  procedure mem_ch(ch: char);  begin    if pt1 >= pt2 then get_more_memory;    pt1^ := ch;    inc(pt1);  end;  procedure mem_write(rs: string);  var    i: Integer;  begin    for i := 1 to length(rs) do      begin        if pt1 >= pt2 then get_more_memory;        pt1^ := rs[i];        inc(pt1);      end;  end;  procedure gn_base(obj: TlkJSONbase);  var    ws: string;    i, j: Integer;    xs: TlkJSONstring;  begin    if not assigned(obj) then exit;    if obj is TlkJSONnumber then      begin{$IFDEF HAVE_FORMATSETTING}        mem_write(FloatToStr(TlkJSONnumber(obj).FValue, fs));{$ELSE}        ws := FloatToStr(TlkJSONnumber(obj).FValue);        i := pos(DecimalSeparator, ws);        if (DecimalSeparator <> '.') and (i > 0) then ws[i] := '.';        mem_write(ws);{$ENDIF}      end    else if obj is TlkJSONstring then      begin        ws := UTF8Encode(TlkJSONstring(obj).FValue);        i := 1;        mem_ch('"');        while i <= length(ws) do          begin            case ws[i] of              '/', '\', '"':                begin                  mem_ch('\');                  mem_ch(ws[i]);                end;              #8: mem_write('\b');              #9: mem_write('\t');              #10: mem_write('\n');              #13: mem_write('\r');              #12: mem_write('\f');            else              if ord(ws[i]) < 32 then                mem_write('\u' + inttohex(ord(ws[i]), 4))              else                mem_ch(ws[i]);            end;            inc(i);          end;        mem_ch('"');      end    else if obj is TlkJSONboolean then      begin        if TlkJSONboolean(obj).FValue then          mem_write('true')        else          mem_write('false');      end    else if obj is TlkJSONnull then      begin        mem_write('null');      end    else if obj is TlkJSONlist then      begin        mem_ch('[');        j := TlkJSONobject(obj).Count - 1;        for i := 0 to j do          begin            if i > 0 then mem_ch(',');            gn_base(TlkJSONlist(obj).Child[i]);          end;        mem_ch(']');      end    else if obj is TlkJSONobjectmethod then      begin        try          xs := TlkJSONstring.Create;          xs.FValue := TlkJSONobjectmethod(obj).FName;          gn_base(TlkJSONbase(xs));          mem_ch(':');          gn_base(TlkJSONbase(TlkJSONobjectmethod(obj).FValue));        finally          if assigned(xs) then FreeAndNil(xs);        end;      end    else if obj is TlkJSONobject then      begin        mem_ch('{');        j := TlkJSONobject(obj).Count - 1;        for i := 0 to j do          begin            if i > 0 then mem_ch(',');            gn_base(TlkJSONobject(obj).Child[i]);          end;        mem_ch('}');      end;  end;{$ENDIF NEW_STYLE_GENERATE}begin{$IFDEF HAVE_FORMATSETTING}  GetLocaleFormatSettings(GetThreadLocale, fs);  fs.DecimalSeparator := '.';{$ENDIF}{$IFDEF NEW_STYLE_GENERATE}  pt0 := nil;  get_more_memory;  gn_base(obj);  mem_ch(#0);  result := string(pt0);  freemem(pt0);{$ELSE}  result := gn_base(obj);{$ENDIF}end;class function TlkJSON.ParseText(const txt: string): TlkJSONbase;{$IFDEF HAVE_FORMATSETTING}var  fs: TFormatSettings;{$ENDIF}  function js_base(idx: Integer; var ridx: Integer; var o:    TlkJSONbase): Boolean; forward;  function xe(idx: Integer): Boolean;  {$IFDEF FPC}inline;  {$ENDIF}  begin    result := idx <= length(txt);  end;  procedure skip_spc(var idx: Integer);  {$IFDEF FPC}inline;  {$ENDIF}  begin    while (xe(idx)) and (ord(txt[idx]) < 33) do      inc(idx);  end;  procedure add_child(var o, c: TlkJSONbase);  var    i: Integer;  begin    if o = nil then      begin        o := c;      end    else      begin        if o is TlkJSONobjectmethod then          begin            TlkJSONobjectmethod(o).FValue := c;          end        else if o is TlkJSONlist then          begin            TlkJSONlist(o)._Add(c);          end        else if o is TlkJSONobject then          begin            i := TlkJSONobject(o)._Add(c);            if TlkJSONobject(o).UseHash then{$IFDEF USE_HASH}              TlkJSONobject(o).ht.AddPair(TlkJSONobjectmethod(c).Name, i);{$ELSE}              TlkJSONobject(o).ht.Insert(TlkJSONobjectmethod(c).Name, i);{$ENDIF USE_HASH}          end;      end;  end;  function js_boolean(idx: Integer; var ridx: Integer; var o:    TlkJSONbase): Boolean;  var    js: TlkJSONboolean;  begin    skip_spc(idx);    if copy(txt, idx, 4) = 'true' then      begin        result := true;        ridx := idx + 4;        js := TlkJSONboolean.Create;        js.FValue := true;        add_child(o, TlkJSONbase(js));      end    else if copy(txt, idx, 5) = 'false' then      begin        result := true;        ridx := idx + 5;        js := TlkJSONboolean.Create;        js.FValue := false;        add_child(o, TlkJSONbase(js));      end    else      begin        result := false;      end;  end;  function js_null(idx: Integer; var ridx: Integer; var o:    TlkJSONbase): Boolean;  var    js: TlkJSONnull;  begin    skip_spc(idx);    if copy(txt, idx, 4) = 'null' then      begin        result := true;        ridx := idx + 4;        js := TlkJSONnull.Create;        add_child(o, TlkJSONbase(js));      end    else      begin        result := false;      end;  end;  function js_integer(idx: Integer; var ridx: Integer): Boolean;  begin    result := false;    while (xe(idx)) and (txt[idx] in ['0'..'9']) do      begin        result := true;        inc(idx);      end;    if result then ridx := idx;  end;  function js_number(idx: Integer; var ridx: Integer; var o:    TlkJSONbase): Boolean;  var    js: TlkJSONnumber;    ws: string;  {$IFNDEF HAVE_FORMATSETTING}    i: Integer;  {$ENDIF}  begin    skip_spc(idx);    result := xe(idx);    if not result then exit;    if txt[idx] in ['+', '-'] then      begin        inc(idx);        result := xe(idx);      end;    if not result then exit;    result := js_integer(idx, idx);    if not result then exit;    if (xe(idx)) and (txt[idx] = '.') then      begin        inc(idx);        result := js_integer(idx, idx);        if not result then exit;      end;    if (xe(idx)) and (txt[idx] in ['e', 'E']) then      begin        inc(idx);        if (xe(idx)) and (txt[idx] in ['+', '-']) then inc(idx);        result := js_integer(idx, idx);        if not result then exit;      end;    if not result then exit;    js := TlkJSONnumber.Create;    ws := copy(txt, ridx, idx - ridx);{$IFDEF HAVE_FORMATSETTING}    js.FValue := StrToFloat(ws, fs);{$ELSE}    i := pos('.', ws);    if (DecimalSeparator <> '.') and (i > 0) then      ws[pos('.', ws)] := DecimalSeparator;    js.FValue := StrToFloat(ws);{$ENDIF}    add_child(o, TlkJSONbase(js));    ridx := idx;  end;{}  function js_string(idx: Integer; var ridx: Integer; var o:    TlkJSONbase): Boolean;    function strSpecialChars(const s: string): string;    var      i, j : integer;    begin      i := Pos('\', s);      if (i = 0) then        Result := s      else      begin        Result := Copy(s, 1, i-1);        j := i;        repeat          if (s[j] = '\') then          begin            inc(j);            case s[j] of              '\': Result := Result + '\';              '"': Result := Result + '"';              '''': Result := Result + '''';              '/': Result := Result + '/';              'b': Result := Result + #8;              'f': Result := Result + #12;              'n': Result := Result + #10;              'r': Result := Result + #13;              't': Result := Result + #9;              'u':                begin                  Result := Result + code2utf(strtoint('$' + copy(s, j + 1, 4)));                  inc(j, 4);                end;            end;          end          else            Result := Result + s[j];          inc(j);        until j > length(s);      end;    end;  var    js: TlkJSONstring;    fin: Boolean;    ws: String;    i,j,widx: Integer;  begin    skip_spc(idx);    result := xe(idx) and (txt[idx] = '"');    if not result then exit;    inc(idx);    widx := idx;    fin:=false;    REPEAT      i := 0;      j := 0;      while (widx<=length(txt)) and (j=0) do        begin          if (i=0) and (txt[widx]='\') then i:=widx;          if (j=0) and (txt[widx]='"') then j:=widx;          inc(widx);        end;// incorrect string!!!      if j=0 then        begin          result := false;          exit;        end;// if we have no slashed chars in string      if (i=0) or (j<i) then        begin          ws := copy(txt,idx,j-idx);          idx := j;          fin := true;        end// if i>0 and j>=i - skip slashed char      else        begin          widx:=i+2;        end;    UNTIL fin;    ws := strSpecialChars(ws);    inc(idx);    js := TlkJSONstring.Create;{$ifdef USE_D2009}    js.FValue := UTF8ToString(ws);{$else}    js.FValue := UTF8Decode(ws);{$endif}    add_child(o, TlkJSONbase(js));    ridx := idx;  end;  function js_list(idx: Integer; var ridx: Integer; var o:    TlkJSONbase): Boolean;  var    js: TlkJSONlist;  begin    result := false;    try      js := TlkJSONlist.Create;      skip_spc(idx);      result := xe(idx);      if not result then exit;      result := txt[idx] = '[';      if not result then exit;      inc(idx);      while js_base(idx, idx, TlkJSONbase(js)) do        begin          skip_spc(idx);          if (xe(idx)) and (txt[idx] = ',') then inc(idx);        end;      skip_spc(idx);      result := (xe(idx)) and (txt[idx] = ']');      if not result then exit;      inc(idx);    finally      if not result then        begin          js.Free;        end      else        begin          add_child(o, TlkJSONbase(js));          ridx := idx;        end;    end;  end;  function js_method(idx: Integer; var ridx: Integer; var o:    TlkJSONbase): Boolean;  var    mth: TlkJSONobjectmethod;    ws: TlkJSONstring;  begin    result := false;    try      ws := nil;      mth := TlkJSONobjectmethod.Create;      skip_spc(idx);      result := xe(idx);      if not result then exit;      result := js_string(idx, idx, TlkJSONbase(ws));      if not result then exit;      skip_spc(idx);      result := xe(idx) and (txt[idx] = ':');      if not result then exit;      inc(idx);      mth.FName := ws.FValue;      result := js_base(idx, idx, TlkJSONbase(mth));    finally      if ws <> nil then ws.Free;      if result then        begin          add_child(o, TlkJSONbase(mth));          ridx := idx;        end      else        begin          mth.Free;        end;    end;  end;  function js_object(idx: Integer; var ridx: Integer; var o:    TlkJSONbase): Boolean;  var    js: TlkJSONobject;  begin    result := false;    try      js := TlkJSONobject.Create;      skip_spc(idx);      result := xe(idx);      if not result then exit;      result := txt[idx] = '{';      if not result then exit;      inc(idx);      while js_method(idx, idx, TlkJSONbase(js)) do        begin          skip_spc(idx);          if (xe(idx)) and (txt[idx] = ',') then inc(idx);        end;      skip_spc(idx);        result := (xe(idx)) and (txt[idx] = '}');      if not result then exit;      inc(idx);    finally      if not result then        begin          js.Free;        end      else        begin          add_child(o, TlkJSONbase(js));          ridx := idx;        end;    end;  end;  function js_base(idx: Integer; var ridx: Integer; var o:    TlkJSONbase): Boolean;  begin    skip_spc(idx);    result := js_boolean(idx, idx, o);    if not result then result := js_null(idx, idx, o);    if not result then result := js_number(idx, idx, o);    if not result then result := js_string(idx, idx, o);    if not result then result := js_list(idx, idx, o);    if not result then result := js_object(idx, idx, o);    if result then ridx := idx;  end;var  idx: Integer;begin{$IFDEF HAVE_FORMATSETTING}  GetLocaleFormatSettings(GetThreadLocale, fs);  fs.DecimalSeparator := '.';{$ENDIF}  result := nil;  if txt = '' then exit;  try    idx := 1;    // skip a BOM utf8 marker    if copy(txt,idx,3)=#239#187#191 then      begin        inc(idx,3);    // if there are only a BOM - exit;        if idx>length(txt) then exit;      end;    if not js_base(idx, idx, result) then FreeAndNil(result);  except    if assigned(result) then FreeAndNil(result);  end;end;{ ElkIntException }constructor ElkIntException.Create(idx: Integer; msg: string);begin  self.idx := idx;  inherited Create(msg);end;{ TlkHashTable }{$IFDEF USE_HASH}procedure TlkHashTable.AddPair(const ws: WideString; idx: Integer);var  i, j, k: cardinal;  p: PlkHashItem;  find: boolean;begin  find := false;  if InTable(ws, i, j, k) then    begin// if string is already in table, changing index      if TlkJSONobject(FParent).GetNameOf(PlkHashItem(a_x[j].Items[k])^.index) = ws then        begin           PlkHashItem(a_x[j].Items[k])^.index := idx;           find := true;        end;    end;  if find = false then    begin      GetMem(p,sizeof(TlkHashItem));      k := a_x[j].Add(p);      p^.hash := i;      p^.index := idx;      while (k>0) and (PlkHashItem(a_x[j].Items[k])^.hash < PlkHashItem(a_x[j].Items[k-1])^.hash) do        begin          a_x[j].Exchange(k,k-1);          dec(k);        end;    end;end;function TlkHashTable.counters: string;var  i, j: Integer;  ws: string;begin  ws := '';  for i := 0 to 15 do    begin      for j := 0 to 15 do//        ws := ws + format('%.3d ', [length(a_h[i * 16 + j])]);        ws := ws + format('%.3d ', [a_x[i * 16 + j].Count]);      ws := ws + #13#10;    end;  result := ws;end;procedure TlkHashTable.Delete(const ws: WideString);var  i, j, k: cardinal;begin  if InTable(ws, i, j, k) then    begin//      while k < high(a_h[j]) do//        begin//          hswap(j, k, k + 1);//          inc(k);//        end;//      SetLength(a_h[j], k);      FreeMem(a_x[j].Items[k]);      a_x[j].Delete(k);    end;end;{$IFDEF THREADSAFE}const  rnd_table: array[0..255] of byte =  (216, 191, 234, 201, 12, 163, 190, 205, 128, 199, 210, 17, 52, 43,    38, 149, 40, 207, 186, 89, 92, 179, 142, 93, 208, 215, 162,    161, 132, 59, 246, 37, 120, 223, 138, 233, 172, 195, 94, 237, 32,    231, 114, 49, 212, 75, 198, 181, 200, 239, 90, 121, 252, 211,    46, 125, 112, 247, 66, 193, 36, 91, 150, 69, 24, 255, 42, 9, 76,    227, 254, 13, 192, 7, 18, 81, 116, 107, 102, 213, 104, 15, 250,    153, 156, 243, 206, 157, 16, 23, 226, 225, 196, 123, 54, 101,    184, 31, 202, 41, 236, 3, 158, 45, 96, 39, 178, 113, 20, 139, 6,    245, 8, 47, 154, 185, 60, 19, 110, 189, 176, 55, 130, 1, 100,    155, 214, 133, 88, 63, 106, 73, 140, 35, 62, 77, 0, 71, 82, 145,    180,    171, 166, 21, 168, 79, 58, 217, 220, 51, 14, 221, 80, 87, 34, 33,    4, 187, 118, 165, 248, 95, 10, 105, 44, 67, 222, 109, 160, 103,    242, 177, 84, 203, 70, 53, 72, 111, 218, 249, 124, 83, 174, 253,    240, 119, 194, 65, 164, 219, 22, 197, 152, 127, 170, 137, 204,    99, 126, 141, 64, 135, 146, 209, 244, 235, 230, 85, 232, 143,    122, 25, 28, 115, 78, 29, 144, 151, 98, 97, 68, 251, 182, 229,    56,    159, 74, 169, 108, 131, 30, 173, 224, 167, 50, 241, 148, 11, 134,    117, 136, 175, 26, 57, 188, 147, 238, 61, 48, 183, 2, 129,    228, 27, 86, 5);{$ELSE}var  rnd_table: array[0..255] of byte;{$ENDIF}function TlkHashTable.DefaultHashOf(const ws: WideString): cardinal;{$IFDEF DOTNET}var  i, j: Integer;  x1, x2, x3, x4: byte;begin  result := 0;//  result := 0;  x1 := 0;  x2 := 1;  for i := 1 to length(ws) do    begin      j := ord(ws[i]);// first version of hashing      x1 := (x1 + j) {and $FF};      x2 := (x2 + 1 + (j shr 8)) {and $FF};      x3 := rnd_table[x1];      x4 := rnd_table[x3];      result := ((x1 * x4) + (x2 * x3)) xor result;    end;end;{$ELSE}var  x1, x2, x3, x4: byte;  p: PWideChar;begin  result := 0;  x1 := 0;  x2 := 1;  p := PWideChar(ws);  while p^ <> #0 do    begin      inc(x1, ord(p^)) {and $FF};      inc(x2, 1 + (ord(p^) shr 8)) {and $FF};      x3 := rnd_table[x1];      x4 := rnd_table[x3];      result := ((x1 * x4) + (x2 * x3)) xor result;      inc(p);    end;end;{$ENDIF}procedure TlkHashTable.hswap(j, k, l: Integer);//var//  h: TlkHashItem;begin//  h := a_h[j, k];//  a_h[j, k] := a_h[j, l];//  a_h[j, l] := h;  a_x[j].Exchange(k, l);end;function TlkHashTable.IndexOf(const ws: WideString): Integer;var  i, j, k: Cardinal;begin  if not InTable(ws, i, j, k) then    begin      result := -1;    end  else    begin//      result := a_h[j, k].index;      result := PlkHashItem(a_x[j].Items[k])^.index;    end;end;function TlkHashTable.InTable(const ws: WideString; var i, j, k:  cardinal):  Boolean;var  l, wu, wl: Integer;  x: Cardinal;  fin: Boolean;begin  i := HashOf(ws);  j := i and $FF;  result := false;{using "binary" search always, because array is sorted}  if a_x[j].Count-1 >= 0 then    begin      wl := 0;      wu := a_x[j].Count-1;      repeat        fin := true;        if PlkHashItem(a_x[j].Items[wl])^.hash = i then          begin            k := wl;            result := true;          end        else if PlkHashItem(a_x[j].Items[wu])^.hash = i then          begin            k := wu;            result := true;          end        else if (wu - wl) > 1 then          begin            fin := false;            x := (wl + wu) shr 1;            if PlkHashItem(a_x[j].Items[x])^.hash > i then              begin                wu := x;              end            else              begin                wl := x;              end;          end;      until fin;    end;// verify k index in chain  if result = true then    begin      while (k > 0) and (PlkHashItem(a_x[j].Items[k])^.hash = PlkHashItem(a_x[j].Items[k-1])^.hash) do dec(k);      repeat        fin := true;        if TlkJSONobject(FParent).GetNameOf(PlkHashItem(a_x[j].Items[k])^.index) <> ws then          begin            if k < a_x[j].Count-1 then              begin                inc(k);                fin := false;              end            else              begin                result := false;              end;          end        else          begin            result := true;          end;      until fin;    end;end;{$IFNDEF THREADSAFE}procedure init_rnd;var  x0: Integer;  i: Integer;begin  x0 := 5;  for i := 0 to 255 do    begin      x0 := (x0 * 29 + 71) and $FF;      rnd_table[i] := x0;    end;end;{$ENDIF}procedure TlkHashTable.SetHashFunction(const AValue:  TlkHashFunction);begin  FHashFunction := AValue;end;constructor TlkHashTable.Create;var  i: Integer;begin  inherited;//  for i := 0 to 255 do SetLength(a_h[i], 0);  for i := 0 to 255 do a_x[i] := TList.Create;  HashOf := {$IFDEF FPC}@{$ENDIF}DefaultHashOf;end;destructor TlkHashTable.Destroy;var  i, j: Integer;begin//  for i := 0 to 255 do SetLength(a_h[i], 0);  for i := 0 to 255 do    begin      for j := 0 to a_x[i].Count - 1 do Freemem(a_x[i].Items[j]);      a_x[i].Free;    end;  inherited;end;function TlkHashTable.SimpleHashOf(const ws: WideString): cardinal;var  i: Integer;begin  result := length(ws);  for i := 1 to length(ws) do result := result + ord(ws[i]);end;{$ENDIF USE_HASH}{ TlkJSONstreamed }{$IFNDEF KOL}class function TlkJSONstreamed.LoadFromFile(srcname: string):  TlkJSONbase;var  fs: TFileStream;begin  result := nil;  if not FileExists(srcname) then exit;  try    fs := TFileStream.Create(srcname, fmOpenRead);    result := LoadFromStream(fs);  finally    if Assigned(fs) then FreeAndNil(fs);  end;end;class function TlkJSONstreamed.LoadFromStream(src: TStream):  TlkJSONbase;var  ws: string;  len: int64;begin  result := nil;  if not assigned(src) then exit;  len := src.Size - src.Position;  SetLength(ws, len);  src.Read(pchar(ws)^, len);  result := ParseText(ws);end;class procedure TlkJSONstreamed.SaveToFile(obj: TlkJSONbase;  dstname: string);var  fs: TFileStream;begin  if not assigned(obj) then exit;  try    fs := TFileStream.Create(dstname, fmCreate);    SaveToStream(obj, fs);  finally    if Assigned(fs) then FreeAndNil(fs);  end;end;class procedure TlkJSONstreamed.SaveToStream(obj: TlkJSONbase;  dst: TStream);var  ws: string;begin  if not assigned(obj) then exit;  if not assigned(dst) then exit;  ws := GenerateText(obj);  dst.Write(pchar(ws)^, length(ws));end;{$ENDIF}{ TlkJSONdotnetclass }{$IFDEF DOTNET}procedure TlkJSONdotnetclass.AfterConstruction;beginend;procedure TlkJSONdotnetclass.BeforeDestruction;beginend;constructor TlkJSONdotnetclass.Create;begin  inherited;  AfterConstruction;end;destructor TlkJSONdotnetclass.Destroy;begin  BeforeDestruction;  inherited;end;{$ENDIF DOTNET}{ TlkBalTree }{$IFNDEF USE_HASH}procedure TlkBalTree.Clear;  procedure rec(t: PlkBalNode);  begin    if t.left<>fbottom then rec(t.left);    if t.right<>fbottom then rec(t.right);    t.nm := '';    dispose(t);  end;begin  if froot<>fbottom then rec(froot);  froot := fbottom;  fdeleted := fbottom;end;function TlkBalTree.counters: string;begin  result := format('Balanced tree root node level is %d',[froot.level]);end;constructor TlkBalTree.Create;begin  inherited Create;  new(fbottom);  fbottom.left := fbottom;  fbottom.right := fbottom;  fbottom.level := 0;  fdeleted := fbottom;  froot := fbottom;end;function TlkBalTree.Delete(const ws: WideString): Boolean;  procedure UpdateKeys(t: PlkBalNode; idx: integer);  begin    if t <> fbottom then begin      if t.key > idx then        t.key := t.key - 1;      UpdateKeys(t.left, idx);      UpdateKeys(t.right, idx);    end;  end;  function del(var t: PlkBalNode): Boolean;  begin    result := false;    if t<>fbottom then begin      flast := t;      if ws<t.nm then        result := del(t.left)      else begin        fdeleted := t;        result := del(t.right);      end;      if (t = flast) and (fdeleted <> fbottom) and (ws = fdeleted.nm) then begin        UpdateKeys(froot, fdeleted.key);        fdeleted.key := t.key;        fdeleted.nm := t.nm;        t := t.right;        flast.nm := '';        dispose(flast);        result := true;      end      else if (t.left.level < (t.level - 1)) or (t.right.level < (t.level - 1)) then begin        t.level := t.level - 1;        if t.right.level > t.level then          t.right.level := t.level;        skew(t);        skew(t.right);        skew(t.right.right);        split(t);        split(t.right);      end;    end;  end;{// mine version, buggy, see tracker message// [ 2229135 ] Value deletion is broken by "Nobody/Anonymous - nobody"  function del(var t: PlkBalNode): Boolean;  begin    result := false;    if t<>fbottom then      begin        flast := t;        if ws<t.nm then          result := del(t.left)        else          begin            fdeleted := t;            result := del(t.right);          end;        if (t = flast) and (fdeleted<>fbottom) and (ws = t.nm) then          begin            fdeleted.key := t.key;            fdeleted.nm := t.nm;            t := t.right;            flast.nm := '';            dispose(flast);            result := true;          end        else if (t.left.level<(t.level-1)) or (t.right.level<(t.level-1)) then          begin            t.level := t.level-1;            if t.right.level>t.level then t.right.level := t.level;            skew(t);            skew(t.right);            skew(t.right.right);            split(t);            split(t.right);          end;      end;  end;}begin  result := del(froot);end;destructor TlkBalTree.Destroy;begin  Clear;  dispose(fbottom);  inherited;end;function TlkBalTree.IndexOf(const ws: WideString): Integer;var  tk: PlkBalNode;begin  result := -1;  tk := froot;  while (result=-1) and (tk<>fbottom) do    begin      if tk.nm = ws then result := tk.key      else if ws<tk.nm then tk := tk.left      else tk := tk.right;    end;end;function TlkBalTree.Insert(const ws: WideString; x: Integer): Boolean;  function ins(var t: PlkBalNode): Boolean;  begin    if t = fbottom then      begin        new(t);        t.key := x;        t.nm := ws;        t.left := fbottom;        t.right := fbottom;        t.level := 1;        result := true;      end    else      begin        if ws < t.nm then          result := ins(t.left)        else if ws > t.nm then          result := ins(t.right)        else result := false;        skew(t);        split(t);      end;  end;begin  result := ins(froot);end;procedure TlkBalTree.skew(var t: PlkBalNode);var  temp: PlkBalNode;begin  if t.left.level = t.level then    begin      temp := t;      t := t.left;      temp.left := t.right;      t.right := temp;    end;end;procedure TlkBalTree.split(var t: PlkBalNode);var  temp: PlkBalNode;begin  if t.right.right.level = t.level then    begin      temp := t;      t := t.right;      temp.right := t.left;      t.left := temp;      t.level := t.level+1;    end;end;{$ENDIF USE_HASH}initialization{$IFNDEF THREADSAFE}{$IFDEF USE_HASH}  init_rnd;{$ENDIF USE_HASH}{$ENDIF THREADSAFE}end.
 |