Browse Source

Merge branch 'develop'

Exilon 6 years ago
parent
commit
ad1cf1ae71

+ 2 - 0
.gitignore

@@ -51,6 +51,8 @@ desktop.ini
 lib/i386-win32/
 
 backup/
+debug/
+release/
 
 *.rsj
 

+ 311 - 0
Quick.Expression.pas

@@ -0,0 +1,311 @@
+{ ***************************************************************************
+
+  Copyright (c) 2016-2019 Kike Pérez
+
+  Unit        : Quick.Expression
+  Description : Expression parser & validator
+  Author      : Kike Pérez
+  Version     : 1.0
+  Created     : 04/05/2019
+  Modified    : 31/05/2019
+
+  This file is part of QuickLib: https://github.com/exilon/QuickLib
+
+ ***************************************************************************
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ *************************************************************************** }
+
+unit Quick.Expression;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  SysUtils,
+  StrUtils,
+  RTTI,
+  Quick.Commons,
+  Quick.RTTI.Utils,
+  Quick.Value,
+  Quick.Value.RTTI;
+
+type
+  TOperator = (opNone, opEqual, opNotEqual, opGreater, opEqualOrGreater, opLower, opEqualOrLower, opLike, opLikeR, opLikeL);
+
+  TCombine = (coNone, coAND, coOR, coXOR);
+
+  TExpression = class
+  private
+    fCombine : TCombine;
+  public
+    property Combine : TCombine read fCombine write fCombine;
+    function Validate(aValue : TObject) : Boolean; virtual; abstract;
+    function IsNull : Boolean; virtual; abstract;
+  end;
+
+  TSingleExpression = class(TExpression)
+  private
+    fValue1 : string;
+    fOperator : TOperator;
+    fValue2 : string;
+  public
+    property Value1 : string read fValue1 write fValue1;
+    property &Operator : TOperator read fOperator write fOperator;
+    property Value2 : string read fValue2 write fValue2;
+    function Validate(aValue : TObject) : Boolean; override;
+    function IsNull : Boolean; override;
+  end;
+
+  TExpressionArray = array of TExpression;
+
+  TMultiExpression = class(TExpression)
+  private
+    fArray : TExpressionArray;
+  public
+    destructor Destroy; override;
+    property Items : TExpressionArray read fArray write fArray;
+    function Validate(aValue : TObject) : Boolean; override;
+    function IsNull : Boolean; override;
+    procedure Add(aExpression : TExpression);
+  end;
+
+  TExpressionParser = class
+  private
+    class function IsSingleExpression(const aExpression : string) : Boolean;
+    class function GetSingleExpression(const aExpression : string) : TSingleExpression;
+    class function GetMultiExpression(const aExpression : string) : TMultiExpression;
+    class function GetOperator(const aOperator : string) : TOperator;
+    class function GetCombine(const aValue : string) : TCombine;
+  public
+    class function Parse(const aExpression : string) : TExpression;
+    class function Validate(const obj : TObject; const aExpression : string) : Boolean;
+  end;
+
+  ENotValidExpression = class(Exception);
+  EExpressionValidateError = class(Exception);
+
+implementation
+
+const
+  OperatorStr : array[Low(TOperator)..TOperator.opLike] of string = ('none','=','<>','>','>=','<','<=','LIKE');
+  {$IFDEF NEXTGEN}
+  LOWSTR = 0;
+  {$ELSE}
+  LOWSTR = 1;
+  {$ENDIF}
+
+{ TExpressionParser }
+
+//a > 10
+//(a > 10) AND (b < 1)
+//((a > 10) AND (b < 1)) OR (c = 10)
+
+class function TExpressionParser.GetCombine(const aValue: string): TCombine;
+begin
+  if CompareText(aValue,'AND') = 0 then Result := TCombine.coAND
+    else if CompareText(aValue,'OR') = 0 then Result := TCombine.coOR
+    else if CompareText(aValue,'XOR') = 0 then Result := TCombine.coXOR;
+end;
+
+class function TExpressionParser.GetMultiExpression(const aExpression : string) : TMultiExpression;
+var
+  count : Integer;
+  i : Integer;
+  idx : Integer;
+  exp : string;
+  combine : string;
+  rexp : TExpression;
+  str : string;
+begin
+  i := LOWSTR;
+  idx := 0;
+  count := 0;
+  Result := TMultiExpression.Create;
+  exp := aExpression.TrimLeft;
+  while not exp.IsEmpty do
+  begin
+    if exp[i] = '(' then
+    begin
+      Inc(count);
+      if count = 1 then idx := i;
+    end
+    else if exp[i] = ')' then Dec(count);
+    if (count = 0) and (idx > 0) then
+    begin
+      str := ExtractStr(exp,idx,i - idx +1);
+      exp := exp.TrimLeft;
+      if IsSingleExpression(str) then rexp := GetSingleExpression(str)
+      else
+      begin
+        //remove outer parentesis
+        if str.StartsWith('(') then str := Copy(str,LOWSTR + 1,str.Length - 2);
+        rexp := GetMultiExpression(str);
+      end;
+      //get combine
+      combine := ExtractStr(exp,LOWSTR,exp.IndexOf(' '));
+      exp := exp.TrimLeft;
+      rexp.Combine := GetCombine(combine);
+      if (rexp.Combine = TCombine.coNone) and not (exp.IsEmpty) then raise ENotValidExpression.Create('Not valid expression defined!');
+      //add to multiexpression
+      Result.Add(rexp);
+      idx := 0;
+      i := -1;
+    end;
+    Inc(i);
+  end;
+end;
+
+class function TExpressionParser.GetOperator(const aOperator: string): TOperator;
+var
+  op : TOperator;
+begin
+  for op := Low(TOperator) to High(TOperator) do
+  begin
+    if CompareText(OperatorStr[op],aOperator) = 0 then Exit(op);
+  end;
+  raise ENotValidExpression.Create('Not valid operator defined!');
+end;
+
+class function TExpressionParser.GetSingleExpression(const aExpression: string) : TSingleExpression;
+var
+  exp : string;
+begin
+  if aExpression.StartsWith('(') then exp := GetSubString(aExpression,'(',')')
+    else exp := aExpression;
+  Result := TSingleExpression.Create;
+  Result.Value1 := ExtractStr(exp,LOWSTR,exp.IndexOf(' '));
+  exp := exp.TrimLeft;
+  Result.&Operator := GetOperator(ExtractStr(exp,LOWSTR,exp.IndexOf(' ')));
+  Result.Value2 := UnDbQuotedStr(exp);
+  //determine like
+  if Result.&Operator = opLike then
+  begin
+    if Result.Value2.CountChar('%') = 2 then Result.Value2 := Copy(Result.Value2, 2, Result.Value2.Length - 2)
+    else if Result.Value2.StartsWith('%') then
+    begin
+      Result.&Operator := TOperator.opLikeR;
+      Result.Value2 := Copy(Result.Value2, 2, Result.Value2.Length);
+    end
+    else if Result.Value2.EndsWith('%') then
+    begin
+      Result.&Operator := TOperator.opLikeL;
+      Result.Value2 := Copy(Result.Value2,LOWSTR,Result.Value2.Length - 1);
+    end
+    else raise ENotValidExpression.Create('Not valid Like specified!');
+  end;
+end;
+
+class function TExpressionParser.IsSingleExpression(const aExpression: string): Boolean;
+begin
+  Result := (aExpression.CountChar('(') < 2) and (aExpression.CountChar(')') < 2);
+end;
+
+class function TExpressionParser.Parse(const aExpression : string) : TExpression;
+var
+  exp : string;
+begin
+  if aExpression.IsEmpty then raise ENotValidExpression.Create('Expression is empty');
+  exp := aExpression.TrimLeft;
+  //single expression or multiexpression
+  if IsSingleExpression(exp) then Exit(GetSingleExpression(exp))
+    else Result := GetMultiExpression(exp);
+end;
+
+class function TExpressionParser.Validate(const obj: TObject; const aExpression: string): Boolean;
+var
+  exp : TExpression;
+begin
+  exp := TExpressionParser.Parse(aExpression);
+  try
+    Result := exp.Validate(obj);
+  finally
+    exp.Free;
+  end;
+end;
+
+{ TSingleExpression }
+
+function TSingleExpression.IsNull: Boolean;
+begin
+  Result := (fValue1.IsEmpty) or (fValue2.IsEmpty);
+end;
+
+function TSingleExpression.Validate(aValue : TObject) : Boolean;
+var
+  value1 : TFlexValue;
+  value2 : TFlexValue;
+begin
+  if aValue = nil then Exit;
+  value1.AsTValue := TRTTI.GetPathValue(aValue,fValue1);
+  case fOperator of
+    TOperator.opEqual :
+      begin
+        if value1.IsString then Result := CompareText(value1,fValue2) = 0
+          else Result := value1{$IFDEF FPC}.AsAnsiString{$ENDIF} = fValue2;
+      end;
+    TOperator.opNotEqual : Result := value1{$IFDEF FPC}.AsAnsiString{$ENDIF}  <> fValue2;
+    TOperator.opGreater : Result := value1{$IFDEF FPC}.AsAnsiString{$ENDIF}  > fValue2;
+    TOperator.opEqualOrGreater : Result := value1{$IFDEF FPC}.AsAnsiString{$ENDIF}  >= fValue2;
+    TOperator.opLower : Result := value1{$IFDEF FPC}.AsAnsiString{$ENDIF}  < fValue2;
+    TOperator.opEqualOrLower : Result := value1{$IFDEF FPC}.AsAnsiString{$ENDIF}  <= fValue2;
+    TOperator.opLike : Result := {$IFNDEF FPC}ContainsText(value1,fValue2);{$ELSE}AnsiContainsText(value1.AsAnsiString,fValue2);{$ENDIF}
+    TOperator.opLikeR : Result := EndsText(fValue2,value1);
+    TOperator.opLikeL : Result := StartsText(fValue2,value1);
+    else raise ENotValidExpression.Create('Operator not defined');
+  end;
+end;
+
+{ TMultiExpression }
+
+procedure TMultiExpression.Add(aExpression: TExpression);
+begin
+  fArray := fArray + [aExpression];
+end;
+
+destructor TMultiExpression.Destroy;
+var
+  exp : TExpression;
+begin
+  for exp in fArray do exp.Free;
+  inherited;
+end;
+
+function TMultiExpression.IsNull: Boolean;
+begin
+  Result := High(fArray) < 0;
+end;
+
+function TMultiExpression.Validate(aValue : TObject) : Boolean;
+var
+  i : Integer;
+begin
+  Result := False;
+  for i := Low(fArray) to High(fArray) do
+  begin
+    if i = Low(fArray) then Result := fArray[i].Validate(aValue)
+    else
+    begin
+      case fArray[i-1].Combine of
+        TCombine.coAND : Result := Result and fArray[i].Validate(aValue);
+        TCombine.coOR : Result := Result or fArray[i].Validate(aValue);
+        TCombine.coXOR : Result := Result xor fArray[i].Validate(aValue);
+        else Exit;
+      end;
+    end;
+  end;
+end;
+
+end.

+ 454 - 0
Quick.Linq.pas

@@ -0,0 +1,454 @@
+{ ***************************************************************************
+
+  Copyright (c) 2016-2019 Kike Pérez
+
+  Unit        : Quick.Linq
+  Description : Arrays and Generic Lists Linq functions
+  Author      : Kike Pérez
+  Version     : 1.0
+  Created     : 04/04/2019
+  Modified    : 31/05/2019
+
+  This file is part of QuickLib: https://github.com/exilon/QuickLib
+
+ ***************************************************************************
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ *************************************************************************** }
+
+unit Quick.Linq;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  SysUtils,
+  Generics.Collections,
+  Generics.Defaults,
+  RTTI,
+  Quick.RTTI.Utils,
+  Quick.Expression,
+  Quick.Commons,
+  Quick.Value,
+  {$IFDEF FPC}
+  Quick.Value.RTTI,
+  {$ENDIF}
+  Quick.Arrays;
+
+type
+
+  TOrderDirection = (odAscending, odDescending);
+
+  ILinqQuery<T> = interface
+  ['{16B68C0B-EA38-488A-99D9-BAD1E8560E8E}']
+    function Where(const aWhereClause : string; aWhereValues : array of const) : ILinqQuery<T>; overload;
+    function Where(const aWhereClause: string): ILinqQuery<T>; overload;
+    function OrderBy(const aFieldNames : string) : ILinqQuery<T>;
+    function OrderByDescending(const aFieldNames : string) : ILinqQuery<T>;
+    function SelectFirst : T;
+    function SelectLast : T;
+    function SelectTop(aLimit : Integer) : TxArray<T>;
+    function Select : TxArray<T>; overload;
+    function Select(const aPropertyName : string) : TFlexArray; overload;
+    function Count : Integer;
+    function Update(const aFields : array of string; aValues : array of const) : Integer;
+    function Delete : Integer;
+  end;
+
+  TLinqQuery<T : class> = class(TInterfacedObject,ILinqQuery<T>)
+  private type
+    arrayOfT = array of T;
+  private
+    fWhereClause : TExpression;
+    fOrderBy : TArray<string>;
+    fOrderDirection : TOrderDirection;
+    //fPList : Pointer;
+    fList : arrayOfT;
+    function FormatParams(const aWhereClause : string; aWhereParams : array of const) : string;
+    procedure DoOrderBy(vArray : ArrayOfT);
+    function Compare(const aPropertyName : string; L, R : T) : Integer;
+    procedure Clear;
+  public
+    {$IFNDEF FPC}
+    constructor Create(aObjectList : TObjectList<T>); overload;
+    {$ENDIF}
+    constructor Create(aList : TList<T>); overload;
+    constructor Create(aXArray : TxArray<T>); overload;
+    constructor Create(aArray : TArray<T>); overload;
+    destructor Destroy; override;
+    function Where(const aWhereClause : string; aWhereParams : array of const) : ILinqQuery<T>; overload;
+    function Where(const aWhereClause: string): ILinqQuery<T>; overload;
+    function OrderBy(const aFieldNames : string) : ILinqQuery<T>;
+    function OrderByDescending(const aFieldNames : string) : ILinqQuery<T>;
+    function SelectFirst : T;
+    function SelectLast : T;
+    function SelectTop(aLimit : Integer) : TxArray<T>;
+    function Select : TxArray<T>; overload;
+    function Select(const aPropertyName : string) : TFlexArray; overload;
+    function Count : Integer;
+    function Update(const aFields : array of string; aValues : array of const) : Integer;
+    function Delete : Integer;
+  end;
+
+  TLinq<T : class> = class
+  public
+    {$IFNDEF FPC}
+    class function From(aObjectList : TObjectList<T>) : ILinqQuery<T>; overload;
+    {$ENDIF}
+    class function From(aArray : TArray<T>) : ILinqQuery<T>; overload;
+    class function From(aXArray : TXArray<T>) : ILinqQuery<T>; overload;
+  end;
+
+  ELinqNotValidExpression = class(Exception);
+  ELinqError = class(Exception);
+
+
+implementation
+
+{ TLinqQuery<T> }
+
+procedure TLinqQuery<T>.Clear;
+begin
+  SetLength(fOrderBy,0);
+end;
+
+constructor TLinqQuery<T>.Create(aArray: TArray<T>);
+begin
+  Clear;
+  fList := aArray;
+end;
+
+{$IFNDEF FPC}
+constructor TLinqQuery<T>.Create(aObjectList: TObjectList<T>);
+begin
+  Clear;
+  //Create(aObjectList.List);
+  //fPList := Pointer(aObjectList.List);
+  //fList := arrayOfT(fPList);
+  fList := aObjectList.List;
+end;
+{$ENDIF}
+
+constructor TLinqQuery<T>.Create(aXArray: TxArray<T>);
+begin
+  Clear;
+  fList := aXArray;
+end;
+
+constructor TLinqQuery<T>.Create(aList: TList<T>);
+begin
+  Clear;
+  fList := aList.ToArray;
+end;
+
+function TLinqQuery<T>.Compare(const aPropertyName: string; L, R: T): Integer;
+var
+  valueL : TValue;
+  valueR : TValue;
+begin
+  Result := 0;
+  valueL := TRTTI.GetPathValue(L,aPropertyName);
+  valueR := TRTTI.GetPathValue(R,aPropertyName);
+  if (valueL.IsEmpty) and (not valueR.IsEmpty) then Exit(1)
+    else if (not valueL.IsEmpty) and (valueR.IsEmpty) then Exit(-1);
+
+  case valueL.Kind of
+    {$IFNDEF FPC}
+    tkString,
+    {$ENDIF}
+    tkChar, tkWString, tkUString : Result := CompareText(valueL.AsString, valueR.AsString);
+    tkInteger, tkInt64 :
+      begin
+        if valueL.AsInteger > valueR.AsInteger then Result := 1
+          else if valueL.AsInteger < valueR.AsInteger then Result := -1;
+      end;
+    tkFloat :
+      begin
+        if valueL.AsExtended > valueR.AsExtended then Result := 1
+          else if valueL.AsExtended < valueR.AsExtended then Result := -1;
+      end;
+    end;
+end;
+
+function TLinqQuery<T>.Count: Integer;
+var
+  i : Integer;
+begin
+  Result := 0;
+  if fWhereClause = nil then raise ELinqNotValidExpression.Create('Not valid expression defined!');
+  for i := High(fList) downto Low(fList) do
+  begin
+    if fWhereClause.Validate(fList[i]) then
+    begin
+      Inc(Result);
+    end;
+  end;
+end;
+
+function TLinqQuery<T>.Delete: Integer;
+var
+  i : Integer;
+begin
+  Result := 0;
+  if fWhereClause = nil then raise ELinqNotValidExpression.Create('Not valid expression defined!');
+  for i := High(fList) downto Low(fList) do
+  begin
+    if fWhereClause.Validate(fList[i]) then
+    begin
+      TObject(fList[i]).Free;
+      //System.Delete(fList,i,1);
+      Inc(Result);
+    end;
+  end;
+end;
+
+destructor TLinqQuery<T>.Destroy;
+begin
+  if Assigned(fWhereClause) then fWhereClause.Free;
+  inherited;
+end;
+
+procedure TLinqQuery<T>.DoOrderBy(vArray : ArrayOfT);
+begin
+  if High(fOrderBy) < 0 then Exit;
+  {$IFNDEF FPC}
+  TArray.Sort<T>(vArray, TComparer<T>.Construct(
+        function (const A, B: T): Integer
+        var
+          field : string;
+        begin
+          for field in fOrderBy do
+          begin
+            Result := Compare(field,A,B);
+            if Result <> 0 then Break;
+          end;
+          if fOrderDirection = TOrderDirection.odDescending then Result := Result * -1;
+        end)
+      );
+  {$ENDIF}
+end;
+
+function TLinqQuery<T>.OrderBy(const aFieldNames: string): ILinqQuery<T>;
+begin
+  Result := Self;
+  if aFieldNames = '' then raise ELinqError.Create('No order fields specified!');
+  fOrderBy := aFieldNames.Split([',']);
+  fOrderDirection := TOrderDirection.odAscending;
+end;
+
+function TLinqQuery<T>.OrderByDescending(const aFieldNames: string): ILinqQuery<T>;
+begin
+  Result := Self;
+  if aFieldNames = '' then raise ELinqError.Create('No order fields specified!');
+  fOrderBy := aFieldNames.Split([',']);
+  fOrderDirection := TOrderDirection.odDescending;
+end;
+
+function TLinqQuery<T>.Select(const aPropertyName: string): TFlexArray;
+var
+  obj : T;
+  value : TFlexValue;
+begin
+  if fWhereClause = nil then raise ELinqNotValidExpression.Create('Not valid expression defined!');
+  for obj in fList do
+  begin
+    if fWhereClause.Validate(obj) then
+    begin
+      //value := TRTTI.GetProperty(obj,aPropertyName);
+      {$IFNDEF FPC}
+      value := TRTTI.GetPathValue(obj,aPropertyName).AsVariant;
+      {$ELSE}
+      value.AsTValue := TRTTI.GetPathValue(obj,aPropertyName);
+      {$ENDIF}
+      Result.Add(value);
+    end;
+  end;
+end;
+
+function TLinqQuery<T>.Select: TxArray<T>;
+var
+  obj : T;
+begin
+  if fWhereClause = nil then raise ELinqNotValidExpression.Create('Not valid expression defined!');
+  for obj in fList do
+  begin
+    if fWhereClause.Validate(obj) then Result.Add(obj);
+  end;
+  DoOrderBy(Result);
+end;
+
+function TLinqQuery<T>.SelectFirst: T;
+var
+  obj : T;
+begin
+  {$IFNDEF FPC}
+  Result := nil;
+  {$ENDIF}
+  DoOrderBy(fList);
+  if fWhereClause = nil then raise ELinqNotValidExpression.Create('Not valid expression defined!');
+  for obj in fList do
+  begin
+    if fWhereClause.Validate(obj) then Exit(obj);
+  end;
+end;
+
+function TLinqQuery<T>.SelectLast: T;
+var
+  obj : T;
+begin
+  {$IFNDEF FPC}
+  Result := nil;
+  {$ENDIF}
+  DoOrderBy(fList);
+  if fWhereClause = nil then raise ELinqNotValidExpression.Create('Not valid expression defined!');
+  for obj in fList do
+  begin
+    if fWhereClause.Validate(obj) then Result := obj;
+  end;
+end;
+
+function TLinqQuery<T>.SelectTop(aLimit: Integer): TxArray<T>;
+var
+  obj : T;
+  i : Integer;
+begin
+  DoOrderBy(fList);
+  if fWhereClause = nil then raise ELinqNotValidExpression.Create('Not valid expression defined!');
+  i := 0;
+  for obj in fList do
+  begin
+    if fWhereClause.Validate(obj) then
+    begin
+      Result.Add(obj);
+      Inc(i);
+      if i > aLimit then Exit;
+    end;
+  end;
+end;
+
+function TLinqQuery<T>.Update(const aFields: array of string; aValues: array of const): Integer;
+var
+  obj : T;
+  i : Integer;
+  {$IFDEF FPC}
+  value : TValue;
+  {$ENDIF}
+begin
+  Result := 0;
+  if fWhereClause = nil then raise ELinqNotValidExpression.Create('Not valid expression defined!');
+  for obj in fList do
+  begin
+    if obj = nil then continue;
+    if fWhereClause.Validate(obj) then
+    begin
+      for i := Low(aFields) to High(aFields)  do
+      begin
+        if not TRTTI.PropertyExists(TypeInfo(T),aFields[i]) then raise ELinqError.CreateFmt('Linq update field "%s" not found in obj',[aFields[i]]);
+        try
+          {$IFNDEF FPC}
+          TRTTI.SetPropertyValue(obj,aFields[i],aValues[i]);
+          {$ELSE}
+          case aValues[i].VType of
+            vtString : value := string(aValues[i].VString^);
+            vtChar : value := string(aValues[i].VChar);
+            {$IFDEF MSWINDOWS}
+            vtAnsiString : value := AnsiString(aValues[i].VAnsiString);
+            vtWideString : value := WideString(aValues[i].VWideString);
+            {$ENDIF}
+            {$IFDEF UNICODE}
+            vtUnicodeString: AsString := string(aValues[i].VUnicodeString);
+            {$ENDIF UNICODE}
+            vtInteger : value := aValues[i].VInteger;
+            vtInt64 : value := aValues[i].VInt64^;
+            vtExtended : value := aValues[i].VExtended^;
+            vtBoolean : value := aValues[i].VBoolean;
+           else raise Exception.Create('DataType not supported by Linq update');
+          end;
+          TRTTI.SetPropertyValue(obj,aFields[i],value);
+          {$ENDIF}
+        except
+          on E : Exception do raise ELinqError.CreateFmt('Linq update error: %s',[e.Message]);
+        end;
+      end;
+      Inc(Result);
+    end;
+  end;
+end;
+
+function TLinqQuery<T>.FormatParams(const aWhereClause : string; aWhereParams : array of const) : string;
+var
+  i : Integer;
+begin
+  Result := aWhereClause;
+  if aWhereClause = '' then
+  begin
+    Result := '1 = 1';
+    Exit;
+  end;
+  for i := 0 to aWhereClause.CountChar('?') - 1 do
+  begin
+    case aWhereParams[i].VType of
+      vtInteger : Result := StringReplace(Result,'?',IntToStr(aWhereParams[i].VInteger),[]);
+      vtInt64 : Result := StringReplace(Result,'?',IntToStr(aWhereParams[i].VInt64^),[]);
+      vtExtended : Result := StringReplace(Result,'?',FloatToStr(aWhereParams[i].VExtended^),[]);
+      vtBoolean : Result := StringReplace(Result,'?',BoolToStr(aWhereParams[i].VBoolean),[]);
+      vtAnsiString : Result := StringReplace(Result,'?',string(aWhereParams[i].VAnsiString),[]);
+      vtWideString : Result := StringReplace(Result,'?',string(aWhereParams[i].VWideString^),[]);
+      {$IFNDEF NEXTGEN}
+      vtString : Result := StringReplace(Result,'?',aWhereParams[i].VString^,[]);
+      {$ENDIF}
+      vtChar : Result := StringReplace(Result,'?',aWhereParams[i].VChar,[]);
+      vtPChar : Result := StringReplace(Result,'?',string(aWhereParams[i].VPChar),[]);
+    else Result := StringReplace(Result,'?', DbQuotedStr(string(aWhereParams[i].VUnicodeString)),[]);
+    end;
+  end;
+end;
+
+function TLinqQuery<T>.Where(const aWhereClause: string; aWhereParams: array of const): ILinqQuery<T>;
+begin
+  Result := Where(FormatParams(aWhereClause,aWhereParams));
+end;
+
+function TLinqQuery<T>.Where(const aWhereClause: string): ILinqQuery<T>;
+begin
+  Result := Self;
+  try
+    fWhereClause := TExpressionParser.Parse(aWhereClause);
+  except
+    on E : Exception do raise ELinqNotValidExpression.Create(e.Message);
+  end;
+end;
+
+{ TLinq }
+
+{$IFNDEF FPC}
+class function TLinq<T>.From(aObjectList: TObjectList<T>): ILinqQuery<T>;
+begin
+  Result := TLinqQuery<T>.Create(aObjectList);
+end;
+{$ENDIF}
+
+class function TLinq<T>.From(aArray: TArray<T>): ILinqQuery<T>;
+begin
+  Result := TLinqQuery<T>.Create(aArray);
+end;
+
+class function TLinq<T>.From(aXArray : TXArray<T>) : ILinqQuery<T>;
+begin
+  Result := TLinqQuery<T>.Create(aXArray);
+end;
+
+
+end.

+ 6 - 3
Quick.RTTI.Utils.pas

@@ -7,7 +7,7 @@
   Author      : Kike Pérez
   Version     : 1.4
   Created     : 09/03/2018
-  Modified    : 21/05/2019
+  Modified    : 27/05/2019
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -411,9 +411,12 @@ begin
   Result := fCtx.GetType(aTypeInfo);
 end;
 
-class function TRTTI.PropertyExists(aTypeInfo: Pointer; const aPropertyName: string): Boolean;
+class function TRTTI.PropertyExists(aTypeInfo: Pointer; const aPropertyName: string) : Boolean;
+var
+  rtype : TRttiType;
 begin
-  Result := fCtx.GetType(aTypeInfo).GetProperty(aPropertyName) <> nil;
+  rtype := fCtx.GetType(aTypeInfo);
+  if rtype <> nil then Result := rtype.GetProperty(aPropertyName) <> nil;
 end;
 
 class procedure TRTTI.SetPropertyValue(aInstance: TObject; const aPropertyName: string; aValue: TValue);

+ 3 - 0
Quick.Value.RTTI.pas

@@ -82,11 +82,14 @@ begin
     tkChar,
     {$IFNDEF FPC}
     tkString,
+    tkUstring,
     {$ELSE}
     tkAstring,
     {$ENDIF}
     tkWideString,
     tkWideChar : AsString := Value.AsString;
+    tkEnumeration,
+    tkSet : AsInteger := Value.AsInteger;
     {$IFNDEF FPC}
     else AsVariant := Value.AsVariant;
     {$ENDIF}

+ 84 - 15
README.md

@@ -5,6 +5,53 @@
 --------
 
 Small delphi/Firemonkey(Windows, Linux, Android, OSX & IOS) and fpc(Windows & Linux) library containing interesting and quick to implement functions, created to simplify application development and crossplatform support and improve productivity.
+
+**Areas of functionality:**
+  
+* **Mapping**: Map fields from a class to other class, copy objects, etc..
+* **Config**: Thread your config as an object and load/save from/to file (Json/Yaml) or Windows Registry.
+* **Serialization**: Serialize objects to/from json/Yaml.
+* **Scheduling**: Schedule tasks launching as independent threads.
+* **Threading**: Simplify run and control of multithread background tasks, Thread-safe Lists, queues, etc
+* **Data**: Flexible data interchange and storage, allowing several input-output types.
+* **Cloud**: Simplify cloud Azure/Amazon file management, send emails and more.
+* **Querying**: Indexed Lists, Searchable Lists and Linq query system for generic lists and arrays.
+* **Benchmark**: Time elapsed control and benchmark functions.
+* **Filesystem**: Process and Services control, file modify monitors and helpers, etc...
+
+
+**Main units description:**
+
+* **Quick.Commons:** Functions frequently needed in the day to day of a developer. 
+* **Quick.AppService:** Allow a console app to run as console mode or service mode with same code simplifying debug tasks.
+* **Quick.Azure/Amazon:** Simplifies blob iteraction with Azure and Amazon Cloud Storage.
+* **Quick.Network:** CIDR and IP Range functions.
+* **Quick.Chrono:** Chronometer and Benchmark a piece of code is simple.
+* **Quick.Console:** Write log messages to console with colors and more...
+* **Quick.Log:** Log to disk or memory with verbose levels and daily or max space rotation.
+* **Quick.Config:** Load/Save a config as Json or Yaml file or Windows Registry keys and manage it as an object.
+* **Quick.FileMonitor:** Monitorizes a file for changes and throws events.
+* **Quick.JsonUtils:** Utils for working with json objects.
+* **Quick.SMTP:** Send email with two code lines.
+* **Quick.Threads:** Thread safe classes, scheduling and backgrounds tasks.
+* **Quick.Process:** Manages windows processes.
+* **Quick.Services:** Manages windows services.
+* **Quick.Format:** String format.
+* **Quick.JsonSerializer:** Serializes an object from/to json text. You can define if public or published will be processed (only Delphi, fpc rtti only supports published properties)	
+* **Quick.AutoMapper:** Map fields from one class to another class. Allows custom mappings to match different fields and custom mapping procedure to cast/convert fields manually.	
+* **Quick.JsonRecord:** Used as a DTO class, with json serialize and mapping functions included.	
+* **Quick.Lists:** Improved lists with indexing or search features.
+* **Quick.Value** FlexValue stores any data type and allow pass to other class with integrated operators and autofrees.
+* **Quick.Arrays:** Improved arrays.
+* **Quick.YAML:** Yaml object structure.
+* **Quick.YAML.Serializer:** Serialize/Deserialize object from/to Yaml.
+* **Quick.Expression:** Evaluate object properties using expressions.
+* **Quick.Linq:** Makes Linq queries to any TObjectList<T>, TList<T>, TArray<T> and TXArray<T>, performing Select by complex Where like SQL syntax, update and order over your list.
+
+
+**Updates:**
+
+* NEW: Linq over generic lists and arrays.
 * NEW: QuickConfig YAML provider.
 * NEW: YAML Object and Serializer
 * NEW: AutoMapper customapping path namespaces style.
@@ -15,20 +62,8 @@ Small delphi/Firemonkey(Windows, Linux, Android, OSX & IOS) and fpc(Windows & Li
 * NEW: Delphi Linux compatibility
 * NEW: QuickConfigJson reload if config file changed
 * NEW: First version with OSX/IOS partial support
-* NEW: Refactorized Quick.Config (more easy)
-* NEW: TScheduledTasks: New schedule methods.
-* NEW: TAnonymousThread, TBackgroundTasks & TScheduledTasks _Sync methods
-* NEW: TBackgroundTasks & TScheduledTasks
-* NEW: TAnonymousThread simplified
-* NEW: TIndexedObjectList & TSearchObjectList.
-* NEW: RTTIUtils.
-* NEW: Improved firemonkey android compatibility.
-* NEW: JsonRecord
-* NEW: AutoMapper
-* NEW: JsonSerializer
-* NEW: Improved Linux compatibility.
-* NEW: Delphinus support
 
+**Documentation:**
 ----------
 **Quick.AppService:** Allow a console app to run as console mode or service mode with same code simplifying debug tasks.
 
@@ -177,7 +212,7 @@ Log.Add('Error x',etError);
 Log.Add('Error is %s',[ErrorStr],etError);
 ```
 
-**Quick.Config:** Load/Save a config as Json or Yaml file or Windows Registry keys. Create a descend class from TAppConfigJson or TAppConfigRegistry and add private variables will be loaded/saved. TAppConfiJson allow detect if config file was changed and do a config reload.
+**Quick.Config:** Load/Save a config as Json or Yaml file or Windows Registry keys. Create a descend class from TAppConfigJson, TAppConfigYaml or TAppConfigRegistry and added published properties will be loaded/saved. Files configs can be reloaded on detect files changes.
 
 ```delphi
 //create a class heritage
@@ -296,6 +331,7 @@ TAnonymousThread.Execute(
       end)
     .Start;
 ```
+
 - **TBackgroundsTasks:** Launch tasks in background allowing number of concurrent workers. Use AddTask_Sync and OnTerminate_Sync methods if code needs to update UI.
   - *AddTask:* Specify Task name, parameters to pass to anonymous method(If OwnedParams=true, task will free params on expiration task) and method than will be executed. 
   - *AddTask_Sync:* Like AddTask but runs code with synchronize thread method (avoids problems if your code updates UI).
@@ -399,7 +435,7 @@ writeln('Explorer.exe open by: ' + GetProcessUser('explorer.exe');
 if FindWindowTimeout('MainWindow',20) then writeln('Window detected');
 ```
 
-**Quick.Process:** Manages windows services.
+**Quick.Services:** Manages windows services.
 ```delphi
 //detect if a service is installed
 if not ServiceIsPresent('localhost','MySvc') then raise Exception.Create('Service not installed!');
@@ -575,6 +611,7 @@ begin
     end;
 end;
 ```
+
 **Quick.YAML:** Yaml object structure.
 - TYamlObject: A Yaml object is and array of YamlValue pairs.
 ```delphi
@@ -601,4 +638,36 @@ end;
   text := YamlSerializer.ObjectToYaml(obj);
   //Deserialize
   YamlSerializer.YamlToObject(obj,yamltext);
+```
+
+**Quick.Expression:** Evaluate object properties using expressions.
+```delphi
+  if TExpressionParser.Validate(user,('(Age > 30) AND (Dept.Name = "Financial")') then
+  begin
+    //do something
+  end;
+```
+
+**Quick.Linq:** Makes Linq queries to any TObjectList<T>, TList<T>, TArray<T> and TXArray<T>, performing Select by complex Where like SQL syntax, update and order over your list.
+```delphi
+  //Select multi conditional
+  for user in TLinq<TUser>.From(userslist).Where('(Name = ?) OR (SurName = ?) OR (SurName = ?)',['Peter','Smith','Huan']).Select do
+  begin
+    //do something
+  end;
+  
+  //Select like and update field
+  TLinq<TUser>.From(userlist).Where('SurName Like ?',['%son']).SelectFirst.Name := 'Robert';
+  
+  //Select top and Order by field
+  for user in TLinq<TUser>.From(userlist).Where('Age > ?',[18]).SelectTop(10).OrderBy('Name') do
+  begin
+    //do something
+  end;
+  
+  //update fields by conditional
+  TLinq<TUser>.From(userlist).Where('Name = ?',['Peter']).Update(['Name'],['Joe']);
+  
+  //count results
+  numusers := TLinq<TUser>.From(userlist).Where('(Age > ?) AND (Age < ?)',[30,40]).Count;
 ```

+ 189 - 0
samples/delphi/Quick.Linq/LinqLists/LinqList.dpr

@@ -0,0 +1,189 @@
+program LinqList;
+
+{$APPTYPE CONSOLE}
+
+{$R *.res}
+
+uses
+  System.SysUtils,
+  Quick.Commons,
+  Quick.Console,
+  Quick.Chrono,
+  Quick.Lists,
+  Quick.Linq;
+
+type
+  TLoginInfo = record
+    Username : string;
+    UserPassword : string;
+    Locked : Boolean;
+  end;
+
+  TUser = class
+  private
+    fId : Int64;
+    fName : string;
+    fSurName : string;
+    fAge : Integer;
+    fLoginInfo : TLoginInfo;
+  published
+    property Id : Int64 read fId write fId;
+    property Name : string read fName write fName;
+    property SurName : string read fSurName write fSurName;
+    property Age : Integer read fAge write fAge;
+    property LoginInfo : TLoginInfo read fLoginInfo write fLoginInfo;
+  end;
+
+
+const
+  numusers = 100000;
+  UserNames : array of string = ['Cliff','Alan','Anna','Phil','John','Michel','Jennifer','Peter','Brandon','Joe','Steve','Lorraine','Bill','Tom','Norma','Martin','Steffan','Wilma','Derek','Lewis','Paul',
+                                 'Erik','Robert','Nicolas','Frederik','Rose'];
+  UserSurnames : array of string = ['Gordon','Summer','Huan','Paterson','Johnson','Michelson','Smith','Peterson','Miller','McCarney','Roller','Gonzalez','Thomson','Muller','Jefferson','Volkov','Matheu','Morrison','Newman','Lover','Sunday',
+                                    'Roberts','Landon','Yuri','Paris','Levis'];
+
+
+var
+  users : TIndexedObjectList<TUser>;
+  users2 : TSearchObjectList<TUser>;
+  user : TUser;
+  i : Integer;
+  n : Integer;
+  crono : TChronometer;
+  login : TLoginInfo;
+
+begin
+  try
+    ReportMemoryLeaksOnShutdown := True;
+
+    users := TIndexedObjectList<TUser>.Create(True);
+    users.Indexes.Add('Name','Name');
+    users.Indexes.Add('Surname','fSurname',TClassField.cfField);
+    users.Indexes.Add('id','Id');
+
+    users2 := TSearchObjectList<TUser>.Create(False);
+
+    cout('Generating list...',etInfo);
+    //generate first dummy entries
+    for i := 1 to numusers - high(UserNames) do
+    begin
+      user := TUser.Create;
+      user.Id := Random(999999999999999);
+      user.Name := 'Name' + i.ToString;
+      user.SurName := 'SurName' + i.ToString;
+      user.Age := 18 + Random(20);
+      users.Add(user);
+      users2.Add(user);
+    end;
+
+    //generate real entries to search
+    for i := 0 to high(UserNames) do
+    begin
+      user := TUser.Create;
+      user.Id := Random(999999999999999);
+      user.Name := UserNames[i];
+      user.SurName := UserSurnames[i];
+      user.Age := 18 + Random(20);
+      login.Username := user.Name;
+      login.UserPassword := RandomPassword(8,[pfIncludeNumbers,pfIncludeSigns]);
+      login.Locked := False;
+      user.LoginInfo := login;
+
+      users.Add(user);
+      users2.Add(user);
+    end;
+
+    crono := TChronometer.Create;
+
+    //test search by index
+    crono.Start;
+    user := users.Get('Name','Peter');
+    crono.Stop;
+    if user <> nil then cout('Found by Index: %s %s in %s',[user.Name,user.SurName,crono.ElapsedTime],etSuccess)
+      else cout('Not found!',etError);
+
+    //test search by normal iteration
+    user := nil;
+    crono.Start;
+    for i := 0 to users.Count - 1 do
+    begin
+      //if (users[i].Name = 'Anus') or (users[i].SurName = 'Smith') then
+      if users[i].Name = 'Peter' then
+      begin
+        crono.Stop;
+        user := users[i];
+        Break;
+      end;
+    end;
+    if user <> nil then cout('Found by Iteration: %s %s at %d position in %s',[user.Name,user.SurName,i,crono.ElapsedTime],etSuccess)
+      else cout('Not found by Iteration!',etError);
+
+
+    //test search by Linq iteration
+    crono.Start;
+    //user := TLinq.From<TUser>(users2).Where('(Name = ?) OR (SurName = ?)',['Anus','Smith']).OrderBy('Name').SelectFirst;
+    user := TLinq<TUser>.From(users2).Where('Name = ?',['Peter']).SelectFirst;
+    crono.Stop;
+    if user <> nil then cout('Found by Linq: %s %s in %s',[user.Name,user.SurName,crono.ElapsedTime],etSuccess)
+      else cout('Not found by Linq! (%s)',[crono.ElapsedTime],etError);
+
+    //test search by embeded iteration
+    crono.Start;
+    user := users2.Get('Name','Peter');
+    crono.Stop;
+    if user <> nil then cout('Found by Search: %s %s in %s',[user.Name,user.SurName,crono.ElapsedTime],etSuccess)
+      else cout('Not found!',etError);
+
+    //ConsoleWaitForEnterKey;
+    cout('Multi results:',etInfo);
+
+    //test search by normal iteration
+    user := nil;
+    n := 0;
+    cout('Found by Iteration:',etInfo);
+    for i := 0 to users.Count - 1 do
+    begin
+      //if ((users[i].Name = 'Anna') or (users[i].Age > 30)) or (users[i].SurName = 'Smith') then
+      //if users[i].Age > 18 then
+      if (users[i].Name = 'Anna') then
+      begin
+        Inc(n);
+        user := users[i];
+        cout('%d. %s %s',[n,user.Name,user.SurName],etSuccess)
+      end;
+    end;
+    if user = nil then cout('Not found by Iteration!',etError);
+
+    //test search by Linq iteration
+    user := nil;
+    n := 0;
+    cout('Found by Linq:',etInfo);
+    //TLinq<TUser>.From(users2).Where('SurName Like ?',['p%']).Delete;
+
+    TLinq<TUser>.From(users2).Where('Name = ?',['Peter']).Update(['Name'],['Poter']);
+
+    //for user in TLinq<TUser>.From(users2).Where('(Name = ?) OR (SurName = ?) OR (SurName = ?)',['Peter','Smith','Huan']).Select do
+    //for user in TLinq<TUser>.From(users2).Where('(Name = ?) OR (Age > ?) OR (SurName = ?)',['Anna',30,'Smith']).Select do
+    //for user in TLinq<TUser>.From(users2).Where('Age > ?',[18]).Select do
+    //for user in TLinq<TUser>.From(users2).Where('SurName Like ?',['%son']).Select do
+    //for user in TLinq<TUser>.From(users2).Where('SurName Like ?',['p%']).Select do
+    //for user in TLinq<TUser>.From(users2).Where('1 = 1',[]).Select do
+    for user in TLinq<TUser>.From(users2).Where('(LoginInfo.UserName Like ?) OR (LoginInfo.UserName Like ?)',['p%','a%'])
+                                         .OrderBy('Name')
+                                         .Select do
+    begin
+      Inc(n);
+      cout('%d. %s %s',[n,user.Name,user.SurName],etSuccess);
+    end;
+    if user = nil then cout('Not found by Linq!',etError);
+
+    cout('Press a key to Exit',etInfo);
+    Readln;
+    users.Free;
+    users2.Free;
+    crono.Free;
+  except
+    on E: Exception do
+      cout('%s : %s',[E.ClassName,E.Message],etError);
+  end;
+end.

+ 708 - 0
samples/delphi/Quick.Linq/LinqLists/LinqList.dproj

@@ -0,0 +1,708 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <ProjectGuid>{634B996C-7A5E-47E4-87E8-A2798A11331B}</ProjectGuid>
+        <ProjectVersion>18.6</ProjectVersion>
+        <FrameworkType>None</FrameworkType>
+        <MainSource>LinqList.dpr</MainSource>
+        <Base>True</Base>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <TargetedPlatforms>7</TargetedPlatforms>
+        <AppType>Console</AppType>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Android' and '$(Base)'=='true') or '$(Base_Android)'!=''">
+        <Base_Android>true</Base_Android>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='iOSDevice32' and '$(Base)'=='true') or '$(Base_iOSDevice32)'!=''">
+        <Base_iOSDevice32>true</Base_iOSDevice32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='iOSDevice64' and '$(Base)'=='true') or '$(Base_iOSDevice64)'!=''">
+        <Base_iOSDevice64>true</Base_iOSDevice64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='iOSSimulator' and '$(Base)'=='true') or '$(Base_iOSSimulator)'!=''">
+        <Base_iOSSimulator>true</Base_iOSSimulator>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='OSX32' and '$(Base)'=='true') or '$(Base_OSX32)'!=''">
+        <Base_OSX32>true</Base_OSX32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
+        <Cfg_1_Win32>true</Cfg_1_Win32>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <DCC_DcuOutput>.\bin\$(Platform)\$(Config)\dcu</DCC_DcuOutput>
+        <DCC_ExeOutput>.\bin\$(Platform)\$(Config)</DCC_ExeOutput>
+        <DCC_E>false</DCC_E>
+        <DCC_N>false</DCC_N>
+        <DCC_S>false</DCC_S>
+        <DCC_F>false</DCC_F>
+        <DCC_K>false</DCC_K>
+        <DCC_UsePackage>RESTComponents;FireDACIBDriver;FireDACCommon;RESTBackendComponents;soapserver;CloudService;FireDACCommonDriver;inet;FireDAC;FireDACSqliteDriver;soaprtl;soapmidas;$(DCC_UsePackage)</DCC_UsePackage>
+        <DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace>
+        <SanitizedProjectName>LinqList</SanitizedProjectName>
+        <VerInfo_Locale>3082</VerInfo_Locale>
+        <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Android)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;DBXInterBaseDriver;FMXComponents;tethering;bindcompfmx;FmxTeeUI;fmx;dbexpress;IndyCore;dsnap;bindengine;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;ibmonitor;FMXTee;DbxCommonDriver;ibxpress;xmlrtl;ibxbindings;rtl;DbxClientDriver;CustomIPTransport;bindcomp;CoolTrayIcon_D210_XE7;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;$(DCC_UsePackage)</DCC_UsePackage>
+        <Android_LauncherIcon36>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png</Android_LauncherIcon36>
+        <Android_LauncherIcon48>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png</Android_LauncherIcon48>
+        <Android_LauncherIcon72>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png</Android_LauncherIcon72>
+        <Android_LauncherIcon96>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png</Android_LauncherIcon96>
+        <Android_LauncherIcon144>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png</Android_LauncherIcon144>
+        <Android_SplashImage426>$(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png</Android_SplashImage426>
+        <Android_SplashImage470>$(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png</Android_SplashImage470>
+        <Android_SplashImage640>$(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png</Android_SplashImage640>
+        <Android_SplashImage960>$(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png</Android_SplashImage960>
+        <EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;fmx.dex.jar;google-analytics-v2.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar;google-play-services-ads-7.0.0.dex.jar;google-play-services-analytics-7.0.0.dex.jar;google-play-services-base-7.0.0.dex.jar;google-play-services-gcm-7.0.0.dex.jar;google-play-services-identity-7.0.0.dex.jar;google-play-services-maps-7.0.0.dex.jar;google-play-services-panorama-7.0.0.dex.jar;google-play-services-plus-7.0.0.dex.jar;google-play-services-wallet-7.0.0.dex.jar</EnabledSysJars>
+        <VerInfo_Keys>package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=</VerInfo_Keys>
+        <BT_BuildType>Debug</BT_BuildType>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_iOSDevice32)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;fmx;dbexpress;IndyCore;dsnap;bindengine;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;ibmonitor;FMXTee;DbxCommonDriver;ibxpress;xmlrtl;ibxbindings;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_iOSDevice64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;fmx;dbexpress;IndyCore;dsnap;bindengine;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FrameViewer;ibmonitor;FMXTee;DbxCommonDriver;ibxpress;xmlrtl;ibxbindings;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;TMSFMXPackPkgDXE11;dbxcds;dsnapxml;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_iOSSimulator)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;fmx;dbexpress;IndyCore;dsnap;bindengine;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;ibmonitor;FMXTee;DbxCommonDriver;ibxpress;xmlrtl;ibxbindings;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_OSX32)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;DBXInterBaseDriver;tethering;bindcompfmx;inetdb;FmxTeeUI;fmx;fmxdae;dbexpress;IndyCore;dsnap;bindengine;DBXMySQLDriver;FireDACMySQLDriver;FireDACCommonODBC;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDACPgDriver;ibmonitor;FMXTee;DbxCommonDriver;ibxpress;xmlrtl;ibxbindings;fmxobj;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;inetdbxpress;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+        <DCC_ConsoleTarget>true</DCC_ConsoleTarget>
+        <VerInfo_Keys>CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts</VerInfo_Keys>
+        <BT_BuildType>Debug</BT_BuildType>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;UbuntuProgressPackage;DBXInterBaseDriver;vclactnband;vclFireDAC;FMXComponents;tethering;svnui;JvGlobus;FireDACADSDriver;JvPluginSystem;JvMM;tmsxlsdXE11;vcltouch;JvBands;vcldb;bindcompfmx;svn;Intraweb;JvJans;JvNet;inetdb;JvAppFrm;EssentialsDR;vcwdedXE11;vcwdXE11;FmxTeeUI;JvDotNetCtrls;AbbreviaVCLD;fmx;fmxdae;tmsdXE11;vclib;JvWizards;tmsexdXE11;dbexpress;IndyCore;vclx;JvPageComps;dsnap;JvDB;VCLRESTComponents;JclDeveloperTools;vclie;bindengine;DBXMySQLDriver;JvCmp;FireDACMySQLDriver;JvHMI;FireDACCommonODBC;FMXComponentEd;LockBoxDR;bindcompdbx;IndyIPCommon;JvCustom;advchartdedxe11;vcl;IndyIPServer;GR32_D;JvXPCtrls;PngComponents;IndySystem;advchartdxe11;dsnapcon;FireDACMSAccDriver;fmxFireDAC;vclimg;madBasic_;TeeDB;Jcl;FrameViewer;JvCore;JvCrypt;FireDACPgDriver;ibmonitor;FMXTee;SevenZippro;DbxCommonDriver;JvDlgs;JvRuntimeDesign;ibxpress;Tee;JvManagedThreads;xmlrtl;ibxbindings;fmxobj;vclwinx;JvTimeFramework;rtl;GR32_R;DbxClientDriver;CustomIPTransport;vcldsnap;JvSystem;JvStdCtrls;bindcomp;appanalytics;CoolTrayIcon_D210_XE7;tmswizdXE11;nTrayIcon;IndyIPClient;bindcompvcl;TeeUI;TMSFMXPackPkgDXE11;JvDocking;dbxcds;VclSmp;JvPascalInterpreter;adortl;KernowSoftwareFMX;JclVcl;dsnapxml;dbrtl;inetdbxpress;IndyProtocols;JvControls;JvPrintPreview;Analog_XE7;JclContainers;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+        <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <BT_BuildType>Debug</BT_BuildType>
+        <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+        <DCC_ConsoleTarget>true</DCC_ConsoleTarget>
+        <UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44>
+        <UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;DBXInterBaseDriver;vclactnband;vclFireDAC;tethering;FireDACADSDriver;vcltouch;vcldb;bindcompfmx;Intraweb;inetdb;EssentialsDR;vcwdXE11;FmxTeeUI;AbbreviaVCLD;fmx;fmxdae;tmsdXE11;vclib;tmsexdXE11;dbexpress;IndyCore;vclx;dsnap;VCLRESTComponents;vclie;bindengine;DBXMySQLDriver;FireDACMySQLDriver;FireDACCommonODBC;bindcompdbx;IndyIPCommon;vcl;IndyIPServer;IndySystem;advchartdxe11;dsnapcon;FireDACMSAccDriver;fmxFireDAC;vclimg;TeeDB;FireDACPgDriver;ibmonitor;FMXTee;DbxCommonDriver;ibxpress;Tee;xmlrtl;ibxbindings;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;IndyIPClient;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;dsnapxml;dbrtl;inetdbxpress;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+        <DCC_ConsoleTarget>true</DCC_ConsoleTarget>
+        <UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44>
+        <UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150>
+        <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace>
+        <BT_BuildType>Debug</BT_BuildType>
+        <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+        <DCC_DebugDCUs>true</DCC_DebugDCUs>
+        <DCC_Optimize>false</DCC_Optimize>
+        <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+        <DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
+        <DCC_RemoteDebug>true</DCC_RemoteDebug>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
+        <DCC_RemoteDebug>false</DCC_RemoteDebug>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+        <Manifest_File>..\IndexedLists\(None)</Manifest_File>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+        <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+        <DCC_DebugInformation>0</DCC_DebugInformation>
+    </PropertyGroup>
+    <ItemGroup>
+        <DelphiCompile Include="$(MainSource)">
+            <MainSource>MainSource</MainSource>
+        </DelphiCompile>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+        <Borland.ProjectType>Application</Borland.ProjectType>
+        <BorlandProject>
+            <Delphi.Personality>
+                <Source>
+                    <Source Name="MainSource">LinqList.dpr</Source>
+                </Source>
+                <Excluded_Packages>
+                    <Excluded_Packages Name="$(BDSBIN)\DataExplorerDBXPluginEnt260.bpl">DBExpress Enterprise Data Explorer Integration</Excluded_Packages>
+                    <Excluded_Packages Name="$(BDSBIN)\bcboffice2k260.bpl">Embarcadero C++Builder Office 2000 Servers Package</Excluded_Packages>
+                    <Excluded_Packages Name="$(BDSBIN)\bcbofficexp260.bpl">Embarcadero C++Builder Office XP Servers Package</Excluded_Packages>
+                    <Excluded_Packages Name="$(BDSBIN)\dcloffice2k260.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
+                    <Excluded_Packages Name="$(BDSBIN)\dclofficexp260.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
+                    <Excluded_Packages Name="C:\Users\Public\Documents\Embarcadero\Studio\20.0\Bpl\AdvChartDXE12.bpl">File C:\Users\Public\Documents\Embarcadero\Studio\20.0\Bpl\AdvChartDXE12.bpl not found</Excluded_Packages>
+                    <Excluded_Packages Name="C:\Users\Public\Documents\Embarcadero\Studio\20.0\Bpl\AdvChartDEDXE12.bpl">File C:\Users\Public\Documents\Embarcadero\Studio\20.0\Bpl\AdvChartDEDXE12.bpl not found</Excluded_Packages>
+                    <Excluded_Packages Name="C:\Users\Public\Documents\Embarcadero\Studio\20.0\Bpl\vcwDXE12.bpl">File C:\Users\Public\Documents\Embarcadero\Studio\20.0\Bpl\vcwDXE12.bpl not found</Excluded_Packages>
+                    <Excluded_Packages Name="C:\Users\Public\Documents\Embarcadero\Studio\20.0\Bpl\vcwdeDXE12.bpl">File C:\Users\Public\Documents\Embarcadero\Studio\20.0\Bpl\vcwdeDXE12.bpl not found</Excluded_Packages>
+                    <Excluded_Packages Name="C:\Users\Public\Documents\Embarcadero\Studio\20.0\Bpl\TMSFMXPackPkgDEDXE12.bpl">File C:\Users\Public\Documents\Embarcadero\Studio\20.0\Bpl\TMSFMXPackPkgDEDXE12.bpl not found</Excluded_Packages>
+                </Excluded_Packages>
+            </Delphi.Personality>
+            <Deployment Version="3">
+                <DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule">
+                    <Platform Name="OSX32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="bin\Win32\Debug\LinqList.exe" Configuration="Debug" Class="ProjectOutput">
+                    <Platform Name="Win32">
+                        <RemoteName>LinqList.exe</RemoteName>
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="$(BDS)\Redist\osx64\libcgsqlite3.dylib" Class="DependencyModule">
+                    <Platform Name="OSX64">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="$(BDS)\Redist\iossimulator\libPCRE.dylib" Class="DependencyModule">
+                    <Platform Name="iOSSimulator">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib" Class="DependencyModule">
+                    <Platform Name="iOSSimulator">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="$(BDS)\Redist\iossimulator\libpcre.dylib" Class="DependencyModule">
+                    <Platform Name="iOSSimulator">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="$(BDS)\Redist\osx32\libcgsqlite3.dylib" Class="DependencyModule">
+                    <Platform Name="OSX32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployClass Name="AdditionalDebugSymbols">
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidClassesDexFile">
+                    <Platform Name="Android">
+                        <RemoteDir>classes</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidFileProvider">
+                    <Platform Name="Android">
+                        <RemoteDir>res\xml</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidGDBServer">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeArmeabiFile">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeMipsFile">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\mips</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidServiceOutput">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashImageDef">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStyles">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStylesV21">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values-v21</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_DefaultAppIcon">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon144">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon36">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-ldpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon48">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon72">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon96">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage426">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-small</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage470">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-normal</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage640">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-large</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage960">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xlarge</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DebugSymbols">
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DependencyFramework">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.framework</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.framework</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DependencyModule">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                        <Extensions>.dll;.bpl</Extensions>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Required="true" Name="DependencyPackage">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                        <Extensions>.bpl</Extensions>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="File">
+                    <Platform Name="Android">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice32">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\Resources\StartUp\</RemoteDir>
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\Resources\StartUp\</RemoteDir>
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch1024">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch1536">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch2048">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch768">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch320">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch640">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch640x1136">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectAndroidManifest">
+                    <Platform Name="Android">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSDeviceDebug">
+                    <Platform Name="iOSDevice32">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSDeviceResourceRules">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSEntitlements">
+                    <Platform Name="iOSDevice32">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSInfoPList">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSResource">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXDebug">
+                    <Platform Name="OSX64">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXEntitlements">
+                    <Platform Name="OSX32">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXInfoPList">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXResource">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\Resources</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\Resources</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Required="true" Name="ProjectOutput">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Linux64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectUWPManifest">
+                    <Platform Name="Win32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="UWP_DelphiLogo150">
+                    <Platform Name="Win32">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="UWP_DelphiLogo44">
+                    <Platform Name="Win32">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
+            </Deployment>
+            <Platforms>
+                <Platform value="Android">False</Platform>
+                <Platform value="iOSDevice32">False</Platform>
+                <Platform value="iOSDevice64">False</Platform>
+                <Platform value="iOSSimulator">False</Platform>
+                <Platform value="OSX32">True</Platform>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">True</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+    <Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
+</Project>

BIN
samples/delphi/Quick.Linq/LinqLists/LinqList.res


+ 14 - 8
samples/delphi/QuickConfig/ConfigToYAML/Main.pas

@@ -21,10 +21,15 @@ type
 
   TMyPriority = (msLow, msMed, msHigh);
 
-  TWinPos = record
-  public
-    PosX : Integer;
-    PosY : Integer;
+  TWinPos = class
+  private
+    fPosX : Integer;
+    fPosY : Integer;
+    fFixed : Boolean;
+  published
+    property PosX : Integer read fPosX write fPosX;
+    property PosY : Integer read fPosY write fPosY;
+    property Fixed : Boolean read fFixed write fFixed;
   end;
 
   TProcessType = record
@@ -145,10 +150,10 @@ begin
   cConfig.LastFilename := 'library.txt';
   cConfig.Sizes := [23,11,554,12,34,29,77,30,48,59,773,221,98,3,22,983,122,231,433,12,31,987];
   cConfig.DefaultWorker.Levels := [10,12,14,18,20];
-  winpos.PosX := 640;
-  winpos.PosX := 480;
+  cConfig.WindowPos.PosX := 640;
+  cConfig.WindowPos.PosX := 480;
+  cConfig.WindowPos.Fixed := True;
   cConfig.Methods := ['GET','POST','PUT','DELETE','HEAD'];
-  cConfig.WindowPos := winpos;
   protype.Id := 5;
   protype.Priority := msHigh;
   protype.Redundant := False;
@@ -236,6 +241,7 @@ procedure TMyConfig.Init;
 begin
   inherited;
   fWorkList := TObjectList<TWorker>.Create(True);
+  fWindowPos := TWinPos.Create;
   fDefaultWorker := TWorker.Create;
   DefaultValues;
 end;
@@ -250,7 +256,7 @@ destructor TMyConfig.Destroy;
 begin
   if Assigned(fWorkList) then fWorkList.Free;
   if Assigned(fDefaultWorker) then fDefaultWorker.Free;
-
+  if Assigned(fWindowPos) then fWindowPos.Free;
   inherited;
 end;
 

+ 1 - 1
samples/fpc/QuickConfig/ConfigToYAML/lib/i386-win32/umain.lfm

@@ -1,5 +1,5 @@
 object Form1: TForm1
-  Left = 379
+  Left = -1541
   Height = 457
   Top = 208
   Width = 592

+ 60 - 0
samples/fpc/QuickLinq/LinqQuerySample.lpi

@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <MainUnitHasScaledStatement Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <MainUnit Value="0"/>
+      <Title Value="LinqQuerySample"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <BuildModes Count="1">
+      <Item1 Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+      <Modes Count="0"/>
+    </RunParams>
+    <Units Count="1">
+      <Unit0>
+        <Filename Value="LinqQuerySample.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit0>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <Target>
+      <Filename Value="LinqQuerySample"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <OtherUnitFiles Value="..\..\..\..\..\QuickLibs\QuickLib"/>
+      <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
+    </SearchPaths>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions Count="3">
+      <Item1>
+        <Name Value="EAbort"/>
+      </Item1>
+      <Item2>
+        <Name Value="ECodetoolError"/>
+      </Item2>
+      <Item3>
+        <Name Value="EFOpenError"/>
+      </Item3>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 178 - 0
samples/fpc/QuickLinq/LinqQuerySample.lpr

@@ -0,0 +1,178 @@
+program LinqQuerySample;
+
+{$mode delphi}
+
+uses
+  SysUtils,
+  Quick.Commons,
+  Quick.Console,
+  Quick.Chrono,
+  Quick.Arrays,
+  Quick.Linq,
+  Quick.Expression;
+
+const
+  numusers = 0;
+  UserNames : array[0..25] of string = ('Cliff','Alan','Anna','Phil','John','Michel','Jennifer','Peter','Brandon','Joe','Steve','Lorraine','Bill','Tom','Norma','Martin','Steffan','Wilma','Derek','Lewis','Paul',
+                                 'Erik','Robert','Nicolas','Frederik','Rose');
+  UserSurnames : array[0..25] of string = ('Gordon','Summer','Huan','Paterson','Johnson','Michelson','Smith','Peterson','Miller','McCarney','Roller','Gonzalez','Thomson','Muller','Jefferson','Volkov','Matheu','Morrison','Newman','Lover','Sunday',
+                                    'Roberts','Landon','Yuri','Paris','Levis');
+type
+  TLoginInfo = class
+  private
+    fUserName : string;
+    fUserPassword : string;
+    fLocked : Boolean;
+  published
+    property UserName : string read fUserName write fUserName;
+    property UserPassword : string read fUserPassword write fUserPassword;
+    property Locked : Boolean read fLocked write fLocked;
+  end;
+
+  { TUser }
+
+  TUser = class
+  private
+    fId : Int64;
+    fName : string;
+    fSurName : string;
+    fAge : Integer;
+    fLoginInfo : TLoginInfo;
+  public
+    constructor Create;
+    destructor Destroy; override;
+  published
+    property Id : Int64 read fId write fId;
+    property Name : string read fName write fName;
+    property SurName : string read fSurName write fSurName;
+    property Age : Integer read fAge write fAge;
+    property LoginInfo : TLoginInfo read fLoginInfo write fLoginInfo;
+  end;
+
+var
+  users : TXArray<TUser>;
+  user : TUser;
+  i : Integer;
+  n : Integer;
+  crono : TChronometer;
+
+{ TUser }
+
+constructor TUser.Create;
+begin
+  fLoginInfo := TLoginInfo.Create;
+end;
+
+destructor TUser.Destroy;
+begin
+  fLoginInfo.Free;
+  inherited Destroy;
+end;
+
+begin
+  try
+    cout('Generating list...',etInfo);
+    //generate first dummy entries
+    for i := 1 to numusers - high(UserNames) do
+    begin
+      user := TUser.Create;
+      user.Id := Random(999999999999999);
+      user.Name := 'Name' + i.ToString;
+      user.SurName := 'SurName' + i.ToString;
+      user.Age := 18 + Random(20);
+      users.Add(user);
+    end;
+
+    //generate real entries to search
+    for i := 0 to high(UserNames) do
+    begin
+      user := TUser.Create;
+      user.Id := Random(999999999999999);
+      user.Name := UserNames[i];
+      user.SurName := UserSurnames[i];
+      user.Age := 18 + Random(20);
+      user.LoginInfo.Username := UserNames[i];
+      user.LoginInfo.UserPassword := RandomPassword(8,[pfIncludeNumbers,pfIncludeSigns]);
+      user.LoginInfo.Locked := False;
+
+      users.Add(user);
+    end;
+
+    crono := TChronometer.Create;
+
+    //test search by normal iteration
+    user := nil;
+    crono.Start;
+    for i := 0 to users.Count - 1 do
+    begin
+      //if (users[i].Name = 'Anus') or (users[i].SurName = 'Smith') then
+      if users[i].Name = 'Peter' then
+      begin
+        crono.Stop;
+        user := users[i];
+        Break;
+      end;
+    end;
+    if user <> nil then cout('Found by Iteration: %s %s at %d position in %s',[user.Name,user.SurName,i,crono.ElapsedTime],etSuccess)
+      else cout('Not found by Iteration!',etError);
+
+
+    //test search by Linq iteration
+    crono.Start;
+    user := TLinq<TUser>.From(users).Where('(Name = ?) OR (SurName = ?)',['Anus','Smith']).OrderBy('Name').SelectFirst;
+    //user := TLinq<TUser>.From(users).Where('LoginInfo.UserName = ?',['Cliff']).SelectFirst;
+    crono.Stop;
+    if user <> nil then cout('Found by Linq: %s %s in %s',[user.Name,user.SurName,crono.ElapsedTime],etSuccess)
+      else cout('Not found by Linq! (%s)',[crono.ElapsedTime],etError);
+
+    //ConsoleWaitForEnterKey;
+    cout('Multi results:',etInfo);
+
+    //test search by normal iteration
+    user := nil;
+    n := 0;
+    cout('Found by Iteration:',etInfo);
+    for i := 0 to users.Count - 1 do
+    begin
+      //if ((users[i].Name = 'Anna') or (users[i].Age > 30)) or (users[i].SurName = 'Smith') then
+      //if users[i].Age > 18 then
+      if (users[i].Name = 'Anna') then
+      begin
+        Inc(n);
+        user := users[i];
+        cout('%d. %s %s',[n,user.Name,user.SurName],etSuccess)
+      end;
+    end;
+    if user = nil then cout('Not found by Iteration!',etError);
+
+    //test search by Linq iteration
+    user := nil;
+    n := 0;
+    cout('Found by Linq:',etInfo);
+    //TLinq.From<TUser>(users).Where('SurName Like ?',['p%']).Delete;
+
+    TLinq<TUser>.From(users).Where('Name = ?',['Peter']).Update(['Name'],['Poter']);
+
+    //for user in TLinq<TUser>.From(users).Where('(Name = ?) OR (SurName = ?) OR (SurName = ?)',['Peter','Smith','Huan']).Select do
+    //for user in TLinq<TUser>.From(users).Where('(Name = ?) OR (Age > ?) OR (SurName = ?)',['Anna',30,'Smith']).Select do
+    //for user in TLinq<TUser>.Fromusers).Where('Age > ?',[18]).Select do
+    //for user in TLinq<TUser>.From(users).Where('SurName Like ?',['%son']).Select do
+    //for user in TLinq<TUser>.From(users).Where('SurName Like ?',['p%']).Select do
+    //for user in TLinq<TUser>.From(users).Where('1 = 1',[]).Select do
+    for user in TLinq<TUser>.From(users).Where('(LoginInfo.UserName Like ?) OR (LoginInfo.UserName Like ?)',['p%','a%'])
+                                         .OrderBy('Name')
+                                         .Select do
+    begin
+      Inc(n);
+      cout('%d. %s %s',[n,user.Name,user.SurName],etSuccess);
+    end;
+    if user = nil then cout('Not found by Linq!',etError);
+
+    cout('Press a key to Exit',etInfo);
+    Readln;
+    crono.Free;
+  except
+    on E: Exception do
+      cout('%s : %s',[E.ClassName,E.Message],etError);
+  end;
+end.