Browse Source

Rewrite: key management GUI, added wizards for key import

Herman Schoenfeld 7 years ago
parent
commit
23583ed918
52 changed files with 3712 additions and 1933 deletions
  1. 127 89
      PascalCoinWallet.lpi
  2. BIN
      Resources/WalletImages/clipboard-24x24.png
  3. BIN
      Resources/WalletImages/lock-16x16.png
  4. BIN
      Resources/WalletImages/minus-16x16.png
  5. BIN
      Resources/WalletImages/plus-16x16.png
  6. BIN
      Resources/WalletImages/success-64x64.png
  7. BIN
      Resources/WalletImages/unlock-64x64.png
  8. BIN
      Resources/WalletImages/unlock-red-64x64.png
  9. 27 35
      Units/Forms/UFRMAbout.lfm
  10. 2 2
      Units/Forms/UFRMAbout.pas
  11. 19 19
      Units/Forms/UFRMAccountExplorer.pas
  12. 1 1
      Units/Forms/UFRMAccountSelect.lfm
  13. 1 1
      Units/Forms/UFRMAccountSelect.pas
  14. 3 3
      Units/Forms/UFRMMainForm.lfm
  15. 11 10
      Units/Forms/UFRMMainForm.pas
  16. 2 2
      Units/Forms/UFRMMessages.pas
  17. 0 96
      Units/Forms/UFRMNewPrivateKeyType.lfm
  18. 0 98
      Units/Forms/UFRMNewPrivateKeyType.pas
  19. 7 7
      Units/Forms/UFRMNodesIp.pas
  20. 2 4
      Units/Forms/UFRMOperation.pas
  21. 4 3
      Units/Forms/UFRMPascalCoinWalletConfig.lfm
  22. 82 109
      Units/Forms/UFRMPascalCoinWalletConfig.pas
  23. 45 65
      Units/Forms/UFRMPayloadDecoder.pas
  24. 1 1
      Units/Forms/UFRMPendingOperations.pas
  25. 1319 591
      Units/Forms/UFRMWalletKeys.lfm
  26. 351 415
      Units/Forms/UFRMWalletKeys.pas
  27. 0 35
      Units/Forms/UFRMWalletKeys2.pas
  28. 132 221
      Units/Forms/UUserInterface.pas
  29. 92 0
      Units/Forms/Wizards/UWIZAddKey.pas
  30. 28 0
      Units/Forms/Wizards/UWIZAddKey_EnterName.lfm
  31. 55 0
      Units/Forms/Wizards/UWIZAddKey_EnterName.pas
  32. 65 0
      Units/Forms/Wizards/UWIZAddKey_GenerateOrImport.lfm
  33. 49 0
      Units/Forms/Wizards/UWIZAddKey_GenerateOrImport.pas
  34. 51 0
      Units/Forms/Wizards/UWIZAddKey_ImportPrivKey.lfm
  35. 66 0
      Units/Forms/Wizards/UWIZAddKey_ImportPrivKey.pas
  36. 29 0
      Units/Forms/Wizards/UWIZAddKey_ImportPubKey.lfm
  37. 59 0
      Units/Forms/Wizards/UWIZAddKey_ImportPubKey.pas
  38. 33 0
      Units/Forms/Wizards/UWIZAddKey_SelectEncryption.lfm
  39. 62 0
      Units/Forms/Wizards/UWIZAddKey_SelectEncryption.pas
  40. 65 0
      Units/Forms/Wizards/UWIZAddKey_Start.lfm
  41. 55 0
      Units/Forms/Wizards/UWIZAddKey_Start.pas
  42. 0 23
      Units/PascalCoin/UConst.pas
  43. 43 17
      Units/PascalCoin/UCrypto.pas
  44. 1 1
      Units/PascalCoin/URPC.pas
  45. 1 1
      Units/PascalCoin/UServerApp.pas
  46. 339 0
      Units/PascalCoin/USettings.pas
  47. 350 4
      Units/PascalCoin/UWallet.pas
  48. 1 1
      Units/PascalCoin/upcdaemon.pas
  49. 6 6
      Units/Utils/UAutoScope.pas
  50. 1 1
      Units/Utils/UGridUtils.pas
  51. 2 2
      Units/Utils/UWizard.lfm
  52. 123 70
      Units/Utils/UWizard.pas

+ 127 - 89
PascalCoinWallet.lpi

@@ -38,7 +38,7 @@
         <PackageName Value="LCL"/>
       </Item1>
     </RequiredPackages>
-    <Units Count="69">
+    <Units Count="75">
       <Unit0>
         <Filename Value="PascalCoinWallet.dpr"/>
         <IsPartOfProject Value="True"/>
@@ -56,7 +56,7 @@
         <IsPartOfProject Value="True"/>
       </Unit3>
       <Unit4>
-        <Filename Value="Units\PascalCoin\UWalletKeys.pas"/>
+        <Filename Value="Units\PascalCoin\UWallet.pas"/>
         <IsPartOfProject Value="True"/>
       </Unit4>
       <Unit5>
@@ -125,259 +125,297 @@
         <ResourceBaseClass Value="Form"/>
       </Unit18>
       <Unit19>
-        <Filename Value="Units\Forms\UFRMWalletKeys.pas"/>
+        <Filename Value="Units\Forms\UFRMPayloadDecoder.pas"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="FRMWalletKeys"/>
+        <ComponentName Value="FRMPayloadDecoder"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
       </Unit19>
       <Unit20>
-        <Filename Value="Units\Forms\UFRMNewPrivateKeyType.pas"/>
+        <Filename Value="Units\Forms\UFRMNodesIp.pas"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="FRMNewPrivateKeyType"/>
+        <ComponentName Value="FRMNodesIp"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
       </Unit20>
       <Unit21>
-        <Filename Value="Units\Forms\UFRMPayloadDecoder.pas"/>
+        <Filename Value="Units\PascalCoin\UTCPIP.pas"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="FRMPayloadDecoder"/>
-        <HasResources Value="True"/>
-        <ResourceBaseClass Value="Form"/>
       </Unit21>
       <Unit22>
-        <Filename Value="Units\Forms\UFRMNodesIp.pas"/>
+        <Filename Value="Units\Utils\UJSONFunctions.pas"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="FRMNodesIp"/>
-        <HasResources Value="True"/>
-        <ResourceBaseClass Value="Form"/>
       </Unit22>
       <Unit23>
-        <Filename Value="Units\PascalCoin\UTCPIP.pas"/>
+        <Filename Value="Units\PascalCoin\URPC.pas"/>
         <IsPartOfProject Value="True"/>
       </Unit23>
       <Unit24>
-        <Filename Value="Units\Utils\UJSONFunctions.pas"/>
+        <Filename Value="Units\PascalCoin\UPoolMining.pas"/>
         <IsPartOfProject Value="True"/>
       </Unit24>
       <Unit25>
-        <Filename Value="Units\PascalCoin\URPC.pas"/>
+        <Filename Value="Units\PascalCoin\UOpenSSL.pas"/>
         <IsPartOfProject Value="True"/>
       </Unit25>
       <Unit26>
-        <Filename Value="Units\PascalCoin\UPoolMining.pas"/>
+        <Filename Value="Units\PascalCoin\UOpenSSLdef.pas"/>
         <IsPartOfProject Value="True"/>
       </Unit26>
       <Unit27>
-        <Filename Value="Units\PascalCoin\UOpenSSL.pas"/>
+        <Filename Value="Units\PascalCoin\UFileStorage.pas"/>
         <IsPartOfProject Value="True"/>
       </Unit27>
       <Unit28>
-        <Filename Value="Units\PascalCoin\UOpenSSLdef.pas"/>
+        <Filename Value="Units\PascalCoin\config.inc"/>
         <IsPartOfProject Value="True"/>
       </Unit28>
       <Unit29>
-        <Filename Value="Units\PascalCoin\UFileStorage.pas"/>
+        <Filename Value="Units\PascalCoin\UAES.pas"/>
         <IsPartOfProject Value="True"/>
       </Unit29>
       <Unit30>
-        <Filename Value="Units\PascalCoin\config.inc"/>
+        <Filename Value="Units\PascalCoin\UChunk.pas"/>
         <IsPartOfProject Value="True"/>
       </Unit30>
       <Unit31>
-        <Filename Value="Units\PascalCoin\UAES.pas"/>
-        <IsPartOfProject Value="True"/>
-      </Unit31>
-      <Unit32>
-        <Filename Value="Units\PascalCoin\UChunk.pas"/>
-        <IsPartOfProject Value="True"/>
-      </Unit32>
-      <Unit33>
         <Filename Value="Units\Forms\UFRMAccountSelect.pas"/>
         <IsPartOfProject Value="True"/>
         <ComponentName Value="FRMAccountSelect"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
-      </Unit33>
-      <Unit34>
+      </Unit31>
+      <Unit32>
         <Filename Value="Units\PascalCoin\UBaseTypes.pas"/>
         <IsPartOfProject Value="True"/>
-      </Unit34>
-      <Unit35>
+      </Unit32>
+      <Unit33>
         <Filename Value="Units\Utils\UWizard.pas"/>
         <IsPartOfProject Value="True"/>
         <ComponentName Value="WizardHostForm"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
-      </Unit35>
-      <Unit36>
+      </Unit33>
+      <Unit34>
         <Filename Value="Units\Utils\generics.collections.pas"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="Generics.Collections"/>
-      </Unit36>
-      <Unit37>
+      </Unit34>
+      <Unit35>
         <Filename Value="Units\Utils\generics.defaults.pas"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="Generics.Defaults"/>
-      </Unit37>
-      <Unit38>
+      </Unit35>
+      <Unit36>
         <Filename Value="Units\Utils\generics.hashes.pas"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="Generics.Hashes"/>
-      </Unit38>
-      <Unit39>
+      </Unit36>
+      <Unit37>
         <Filename Value="Units\Utils\generics.helpers.pas"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="Generics.Helpers"/>
-      </Unit39>
-      <Unit40>
+      </Unit37>
+      <Unit38>
         <Filename Value="Units\Utils\generics.memoryexpanders.pas"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="Generics.MemoryExpanders"/>
-      </Unit40>
-      <Unit41>
+      </Unit38>
+      <Unit39>
         <Filename Value="Units\Utils\generics.strings.pas"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="Generics.Strings"/>
-      </Unit41>
-      <Unit42>
+      </Unit39>
+      <Unit40>
         <Filename Value="Units\Forms\UFRMMessages.pas"/>
         <IsPartOfProject Value="True"/>
         <ComponentName Value="FRMMessages"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
-      </Unit42>
-      <Unit43>
+      </Unit40>
+      <Unit41>
         <Filename Value="Units\Forms\UFRMNodes.pas"/>
         <IsPartOfProject Value="True"/>
         <ComponentName Value="FRMNodes"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
-      </Unit43>
-      <Unit44>
+      </Unit41>
+      <Unit42>
         <Filename Value="Units\Forms\UFRMLogs.pas"/>
         <IsPartOfProject Value="True"/>
         <ComponentName Value="FRMLogs"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
-      </Unit44>
-      <Unit45>
+      </Unit42>
+      <Unit43>
         <Filename Value="Units\Forms\UFRMOperationExplorer.pas"/>
         <IsPartOfProject Value="True"/>
         <ComponentName Value="FRMOperationExplorer"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
-      </Unit45>
-      <Unit46>
+      </Unit43>
+      <Unit44>
         <Filename Value="Units\Forms\UFRMBlockExplorer.pas"/>
         <IsPartOfProject Value="True"/>
         <ComponentName Value="FRMBlockExplorer"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
-      </Unit46>
-      <Unit47>
+      </Unit44>
+      <Unit45>
         <Filename Value="Units\Forms\UFRMPendingOperations.pas"/>
         <IsPartOfProject Value="True"/>
         <ComponentName Value="FRMPendingOperations"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
-      </Unit47>
-      <Unit48>
+      </Unit45>
+      <Unit46>
         <Filename Value="Units\Forms\UFRMAccountExplorer.pas"/>
         <IsPartOfProject Value="True"/>
         <ComponentName Value="FRMAccountExplorer"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
+      </Unit46>
+      <Unit47>
+        <Filename Value="Units\Forms\UUserInterface.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit47>
+      <Unit48>
+        <Filename Value="Units\Utils\UCommonUI.pas"/>
+        <IsPartOfProject Value="True"/>
       </Unit48>
       <Unit49>
-        <Filename Value="Units\Forms\UUserInterface.pas"/>
+        <Filename Value="Units\Utils\UCommon.pas"/>
         <IsPartOfProject Value="True"/>
       </Unit49>
       <Unit50>
-        <Filename Value="Units\Utils\UCommonUI.pas"/>
+        <Filename Value="Units\PascalCoin\UGPUMining.pas"/>
         <IsPartOfProject Value="True"/>
       </Unit50>
       <Unit51>
-        <Filename Value="Units\Utils\UCommon.pas"/>
+        <Filename Value="Units\PascalCoin\upcdaemon.pas"/>
         <IsPartOfProject Value="True"/>
       </Unit51>
       <Unit52>
-        <Filename Value="Units\PascalCoin\UGPUMining.pas"/>
+        <Filename Value="Units\PascalCoin\UPoolMinerThreads.pas"/>
         <IsPartOfProject Value="True"/>
       </Unit52>
       <Unit53>
-        <Filename Value="Units\PascalCoin\upcdaemon.pas"/>
+        <Filename Value="Units\PascalCoin\UServerApp.pas"/>
         <IsPartOfProject Value="True"/>
       </Unit53>
       <Unit54>
-        <Filename Value="Units\PascalCoin\UPoolMinerThreads.pas"/>
+        <Filename Value="Units\PascalCoin\USha256.pas"/>
         <IsPartOfProject Value="True"/>
       </Unit54>
       <Unit55>
-        <Filename Value="Units\PascalCoin\UServerApp.pas"/>
+        <Filename Value="Units\Utils\generics.dictionaries.inc"/>
         <IsPartOfProject Value="True"/>
       </Unit55>
       <Unit56>
-        <Filename Value="Units\PascalCoin\USha256.pas"/>
+        <Filename Value="Units\Utils\generics.dictionariesh.inc"/>
         <IsPartOfProject Value="True"/>
       </Unit56>
       <Unit57>
-        <Filename Value="Units\Utils\generics.dictionaries.inc"/>
+        <Filename Value="Units\Forms\UFRMAccountInfo.pas"/>
         <IsPartOfProject Value="True"/>
+        <HasResources Value="True"/>
       </Unit57>
       <Unit58>
-        <Filename Value="Units\Utils\generics.dictionariesh.inc"/>
+        <Filename Value="Units\Forms\UFRMMemoText.pas"/>
         <IsPartOfProject Value="True"/>
+        <HasResources Value="True"/>
       </Unit58>
       <Unit59>
-        <Filename Value="Units\Forms\UFRMAccountInfo.pas"/>
+        <Filename Value="Units\Forms\UFRMSaleAccounts.pas"/>
         <IsPartOfProject Value="True"/>
-        <HasResources Value="True"/>
       </Unit59>
       <Unit60>
-        <Filename Value="Units\Forms\UFRMMemoText.pas"/>
+        <Filename Value="Units\Forms\UCTRLBanner.pas"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="CTRLBanner"/>
         <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit60>
       <Unit61>
-        <Filename Value="Units\Forms\UFRMSaleAccounts.pas"/>
+        <Filename Value="Units\Forms\UFRMMainForm.pas"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="FRMMainForm"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit61>
       <Unit62>
-        <Filename Value="Units\Forms\UFRMWalletKeys2.pas"/>
+        <Filename Value="Units\Forms\UFRMSyncronizationForm.pas"/>
         <IsPartOfProject Value="True"/>
+        <HasResources Value="True"/>
       </Unit62>
       <Unit63>
-        <Filename Value="Units\Forms\UCTRLBanner.pas"/>
+        <Filename Value="Units\Utils\UAutoScope.pas"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="CTRLBanner"/>
-        <HasResources Value="True"/>
-        <ResourceBaseClass Value="Form"/>
       </Unit63>
       <Unit64>
-        <Filename Value="Units\Forms\UFRMMainForm.pas"/>
+        <Filename Value="Units\Utils\UVisualGrid.inc"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="FRMMainForm"/>
-        <HasResources Value="True"/>
-        <ResourceBaseClass Value="Form"/>
       </Unit64>
       <Unit65>
-        <Filename Value="Units\Forms\UFRMSyncronizationForm.pas"/>
+        <Filename Value="Units\Utils\UVisualGrid.pas"/>
         <IsPartOfProject Value="True"/>
-        <HasResources Value="True"/>
       </Unit65>
       <Unit66>
-        <Filename Value="Units\Utils\UAutoScope.pas"/>
+        <Filename Value="Units\Forms\Wizards\UWIZAddKey_Start.pas"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZAddKey_Start"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit66>
       <Unit67>
-        <Filename Value="Units\Utils\UVisualGrid.inc"/>
+        <Filename Value="Units\Forms\Wizards\UWIZAddKey_GenerateOrImport.pas"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZAddKey_GenerateOrImport"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit67>
       <Unit68>
-        <Filename Value="Units\Utils\UVisualGrid.pas"/>
+        <Filename Value="Units\Forms\Wizards\UWIZAddKey_ImportPubKey.pas"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZAddKey_ImportPubKey"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit68>
+      <Unit69>
+        <Filename Value="Units\Forms\Wizards\UWIZAddKey_ImportPrivKey.pas"/>
+        <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZAddKey_ImportPrivKey"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
+      </Unit69>
+      <Unit70>
+        <Filename Value="Units\Forms\Wizards\UWIZAddKey_EnterName.pas"/>
+        <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZAddKey_EnterName"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
+      </Unit70>
+      <Unit71>
+        <Filename Value="Units\Forms\UFRMWalletKeys.pas"/>
+        <IsPartOfProject Value="True"/>
+        <ComponentName Value="FRMWalletKeys"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
+      </Unit71>
+      <Unit72>
+        <Filename Value="Units\Forms\Wizards\UWIZAddKey.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit72>
+      <Unit73>
+        <Filename Value="Units\PascalCoin\USettings.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit73>
+      <Unit74>
+        <Filename Value="Units\Forms\Wizards\UWIZAddKey_SelectEncryption.pas"/>
+        <IsPartOfProject Value="True"/>
+        <ComponentName Value="WIZAddKey_SelectEncryption"/>
+        <ResourceBaseClass Value="Form"/>
+      </Unit74>
     </Units>
   </ProjectOptions>
   <CompilerOptions>
@@ -388,7 +426,7 @@
     </Target>
     <SearchPaths>
       <IncludeFiles Value="$(ProjOutDir);Units\PascalCoin;Units\Utils"/>
-      <OtherUnitFiles Value="Synapse\lib;Units\Forms;Units\PascalCoin;Units\Utils;Units\SQLite3"/>
+      <OtherUnitFiles Value="Synapse\lib;Units\Forms;Units\PascalCoin;Units\Utils;Units\SQLite3;Units\Forms\Wizards"/>
       <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
     </SearchPaths>
     <Parsing>

BIN
Resources/WalletImages/clipboard-24x24.png


BIN
Resources/WalletImages/lock-16x16.png


BIN
Resources/WalletImages/minus-16x16.png


BIN
Resources/WalletImages/plus-16x16.png


BIN
Resources/WalletImages/success-64x64.png


BIN
Resources/WalletImages/unlock-64x64.png


BIN
Resources/WalletImages/unlock-red-64x64.png


+ 27 - 35
Units/Forms/UFRMAbout.lfm

@@ -1,7 +1,7 @@
 object FRMAbout: TFRMAbout
-  Left = 764
+  Left = -3141
   Height = 405
-  Top = 516
+  Top = 507
   Width = 585
   ActiveControl = bbClose
   BorderIcons = [biSystemMenu]
@@ -194,19 +194,6 @@ object FRMAbout: TFRMAbout
     Caption = 'Source Code:'
     ParentColor = False
   end
-  object Label3: TLabel
-    Left = 90
-    Height = 13
-    Top = 339
-    Width = 135
-    Caption = 'Check For New Versions:'
-    Font.Color = clWindowText
-    Font.Height = -11
-    Font.Name = 'Tahoma'
-    Font.Style = [fsBold]
-    ParentColor = False
-    ParentFont = False
-  end
   object Label4: TLabel
     Cursor = crHandPoint
     Left = 170
@@ -222,29 +209,14 @@ object FRMAbout: TFRMAbout
     ParentFont = False
     OnClick = Label4Click
   end
-  object Label5: TLabel
-    Cursor = crHandPoint
-    Left = 237
-    Height = 13
-    Top = 339
-    Width = 253
-    Caption = 'https://sourceforge.net/projects/pascalcoin'
-    Font.Color = clBlue
-    Font.Height = -11
-    Font.Name = 'Tahoma'
-    Font.Style = [fsBold]
-    ParentColor = False
-    ParentFont = False
-    OnClick = Label5Click
-  end
   object Memo1: TMemo
     Left = 90
-    Height = 266
+    Height = 250
     Top = 46
     Width = 478
     BorderStyle = bsNone
     Lines.Strings = (
-      'Copyright (c) 2016 - 2017 Albert Molina'
+      'Copyright (c) 2018 PascalCoin Project'
       ''
       'Pascal Coin is P2P cryptocurrency without the need for historical operations. This software '
       'comprises a node within the Pascal Coin network and can be used to Mine and Explore blocks and '
@@ -261,9 +233,6 @@ object FRMAbout: TFRMAbout
       'Gebauer.'
       'Original source code is written in Pascal Language and is available at '
       'https://github.com/PascalCoin/PascalCoin'
-      ''
-      'If you like it, consider a donation using BitCoin:'
-      '16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk'
     )
     ParentColor = True
     ReadOnly = True
@@ -281,4 +250,27 @@ object FRMAbout: TFRMAbout
     ModalResult = 1
     TabOrder = 1
   end
+  object Label6: TLabel
+    Left = 112
+    Height = 13
+    Top = 296
+    Width = 43
+    Caption = 'Website:'
+    ParentColor = False
+  end
+  object Label7: TLabel
+    Cursor = crHandPoint
+    Left = 170
+    Height = 13
+    Top = 296
+    Width = 150
+    Caption = 'http://www.pascalcoin.org'
+    Font.Color = clBlue
+    Font.Height = -11
+    Font.Name = 'Tahoma'
+    Font.Style = [fsBold]
+    ParentColor = False
+    ParentFont = False
+    OnClick = Label4Click
+  end
 end

+ 2 - 2
Units/Forms/UFRMAbout.pas

@@ -31,14 +31,14 @@ type
   TFRMAbout = class(TApplicationForm)
     Image1: TImage;
     Label1: TLabel;
+    Label6: TLabel;
+    Label7: TLabel;
     Memo1: TMemo;
     bbClose: TBitBtn;
     lblBuild: TLabel;
     lblProtocolVersion: TLabel;
     Label2: TLabel;
-    Label3: TLabel;
     Label4: TLabel;
-    Label5: TLabel;
     procedure FormCreate(Sender: TObject);
     procedure Label4Click(Sender: TObject);
     procedure Label5Click(Sender: TObject);

+ 19 - 19
Units/Forms/UFRMAccountExplorer.pas

@@ -203,8 +203,8 @@ implementation
 
 {$R *.lfm}
 
-uses UFRMAccountSelect, UConst, UFRMOperation,
-     UWalletKeys, UCrypto, UFRMMemoText, UUserInterface, UCommon;
+uses UFRMAccountSelect, UConst, USettings, UFRMOperation,
+     UWallet, UCrypto, UFRMMemoText, UUserInterface, UCommon;
 
 { TFRMAccountExplorer }
 
@@ -233,14 +233,14 @@ begin
   FOrderedAccountsKeyList := TOrderedAccountKeysList.Create(TUserInterface.Node.Bank.SafeBox,false);
 
   // Subscribe to wallet events
-  TUserInterface.WalletKeys.OnChanged.Add(OnPrivateKeysChanged);
+  TWallet.Keys.OnChanged.Add(OnPrivateKeysChanged);
   Refresh;
 end;
 
 procedure TFRMAccountExplorer.FormDestroy(Sender: TObject);
 begin
   // Unsubscribe from wallet events
-  TUserInterface.WalletKeys.OnChanged.Remove(OnPrivateKeysChanged);
+  TWallet.Keys.OnChanged.Remove(OnPrivateKeysChanged);
 
   // Nullify fields
   FAccountOperationsGrid.Node := Nil;
@@ -351,8 +351,8 @@ begin
         if cbMyPrivateKeys.ItemIndex<0 then exit;
         if cbMyPrivateKeys.ItemIndex=0 then begin
           // All keys in the wallet
-          for i := 0 to TUserInterface.WalletKeys.Count - 1 do begin
-            j := FOrderedAccountsKeyList.IndexOfAccountKey(TUserInterface.WalletKeys[i].AccountKey);
+          for i := 0 to TWallet.Keys.Count - 1 do begin
+            j := FOrderedAccountsKeyList.IndexOfAccountKey(TWallet.Keys[i].AccountKey);
             if (j>=0) then begin
               l := FOrderedAccountsKeyList.AccountKeyList[j];
               for k := 0 to l.Count - 1 do begin
@@ -365,8 +365,8 @@ begin
           end;
         end else begin
           i := PtrInt(cbMyPrivateKeys.Items.Objects[cbMyPrivateKeys.ItemIndex]);
-          if (i>=0) And (i<TUserInterface.WalletKeys.Count) then begin
-            j := FOrderedAccountsKeyList.IndexOfAccountKey(TUserInterface.WalletKeys[i].AccountKey);
+          if (i>=0) And (i<TWallet.Keys.Count) then begin
+            j := FOrderedAccountsKeyList.IndexOfAccountKey(TWallet.Keys[i].AccountKey);
             if (j>=0) then begin
               l := FOrderedAccountsKeyList.AccountKeyList[j];
               for k := 0 to l.Count - 1 do begin
@@ -411,8 +411,8 @@ begin
   cbMyPrivateKeys.items.BeginUpdate;
   Try
     cbMyPrivateKeys.Items.Clear;
-    For i:=0 to TUserInterface.WalletKeys.Count-1 do begin
-      wk := TUserInterface.WalletKeys.Key[i];
+    For i:=0 to TWallet.Keys.Count-1 do begin
+      wk := TWallet.Keys.Key[i];
       if assigned(FOrderedAccountsKeyList) then begin
         FOrderedAccountsKeyList.AddAccountKey(wk.AccountKey);
       end;
@@ -512,10 +512,10 @@ var i : Integer;
 begin
   if (cbMyPrivateKeys.ItemIndex<0) then  exit;
   i := PtrInt(cbMyPrivateKeys.Items.Objects[cbMyPrivateKeys.ItemIndex]);
-  if (i<0) Or (i>=TUserInterface.WalletKeys.Count) then raise Exception.Create('Must select a Key');
-  name := TUserInterface.WalletKeys.Key[i].Name;
+  if (i<0) Or (i>=TWallet.Keys.Count) then raise Exception.Create('Must select a Key');
+  name := TWallet.Keys.Key[i].Name;
   if InputQuery('Change Key name','Input new name',nameString) then begin
-    TUserInterface.WalletKeys.SetName(i,name);
+    TWallet.Keys.SetName(i,name);
   end;
 end;
 
@@ -535,7 +535,7 @@ begin
     ltarget := FAccountsSelectedGrid.LockAccountsList;
     Try
       for i := 0 to lsource.Count-1 do begin
-        if TUserInterface.WalletKeys.IndexOfAccountKey(TUserInterface.Node.Bank.SafeBox.Account(lsource.Get(i)).accountInfo.accountKey)<0 then raise Exception.Create(Format('You cannot operate with account %d because private key not found in your wallet',[lsource.Get(i)]));
+        if TWallet.Keys.IndexOfAccountKey(TUserInterface.Node.Bank.SafeBox.Account(lsource.Get(i)).accountInfo.accountKey)<0 then raise Exception.Create(Format('You cannot operate with account %d because private key not found in your wallet',[lsource.Get(i)]));
         ltarget.Add(lsource.Get(i));
       end;
     Finally
@@ -555,7 +555,7 @@ Var l, selected : TOrderedCardinalList;
 begin
   an := FAccountsGrid.AccountNumber(dgAccounts.Row);
   if (an<0) then raise Exception.Create('No account selected');
-  if TUserInterface.WalletKeys.IndexOfAccountKey(TUserInterface.Node.Bank.SafeBox.Account(an).accountInfo.accountkey)<0 then
+  if TWallet.Keys.IndexOfAccountKey(TUserInterface.Node.Bank.SafeBox.Account(an).accountInfo.accountkey)<0 then
     raise Exception.Create(Format('You cannot add %s account because private key not found in your wallet.'#10+#10+'You''re not the owner!',
       [TAccountComp.AccountNumberToAccountTxtNumber(an)]));
   // Add
@@ -609,8 +609,8 @@ begin
     finally
       FAccountsSelectedGrid.UnlockAccountsList;
     end;
-    DefaultFee := TUserInterface.AppParams.ParamByName[CT_PARAM_DefaultFee].GetAsInt64(0);
-    WalletKeys := TUserInterface.WalletKeys;
+    DefaultFee := TSettings.DefaultFee;
+    WalletKeys := TWallet.Keys;
     ShowModal;
   Finally
     Free;
@@ -623,7 +623,7 @@ begin
   F := TFRMAccountSelect.Create(Self);
   try
     F.Node := TUserInterface.Node;
-    F.WalletKeys := TUserInterface.WalletKeys;
+    F.WalletKeys := TWallet.Keys;
     F.ShowModal;
   finally
     F.Free;
@@ -701,7 +701,7 @@ begin
     If FAccountsGrid.SelectedAccounts(targetAccounts) = 0
       then raise Exception.Create('No row selected');
 
-    TUserInterface.ShowNewOperationDialog(Self, targetAccounts, TUserInterface.AppParams.ParamByName[CT_PARAM_DefaultFee].GetAsInt64(0));
+    TUserInterface.ShowNewOperationDialog(Self, targetAccounts, TSettings.DefaultFee);
   finally
      targetAccounts.Free;
   end;

+ 1 - 1
Units/Forms/UFRMAccountSelect.lfm

@@ -14,7 +14,7 @@ object FRMAccountSelect: TFRMAccountSelect
   OnCreate = FormCreate
   OnDestroy = FormDestroy
   Position = poOwnerFormCenter
-  LCLVersion = '1.6.0.4'
+  LCLVersion = '1.6.4.0'
   object pnlAccountsTop: TPanel
     Left = 395
     Height = 282

+ 1 - 1
Units/Forms/UFRMAccountSelect.pas

@@ -23,7 +23,7 @@ uses
   LCLIntf, LCLType, LMessages,
   Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
   Dialogs, UAccounts, Grids, StdCtrls, Buttons, ExtCtrls, UCommonUI,
-  UWalletKeys, UNode, UGridUtils, UConst, UThread;
+  UWallet, UNode, UGridUtils, UConst, UThread;
 
 const
   CT_AS_MyAccounts = $0001;

+ 3 - 3
Units/Forms/UFRMMainForm.lfm

@@ -1,7 +1,7 @@
 object FRMMainForm: TFRMMainForm
-  Left = 125
+  Left = 52
   Height = 600
-  Top = 58
+  Top = 55
   Width = 865
   Caption = 'Pascal Coin Wallet, JSON-RPC Miner & Explorer'
   ClientHeight = 580
@@ -19,7 +19,7 @@ object FRMMainForm: TFRMMainForm
   OnCreate = FormCreate
   OnDestroy = FormDestroy
   OnResize = FormResize
-  Position = poOwnerFormCenter
+  Position = poDefault
   ShowHint = True
   LCLVersion = '1.6.4.0'
   object paLogoPanel: TPanel

+ 11 - 10
Units/Forms/UFRMMainForm.pas

@@ -17,7 +17,7 @@ interface
 
 uses
   Messages, SysUtils, Classes, Graphics, Controls, Forms,
-  Dialogs, ExtCtrls, ComCtrls, UWalletKeys,
+  Dialogs, ExtCtrls, ComCtrls, UWallet,
   ULog,
   UBlockChain, UNode, UGridUtils, UAccounts, Menus,
   UNetProtocol, UCrypto, Buttons, ActnList, UPoolMining,
@@ -141,7 +141,8 @@ end;
 
 procedure TFRMMainForm.FormCloseQuery(Sender: TObject; var CanClose: boolean);
 begin
-  case TUserInterface.AskQuestion(Self, 'Quit PascalCoin', 'Are you sure you want to quit? Select ''No'' to run in background.', [mbCancel, mbNo, mbYes]) of
+  case TUserInterface.AskQuestion(Self, mtConfirmation, 'Quit PascalCoin',
+  'Are you sure you want to quit? Select ''No'' to run in background.', [mbCancel, mbNo, mbYes]) of
     mbYes: begin
       CanClose := false;
       PostMessage(Self.Handle, CM_PC_Terminate, 0, 0);
@@ -165,7 +166,7 @@ end;
 
 procedure TFRMMainForm.ActivateFirstTime;
 begin
-  TUserInterface.WalletKeys.OnChanged.Add(OnWalletChanged);
+  TWallet.Keys.OnChanged.Add(OnWalletChanged);
   TNetData.NetData.OnConnectivityChanged.Add(OnConnectivityChanged);
   RefreshWalletLockIcon;
   RefreshConnectivityIcon;
@@ -173,7 +174,7 @@ end;
 
 procedure TFRMMainForm.FormDestroy(Sender: TObject);
 begin
-  TUserInterface.WalletKeys.OnChanged.Remove(OnWalletChanged);
+  TWallet.Keys.OnChanged.Remove(OnWalletChanged);
   TNetData.NetData.OnConnectivityChanged.Remove(OnConnectivityChanged);
 end;
 
@@ -188,12 +189,12 @@ end;
 
 procedure TFRMMainForm.RefreshWalletLockIcon;
 begin
-  if NOT TUserInterface.WalletKeys.HasPassword then begin
+  if NOT TWallet.Keys.HasPassword then begin
     { No password has been set }
     tbtnWalletLock.Enabled := false;
     tbtnWalletLock.ImageIndex := 3;
     tbtnWalletLock.Hint := 'Your wallet does not have a password.';
-  end else if TUserInterface.WalletKeys.IsValidPassword then begin
+  end else if TWallet.Keys.IsValidPassword then begin
     { Password has been input, allow user to lock }
     tbtnWalletLock.Enabled := true;
     tbtnWalletLock.ImageIndex := 3;
@@ -360,15 +361,15 @@ end;
 
 procedure TFRMMainForm.tbtnWalletLockClick(Sender:TObject);
 begin
-  if NOT TUserInterface.WalletKeys.HasPassword then begin
+  if NOT TWallet.Keys.HasPassword then begin
      { no password has been set }
      ShowMessage('Your wallet has no password and is unsafe. Please set a password using ''Key Manager'' in Wallet menu.');
-   end else if TUserInterface.WalletKeys.IsValidPassword then begin
+   end else if TWallet.Keys.IsValidPassword then begin
      { wallet is unlocked, lock it }
-     TUserInterface.WalletKeys.LockWallet;
+     TWallet.Keys.LockWallet;
    end else begin
      { wallet is locked, try to unlock it}
-     TUserInterface.UnlockWallet(Self, TUserInterface.WalletKeys);
+     TUserInterface.UnlockWallet(Self);
    end;
 end;
 

+ 2 - 2
Units/Forms/UFRMMessages.pas

@@ -48,7 +48,7 @@ type
 
 implementation
 
-uses UUserInterface;
+uses UUserInterface, USettings;
 
 {$R *.lfm}
 
@@ -69,7 +69,7 @@ begin
     s := DateTimeToStr(now)+' Message received from '+NetConnection.ClientRemoteAddr;
     memoMessages.Lines.Add(DateTimeToStr(now)+' Message received from '+NetConnection.ClientRemoteAddr+' Length '+inttostr(Length(MessageData))+' bytes');
     memoMessages.Lines.Add('RECEIVED> '+MessageData);
-    if TUserInterface.AppParams.ParamByName[CT_PARAM_ShowModalMessages].GetAsBoolean(false) then begin
+    if TSettings.ShowModalMessages then begin
       s := DateTimeToStr(now)+' Message from '+NetConnection.ClientRemoteAddr+#10+
          'Length '+inttostr(length(MessageData))+' bytes'+#10+#10;
       if TCrypto.IsHumanReadable(MessageData) then begin

+ 0 - 96
Units/Forms/UFRMNewPrivateKeyType.lfm

@@ -1,96 +0,0 @@
-object FRMNewPrivateKeyType: TFRMNewPrivateKeyType
-  Left = 763
-  Height = 229
-  Top = 434
-  Width = 311
-  BorderIcons = [biSystemMenu]
-  BorderStyle = bsDialog
-  Caption = 'New Private Key'
-  ClientHeight = 229
-  ClientWidth = 311
-  Color = clBtnFace
-  Font.Color = clWindowText
-  Font.Height = -11
-  Font.Name = 'Tahoma'
-  OnCreate = FormCreate
-  OnDestroy = FormDestroy
-  Position = poOwnerFormCenter
-  LCLVersion = '1.6.0.4'
-  object Label1: TLabel
-    Left = 30
-    Height = 13
-    Top = 25
-    Width = 27
-    Caption = 'Name'
-    ParentColor = False
-  end
-  object ebName: TEdit
-    Left = 70
-    Height = 21
-    Top = 22
-    Width = 206
-    TabOrder = 0
-    Text = 'ebName'
-  end
-  object rgKeyType: TRadioGroup
-    Left = 30
-    Height = 105
-    Top = 60
-    Width = 246
-    AutoFill = True
-    Caption = ' Key Type: '
-    ChildSizing.LeftRightSpacing = 6
-    ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
-    ChildSizing.EnlargeVertical = crsHomogenousChildResize
-    ChildSizing.ShrinkHorizontal = crsScaleChilds
-    ChildSizing.ShrinkVertical = crsScaleChilds
-    ChildSizing.Layout = cclLeftToRightThenTopToBottom
-    ChildSizing.ControlsPerLine = 1
-    ClientHeight = 87
-    ClientWidth = 242
-    Items.Strings = (
-      'asdf'
-    )
-    TabOrder = 1
-  end
-  object bbOk: TBitBtn
-    Left = 112
-    Height = 25
-    Top = 181
-    Width = 75
-    Caption = 'OK'
-    Default = True
-    Glyph.Data = {
-      DE010000424DDE01000000000000760000002800000024000000120000000100
-      0400000000006801000000000000000000001000000000000000000000000000
-      80000080000000808000800000008000800080800000C0C0C000808080000000
-      FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00333333333333
-      3333333333333333333333330000333333333333333333333333F33333333333
-      00003333344333333333333333388F3333333333000033334224333333333333
-      338338F3333333330000333422224333333333333833338F3333333300003342
-      222224333333333383333338F3333333000034222A22224333333338F338F333
-      8F33333300003222A3A2224333333338F3838F338F33333300003A2A333A2224
-      33333338F83338F338F33333000033A33333A222433333338333338F338F3333
-      0000333333333A222433333333333338F338F33300003333333333A222433333
-      333333338F338F33000033333333333A222433333333333338F338F300003333
-      33333333A222433333333333338F338F00003333333333333A22433333333333
-      3338F38F000033333333333333A223333333333333338F830000333333333333
-      333A333333333333333338330000333333333333333333333333333333333333
-      0000
-    }
-    NumGlyphs = 2
-    OnClick = bbOkClick
-    TabOrder = 2
-  end
-  object bbCancel: TBitBtn
-    Left = 201
-    Height = 25
-    Top = 181
-    Width = 75
-    Cancel = True
-    Caption = 'Cancel'
-    Kind = bkCancel
-    ModalResult = 2
-    TabOrder = 3
-  end
-end

+ 0 - 98
Units/Forms/UFRMNewPrivateKeyType.pas

@@ -1,98 +0,0 @@
-unit UFRMNewPrivateKeyType;
-
-{$MODE Delphi}
-
-{ Copyright (c) 2016 by Albert Molina
-
-  Distributed under the MIT software license, see the accompanying file LICENSE
-  or visit http://www.opensource.org/licenses/mit-license.php.
-
-  This unit is a part of Pascal Coin, a P2P crypto currency without need of
-  historical operations.
-
-  If you like it, consider a donation using BitCoin:
-  16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk
-
-  }
-
-interface
-
-{$I ./../PascalCoin/config.inc}
-
-uses
-  LCLIntf, LCLType, LMessages,
-  Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
-  Dialogs, StdCtrls, Buttons, ExtCtrls, UCommonUI, UWalletKeys,UCrypto;
-
-type
-  TFRMNewPrivateKeyType = class(TApplicationForm)
-    Label1: TLabel;
-    ebName: TEdit;
-    rgKeyType: TRadioGroup;
-    bbOk: TBitBtn;
-    bbCancel: TBitBtn;
-    procedure FormCreate(Sender: TObject);
-    procedure bbOkClick(Sender: TObject);
-    procedure FormDestroy(Sender: TObject);
-  private
-    FWalletKeys: TWalletKeys;
-    FGeneratedPrivateKey: TECPrivateKey;
-    procedure SetWalletKeys(const Value: TWalletKeys);
-    { Private declarations }
-  public
-    { Public declarations }
-    Property WalletKeys : TWalletKeys read FWalletKeys write SetWalletKeys;
-    Property GeneratedPrivateKey : TECPrivateKey read FGeneratedPrivateKey write FGeneratedPrivateKey;
-  end;
-
-
-implementation
-
-uses
-  UAccounts, UConst ;
-
-{$R *.lfm}
-
-procedure TFRMNewPrivateKeyType.bbOkClick(Sender: TObject);
-begin
-  if Not Assigned(WalletKeys) then exit;
-  if rgKeyType.ItemIndex<0 then raise Exception.Create('Select a key type');
-
-  if Assigned(FGeneratedPrivateKey) then FGeneratedPrivateKey.Free;
-
-  FGeneratedPrivateKey := TECPrivateKey.Create;
-  FGeneratedPrivateKey.GenerateRandomPrivateKey( PtrInt(rgKeyType.Items.Objects[rgKeyType.ItemIndex]) );
-  WalletKeys.AddPrivateKey(ebName.Text,FGeneratedPrivateKey);
-  ModalResult := MrOk;
-end;
-
-procedure TFRMNewPrivateKeyType.FormCreate(Sender: TObject);
-Var l : TList;
-  i : Integer;
-begin
-  FGeneratedPrivateKey := Nil;
-  FWalletKeys := Nil;
-  ebName.Text := DateTimeToStr(now);
-  rgKeyType.Items.Clear;
-  l := TList.Create;
-  Try
-    TAccountComp.ValidsEC_OpenSSL_NID(l);
-    for i := 0 to l.Count - 1 do begin
-      rgKeyType.Items.AddObject(TAccountComp.GetECInfoTxt(PtrInt(l[i])),l[i]);
-    end;
-  Finally
-    l.free;
-  End;
-end;
-
-procedure TFRMNewPrivateKeyType.FormDestroy(Sender: TObject);
-begin
-  FreeAndNil(FGeneratedPrivateKey);
-end;
-
-procedure TFRMNewPrivateKeyType.SetWalletKeys(const Value: TWalletKeys);
-begin
-  FWalletKeys := Value;
-end;
-
-end.

+ 7 - 7
Units/Forms/UFRMNodesIp.pas

@@ -10,7 +10,7 @@ uses
   LCLIntf, LCLType, LMessages,
   Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
   Dialogs, StdCtrls, Buttons,
-  UCommonUI, UAppParams;
+  UCommonUI;
 
 type
   TFRMNodesIp = class(TApplicationForm)
@@ -33,7 +33,7 @@ type
 implementation
 
 uses
-  UUserInterface, UNetProtocol, UNode, UConst;
+  UUserInterface, USettings, UNetProtocol, UNode, UConst;
 
 {$R *.lfm}
 
@@ -53,8 +53,8 @@ Var
 begin
   memoNodesIp.Clear;
   setlength(nsarr,0);
-  ips := TUserInterface.AppParams.ParamByName[CT_PARAM_TryToConnectOnlyWithThisFixedServers].GetAsString('');
-  if trim(ips)<>'' then begin
+  ips := TSettings.TryConnectOnlyWithThisFixedServers;
+  if ips <> '' then begin
     cbTryOnlyWithThisServers.Checked := true;
     TNode.DecodeIpStringToNodeServerAddressArray(ips,nsarr);
   end else begin
@@ -85,13 +85,13 @@ begin
   end;
   // Encode
   ips := TNode.EncodeNodeServerAddressArrayToIpString(nsarr);
-  TUserInterface.AppParams.ParamByName[CT_PARAM_PeerCache].SetAsString(ips);
+  TSettings.PeerCache := ips;
   if cbTryOnlyWithThisServers.Checked then Begin
-    TUserInterface.AppParams.ParamByName[CT_PARAM_TryToConnectOnlyWithThisFixedServers].SetAsString(ips);
+    TSettings.TryConnectOnlyWithThisFixedServers := ips;
     TNetData.NetData.DiscoverFixedServersOnly(nsarr);
     Application.MessageBox(PChar('Restart application to take effect'),PChar(Application.Title),MB_OK);
   end else begin
-    TUserInterface.AppParams.ParamByName[CT_PARAM_TryToConnectOnlyWithThisFixedServers].SetAsString('');
+    TSettings.TryConnectOnlyWithThisFixedServers := '';
     setlength(nsarr,0);
     TNetData.NetData.DiscoverFixedServersOnly(nsarr);
   end;

+ 2 - 4
Units/Forms/UFRMOperation.pas

@@ -23,7 +23,7 @@ uses
   LCLIntf, LCLType, LMessages,
   Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
   Dialogs, StdCtrls, UCommonUI,
-  UNode, UWalletKeys, UCrypto, Buttons, UBlockChain,
+  UNode, UWallet, UCrypto, Buttons, UBlockChain,
   UAccounts, UFRMAccountSelect, ActnList, ComCtrls, Types, UCommon;
 
 Const
@@ -174,7 +174,7 @@ type
 implementation
 
 uses
-  UECIES, UConst, UOpTransaction, UFRMNewPrivateKeyType, UAES, UFRMWalletKeys;
+  UECIES, UConst, UOpTransaction, UAES, UFRMWalletKeys;
 
 {$R *.lfm}
 
@@ -358,7 +358,6 @@ Var FRM : TFRMWalletKeys;
 begin
   FRM := TFRMWalletKeys.Create(Self);
   Try
-    FRM.WalletKeys := WalletKeys;
     FRM.ShowModal;
     cbBuyNewKey.SetFocus;
     UpdateWalletKeys;
@@ -372,7 +371,6 @@ Var FRM : TFRMWalletKeys;
 begin
   FRM := TFRMWalletKeys.Create(Self);
   Try
-    FRM.WalletKeys := WalletKeys;
     FRM.ShowModal;
     rbChangeKeyWithAnother.Checked := true;
     cbNewPrivateKey.SetFocus;

+ 4 - 3
Units/Forms/UFRMPascalCoinWalletConfig.lfm

@@ -1,7 +1,7 @@
 object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
-  Left = 462
+  Left = -1385
   Height = 524
-  Top = 234
+  Top = 29
   Width = 374
   BorderIcons = [biSystemMenu]
   BorderStyle = bsSingle
@@ -13,8 +13,9 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
   Font.Height = -11
   Font.Name = 'Tahoma'
   OnCreate = FormCreate
+  OnDestroy = FormDestroy
   Position = poOwnerFormCenter
-  LCLVersion = '1.6.0.4'
+  LCLVersion = '1.6.4.0'
   object Label1: TLabel
     Left = 30
     Height = 13

+ 82 - 109
Units/Forms/UFRMPascalCoinWalletConfig.pas

@@ -20,11 +20,12 @@ interface
 uses
   LCLIntf, LCLType, LMessages,
   Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
-  Dialogs, StdCtrls, Buttons, ComCtrls, UCommonUI, UAppParams, UWalletKeys;
+  Dialogs, StdCtrls, Buttons, ComCtrls, UCommonUI;
 
-type
+const
+    CM_PC_WalletKeysChanged = WM_USER + 1;
 
-  TMinerPrivateKey = (mpk_NewEachTime, mpk_Random, mpk_Selected);
+type
 
   { TFRMPascalCoinWalletConfig }
 
@@ -66,60 +67,57 @@ type
     procedure cbSaveLogFilesClick(Sender: TObject);
     procedure bbOpenDataFolderClick(Sender: TObject);
     procedure cbJSONRPCPortEnabledClick(Sender: TObject);
+    procedure FormDestroy(Sender: TObject);
   private
-    FAppParams: TAppParams;
-    FWalletKeys: TWalletKeys;
-    procedure SetAppParams(const Value: TAppParams);
-    procedure SetWalletKeys(const Value: TWalletKeys);
-    Procedure UpdateWalletConfig;
-    { Private declarations }
+    procedure CM_WalletChanged(var Msg: TMessage); message CM_PC_WalletKeysChanged;
+    procedure OnWalletChanged(Sender: TObject);
+    procedure RefreshUI;
+    procedure RefreshUI_WalletAspect;
   public
-    { Public declarations }
-    Property AppParams : TAppParams read FAppParams write SetAppParams;
-    Property WalletKeys : TWalletKeys read FWalletKeys write SetWalletKeys;
   end;
 
 implementation
 
-uses UConst, UAccounts, ULog, UCrypto, UFolderHelper;
+uses UConst, USettings, UAccounts, ULog, UCrypto, UFolderHelper, UWallet, UUserInterface, UCommon;
 
 {$R *.lfm}
 
 procedure TFRMPascalCoinWalletConfig.bbOkClick(Sender: TObject);
 Var df : Int64;
-  mpk : TMinerPrivateKey;
+  mpk : TMinerPrivateKeyType;
   i : Integer;
 begin
   if udInternetServerPort.Position = udJSONRPCMinerServerPort.Position then raise Exception.Create('Server port and JSON-RPC Server miner port are equal!');
 
   if TAccountComp.TxtToMoney(ebDefaultFee.Text,df) then begin
-    AppParams.ParamByName[CT_PARAM_DefaultFee].SetAsInt64(df);
+    TSettings.DefaultFee := df;
   end else begin
-    ebDefaultFee.Text := TAccountComp.FormatMoney(AppParams.ParamByName[CT_PARAM_DefaultFee].GetAsInteger(0));
+    ebDefaultFee.Text := TAccountComp.FormatMoney(TSettings.DefaultFee);
     raise Exception.Create('Invalid Fee value');
   end;
-  AppParams.ParamByName[CT_PARAM_InternetServerPort].SetAsInteger(udInternetServerPort.Position );
+  TSettings.InternetServerPort := udInternetServerPort.Position;
   if rbGenerateANewPrivateKeyEachBlock.Checked then mpk := mpk_NewEachTime
   else if rbUseARandomKey.Checked then mpk := mpk_Random
   else if rbMineAllwaysWithThisKey.Checked then begin
     mpk := mpk_Selected;
     if cbPrivateKeyToMine.ItemIndex<0 then raise Exception.Create('Must select a private key');
     i := PtrInt(cbPrivateKeyToMine.Items.Objects[cbPrivateKeyToMine.ItemIndex]);
-    if (i<0) Or (i>=FWalletKeys.Count) then raise Exception.Create('Invalid private key');
-    AppParams.ParamByName[CT_PARAM_MinerPrivateKeySelectedPublicKey].SetAsString( TAccountComp.AccountKey2RawString( FWalletKeys.Key[i].AccountKey ) );
+    if (i<0) Or (i>=TWallet.Keys.Count) then raise Exception.Create('Invalid private key');
+    if NOT TWallet.Keys.Key[i].HasPrivateKey then raise Exception.Create('Cannot use key "' + TWallet.Keys.Key[i].Name + '" for mining since it is watch-only');
+    TSettings.MinerSelectedPrivateKey := TAccountComp.AccountKey2RawString(TWallet.Keys.Key[i].AccountKey);
   end else mpk := mpk_Random;
 
-  AppParams.ParamByName[CT_PARAM_MinerPrivateKeyType].SetAsInteger(integer(mpk));
-  AppParams.ParamByName[CT_PARAM_JSONRPCMinerServerActive].SetAsBoolean(cbJSONRPCMinerServerActive.Checked );
-  AppParams.ParamByName[CT_PARAM_SaveLogFiles].SetAsBoolean(cbSaveLogFiles.Checked );
-  AppParams.ParamByName[CT_PARAM_ShowLogs].SetAsBoolean(cbShowLogs.Checked );
-  AppParams.ParamByName[CT_PARAM_SaveDebugLogs].SetAsBoolean(cbSaveDebugLogs.Checked);
-  AppParams.ParamByName[CT_PARAM_MinerName].SetAsString(ebMinerName.Text);
-  AppParams.ParamByName[CT_PARAM_ShowModalMessages].SetAsBoolean(cbShowModalMessages.Checked);
-  AppParams.ParamByName[CT_PARAM_JSONRPCMinerServerPort].SetAsInteger(udJSONRPCMinerServerPort.Position);
-  AppParams.ParamByName[CT_PARAM_JSONRPCEnabled].SetAsBoolean(cbJSONRPCPortEnabled.Checked);
-  AppParams.ParamByName[CT_PARAM_JSONRPCAllowedIPs].SetAsString(ebJSONRPCAllowedIPs.Text);
-
+  TSettings.MinerPrivateKeyType := mpk;
+  TSettings.MinerServerRpcActive := cbJSONRPCMinerServerActive.Checked;
+  TSettings.MinerServerRpcPort := udJSONRPCMinerServerPort.Position;
+  TSettings.SaveLogFiles := cbSaveLogFiles.Checked;
+  TSettings.ShowLogs := cbShowLogs.Checked;
+  TSettings.SaveDebugLogs := cbSaveDebugLogs.Checked;
+  TSettings.MinerName := ebMinerName.Text;
+  TSettings.ShowModalMessages := cbShowModalMessages.Checked;
+  TSettings.RpcPortEnabled := cbJSONRPCPortEnabled.Checked;
+  TSettings.RpcAllowedIPs := ebJSONRPCAllowedIPs.Text;
+  TSettings.Save;
   ModalResult := MrOk;
 end;
 
@@ -131,29 +129,7 @@ end;
 procedure TFRMPascalCoinWalletConfig.bbUpdatePasswordClick(Sender: TObject);
 Var s,s2 : String;
 begin
-  if Not Assigned(FWalletKeys) then exit;
-  if Not FWalletKeys.IsValidPassword then begin
-    s := '';
-    Repeat
-      if Not InputQuery('Wallet Password','Insert Wallet Password',s) then exit;
-      FWalletKeys.WalletPassword := s;
-      if Not FWalletKeys.IsValidPassword then Application.MessageBox(PChar('Invalid password'),PChar(Application.Title),MB_ICONERROR+MB_OK);
-    Until FWalletKeys.IsValidPassword;
-  end;
-  if FWalletKeys.IsValidPassword then begin
-    s := ''; s2 := '';
-    if Not InputQuery('Change password','Type new password',s) then exit;
-    if trim(s)<>s then raise Exception.Create('Password cannot start or end with a space character');
-    if Not InputQuery('Change password','Type new password again',s2) then exit;
-    if s<>s2 then raise Exception.Create('Two passwords are different!');
-
-    FWalletKeys.WalletPassword := s;
-    Application.MessageBox(PChar('Password changed!'+#10+#10+
-      'Please note that your new password is "'+s+'"'+#10+#10+
-      '(If you lose this password, you will lose your Wallet forever !)'),
-      PChar(Application.Title),MB_ICONWARNING+MB_OK);
-  end;
-  UpdateWalletConfig;
+  TUserInterface.ChangeWalletPassword(Self)
 end;
 
 procedure TFRMPascalCoinWalletConfig.cbJSONRPCPortEnabledClick(Sender: TObject);
@@ -173,34 +149,49 @@ begin
   ebDefaultFee.Text := TAccountComp.FormatMoney(0);
   ebMinerName.Text := '';
   bbUpdatePassword.Enabled := false;
-  UpdateWalletConfig;
   lblDefaultJSONRPCMinerServerPort.Caption := Format('(Default %d)',[CT_JSONRPCMinerServer_Port]);
+  RefreshUI;
+  TWallet.Keys.OnChanged.Add(OnWalletChanged);
+end;
+
+procedure TFRMPascalCoinWalletConfig.FormDestroy(Sender: TObject);
+begin
+  TWallet.Keys.OnChanged.Remove(OnWalletChanged);
+end;
+
+procedure TFRMPascalCoinWalletConfig.CM_WalletChanged(var Msg: TMessage);
+begin
+  RefreshUI_WalletAspect;
 end;
 
-procedure TFRMPascalCoinWalletConfig.SetAppParams(const Value: TAppParams);
+procedure TFRMPascalCoinWalletConfig.OnWalletChanged(Sender: TObject);
+begin
+  // Ensure handled in UI thread
+  PostMessage(Self.Handle,CM_PC_WalletKeysChanged,0,0);
+end;
+
+procedure TFRMPascalCoinWalletConfig.RefreshUI;
 Var i : Integer;
 begin
-  FAppParams := Value;
-  if Not Assigned(Value) then exit;
   Try
-    udInternetServerPort.Position := AppParams.ParamByName[CT_PARAM_InternetServerPort].GetAsInteger(CT_NetServer_Port);
-    ebDefaultFee.Text := TAccountComp.FormatMoney(AppParams.ParamByName[CT_PARAM_DefaultFee].GetAsInt64(0));
-    cbJSONRPCMinerServerActive.Checked := AppParams.ParamByName[CT_PARAM_JSONRPCMinerServerActive].GetAsBoolean(true);
-    case TMinerPrivateKey(AppParams.ParamByName[CT_PARAM_MinerPrivateKeyType].GetAsInteger(Integer(mpk_Random))) of
+    udInternetServerPort.Position := TSettings.InternetServerPort;
+    ebDefaultFee.Text := TAccountComp.FormatMoney(TSettings.DefaultFee);
+    cbJSONRPCMinerServerActive.Checked := TSettings.MinerServerRpcActive;
+    case TSettings.MinerPrivateKeyType of
       mpk_NewEachTime : rbGenerateANewPrivateKeyEachBlock.Checked := true;
       mpk_Random : rbUseARandomKey.Checked := true;
       mpk_Selected : rbMineAllwaysWithThisKey.Checked := true;
     else rbUseARandomKey.Checked := true;
     end;
-    UpdateWalletConfig;
-    cbSaveLogFiles.Checked := AppParams.ParamByName[CT_PARAM_SaveLogFiles].GetAsBoolean(false);
-    cbShowLogs.Checked := AppParams.ParamByName[CT_PARAM_ShowLogs].GetAsBoolean(false);
-    cbSaveDebugLogs.Checked := AppParams.ParamByName[CT_PARAM_SaveDebugLogs].GetAsBoolean(false);
-    ebMinerName.Text := AppParams.ParamByName[CT_PARAM_MinerName].GetAsString('');
-    cbShowModalMessages.Checked := AppParams.ParamByName[CT_PARAM_ShowModalMessages].GetAsBoolean(false);
-    udJSONRPCMinerServerPort.Position := AppParams.ParamByName[CT_PARAM_JSONRPCMinerServerPort].GetAsInteger(CT_JSONRPCMinerServer_Port);
-    cbJSONRPCPortEnabled.Checked := AppParams.ParamByName[CT_PARAM_JSONRPCEnabled].GetAsBoolean(false);
-    ebJSONRPCAllowedIPs.Text := AppParams.ParamByName[CT_PARAM_JSONRPCAllowedIPs].GetAsString('127.0.0.1;');
+    RefreshUI_WalletAspect;
+    cbSaveLogFiles.Checked := TSettings.SaveLogFiles;
+    cbShowLogs.Checked := TSettings.ShowLogs;
+    cbSaveDebugLogs.Checked := TSettings.SaveDebugLogs;
+    ebMinerName.Text := TSettings.MinerName;
+    cbShowModalMessages.Checked := TSettings.ShowModalMessages;
+    udJSONRPCMinerServerPort.Position := TSettings.MinerServerRpcPort;
+    cbJSONRPCPortEnabled.Checked := TSettings.RpcPortEnabled;
+    ebJSONRPCAllowedIPs.Text := TSettings.RpcAllowedIPs;
   Except
     On E:Exception do begin
       TLog.NewLog(lterror,ClassName,'Exception at SetAppParams: '+E.Message);
@@ -210,52 +201,34 @@ begin
   cbJSONRPCPortEnabledClick(nil);
 end;
 
-procedure TFRMPascalCoinWalletConfig.SetWalletKeys(const Value: TWalletKeys);
-begin
-  FWalletKeys := Value;
-  UpdateWalletConfig;
-end;
-
-procedure TFRMPascalCoinWalletConfig.UpdateWalletConfig;
+procedure TFRMPascalCoinWalletConfig.RefreshUI_WalletAspect;
 Var i, iselected : Integer;
   s : String;
   wk : TWalletKey;
 begin
-  if Assigned(FWalletKeys) then begin
-    if FWalletKeys.IsValidPassword then begin
-      if FWalletKeys.WalletPassword='' then begin
-        bbUpdatePassword.Caption := 'Wallet without password, protect it!';
-      end else begin
-        bbUpdatePassword.Caption := 'Change Wallet password';
-      end;
+  if TWallet.Keys.HasPassword then
+    bbUpdatePassword.Caption := 'Change Wallet password'
+  else
+    bbUpdatePassword.Caption := 'Wallet without password, protect it!';
+  cbPrivateKeyToMine.Items.Clear;
+  for i := 0 to TWallet.Keys.Count - 1 do begin
+    wk := TWallet.Keys.Key[i];
+    if (wk.Name='') then begin
+      s := TCrypto.ToHexaString( TAccountComp.AccountKey2RawString(wk.AccountKey));
     end else begin
-        bbUpdatePassword.Caption := 'Wallet with password, change it!';
+      s := wk.Name;
     end;
-    cbPrivateKeyToMine.Items.Clear;
-    for i := 0 to FWalletKeys.Count - 1 do begin
-      wk := FWalletKeys.Key[i];
-      if (wk.Name='') then begin
-        s := TCrypto.ToHexaString( TAccountComp.AccountKey2RawString(wk.AccountKey));
-      end else begin
-        s := wk.Name;
-      end;
-      if wk.CryptedKey<>'' then begin
-        cbPrivateKeyToMine.Items.AddObject(s,TObject(i));
-      end;
+    if wk.CryptedKey<>'' then begin
+      cbPrivateKeyToMine.Items.AddObject(s,TObject(i));
     end;
-    cbPrivateKeyToMine.Sorted := true;
-    if Assigned(FAppParams) then begin
-      s := FAppParams.ParamByName[CT_PARAM_MinerPrivateKeySelectedPublicKey].GetAsString('');
-      iselected := FWalletKeys.IndexOfAccountKey(TAccountComp.RawString2Accountkey(s));
-      if iselected>=0 then begin
-        iselected :=  cbPrivateKeyToMine.Items.IndexOfObject(TObject(iselected));
-        cbPrivateKeyToMine.ItemIndex := iselected;
-      end;
-
-    end;
-
-  end else bbUpdatePassword.Caption := '(Wallet password)';
-  bbUpdatePassword.Enabled := Assigned(FWAlletKeys);
+  end;
+  cbPrivateKeyToMine.Sorted := true;
+  s := TSettings.MinerSelectedPrivateKey;
+  iselected := TWallet.Keys.IndexOfAccountKey(TAccountComp.RawString2Accountkey(s));
+  if iselected >= 0 then begin
+    iselected :=  cbPrivateKeyToMine.Items.IndexOfObject(TObject(iselected));
+    cbPrivateKeyToMine.ItemIndex := iselected;
+  end;
 end;
 
 end.

+ 45 - 65
Units/Forms/UFRMPayloadDecoder.pas

@@ -23,7 +23,7 @@ uses
   LCLIntf, LCLType, LMessages,
   Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
   Dialogs, StdCtrls, UCommonUI,
-  UBlockChain, UCrypto, UWalletKeys, Buttons, ComCtrls,UAppParams;
+  UBlockChain, UCrypto, UWallet, Buttons, ComCtrls,UAppParams;
 
 type
 
@@ -68,17 +68,14 @@ type
     procedure PageControlChanging(Sender: TObject; var AllowChange: Boolean);
     procedure cbMethodPublicPayloadClick(Sender: TObject);
     procedure bbSaveMethodsClick(Sender: TObject);
-    procedure memoDecodedKeyDown(Sender: TObject; var Key: Word;
-      Shift: TShiftState);
+    procedure memoDecodedKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
     procedure bbFindClick(Sender: TObject);
     procedure ebOphashExit(Sender: TObject);
     procedure ebOphashKeyPress(Sender: TObject; var Key: Char);
     procedure cbShowAsHexadecimalClick(Sender: TObject);
   private
     FOpResume : TOperationResume;
-    FWalletKeys : TWalletKeys;
     FSavedDecodeMethods : boolean;
-    FAppParams : TAppParams;
     FSemaphor : Boolean;
     { Private declarations }
     Procedure TryToDecode;
@@ -86,7 +83,7 @@ type
     procedure SetOpResume(const Value: TOperationResume);
   public
     { Public declarations }
-    Procedure Init(Const AOperationResume : TOperationResume; WalletKeys : TWalletKeys; AppParams : TAppParams);
+    Procedure Init(Const AOperationResume : TOperationResume);
     Property OpResume : TOperationResume read FOpResume write SetOpResume;
     Procedure DoFind(Const OpHash : String);
   end;
@@ -95,7 +92,7 @@ implementation
 
 {$R *.lfm}
 
-Uses UNode, UTime, UECIES, UAES, UAccounts;
+Uses UNode, UTime, UECIES, UAES, UAccounts, USettings;
 
 { TFRMPayloadDecoder }
 
@@ -183,8 +180,6 @@ procedure TFRMPayloadDecoder.FormCreate(Sender: TObject);
 begin
   FSemaphor := true;
   try
-    FWalletKeys := Nil;
-    FAppParams := Nil;
     memoDecoded.Lines.Clear;
     memoOriginalPayloadInHexa.Lines.Clear;
     lblPasswordsInfo.Caption := '';
@@ -194,10 +189,8 @@ begin
   end;
 end;
 
-procedure TFRMPayloadDecoder.Init(Const AOperationResume : TOperationResume; WalletKeys : TWalletKeys; AppParams : TAppParams);
+procedure TFRMPayloadDecoder.Init(Const AOperationResume : TOperationResume);
 begin
-  FWalletKeys := WalletKeys;
-  FAppParams := AppParams;
   OpResume := AOperationResume;
   FSavedDecodeMethods := true;
   PageControl.ActivePage := tsDecoded;
@@ -233,11 +226,12 @@ end;
 
 procedure TFRMPayloadDecoder.SaveMethods;
 begin
-  FAppParams.ParamByName['PayloadDecoder.notencrypted'].SetAsBoolean(cbMethodPublicPayload.Checked);
-  FAppParams.ParamByName['PayloadDecoder.usingprivatekeys'].SetAsBoolean(cbUsingPrivateKeys.Checked);
-  FAppParams.ParamByName['PayloadDecoder.usingpasswords'].SetAsBoolean(cbUsingPasswords.Checked);
-  FAppParams.ParamByName['PayloadDecoder.passwords'].SetAsString(memoPasswords.Lines.Text);
-  FAppParams.ParamByName['PayloadDecoder.showashexadecimal'].SetAsBoolean(cbShowAsHexadecimal.Checked);
+  TSettings.AppParams.ParamByName['PayloadDecoder.notencrypted'].SetAsBoolean(cbMethodPublicPayload.Checked);
+  TSettings.AppParams.ParamByName['PayloadDecoder.usingprivatekeys'].SetAsBoolean(cbUsingPrivateKeys.Checked);
+  TSettings.AppParams.ParamByName['PayloadDecoder.usingpasswords'].SetAsBoolean(cbUsingPasswords.Checked);
+  TSettings.AppParams.ParamByName['PayloadDecoder.passwords'].SetAsString(memoPasswords.Lines.Text);
+  TSettings.AppParams.ParamByName['PayloadDecoder.showashexadecimal'].SetAsBoolean(cbShowAsHexadecimal.Checked);
+  TSettings.Save;
   FSavedDecodeMethods := true;
 end;
 
@@ -300,18 +294,11 @@ begin
     else lblFee.Font.Color := clRed;
     ebOpHash.text := TCrypto.ToHexaString(Value.OperationHash);
     memoOriginalPayloadInHexa.Lines.Text := TCrypto.ToHexaString(Value.OriginalPayload);
-    if Assigned(FWalletKeys) then begin
-      cbMethodPublicPayload.Checked := FAppParams.ParamByName['PayloadDecoder.notencrypted'].GetAsBoolean(true);
-      cbUsingPrivateKeys.Checked := FAppParams.ParamByName['PayloadDecoder.usingprivatekeys'].GetAsBoolean(true);
-      cbUsingPasswords.Checked := FAppParams.ParamByName['PayloadDecoder.usingpasswords'].GetAsBoolean(true);
-      memoPasswords.Lines.Text := FAppParams.ParamByName['PayloadDecoder.passwords'].GetAsString('');
-      cbShowAsHexadecimal.Checked := FAppParams.ParamByName['PayloadDecoder.showashexadecimal'].GetAsBoolean(false);
-    end else begin
-      cbMethodPublicPayload.Checked := true;
-      cbUsingPrivateKeys.Checked := true;
-      cbUsingPasswords.Checked := true;
-      memoPasswords.Lines.Text := '';
-    end;
+    cbMethodPublicPayload.Checked := TSettings.AppParams.ParamByName['PayloadDecoder.notencrypted'].GetAsBoolean(true);
+    cbUsingPrivateKeys.Checked := TSettings.AppParams.ParamByName['PayloadDecoder.usingprivatekeys'].GetAsBoolean(true);
+    cbUsingPasswords.Checked := TSettings.AppParams.ParamByName['PayloadDecoder.usingpasswords'].GetAsBoolean(true);
+    memoPasswords.Lines.Text := TSettings.AppParams.ParamByName['PayloadDecoder.passwords'].GetAsString('');
+    cbShowAsHexadecimal.Checked := TSettings.AppParams.ParamByName['PayloadDecoder.showashexadecimal'].GetAsBoolean(false);
     FSavedDecodeMethods := true;
     PageControl.ActivePage := tsDecoded;
     TryToDecode;
@@ -325,10 +312,8 @@ procedure TFRMPayloadDecoder.TryToDecode;
   Var i : Integer;
   begin
     Result := false;
-    if Not assigned(FWalletKeys) then exit;
-
-    for i := 0 to FWalletKeys.Count - 1 do begin
-      WalletKey := FWalletKeys.Key[i];
+    for i := 0 to TWallet.Keys.Count - 1 do begin
+      WalletKey := TWallet.Keys.Key[i];
       If Assigned(WalletKey.PrivateKey) then begin
         If ECIESDecrypt(WalletKey.PrivateKey.EC_OpenSSL_NID,WalletKey.PrivateKey.PrivateKey,false,raw,Decrypted) then begin
           Result := true;
@@ -361,42 +346,37 @@ Var raw : TRawBytes;
   ok : boolean;
 begin
   ok := true;
-  if Assigned(FWalletKeys) And Assigned(FAppParams) then begin
-    raw := FOpResume.OriginalPayload;
-    if raw<>'' then begin
-      // First try to a human readable...
-      if (cbMethodPublicPayload.Checked) and (TCrypto.IsHumanReadable(raw)) then begin
-        if cbShowAsHexadecimal.Checked then memoDecoded.Lines.Text := TCrypto.ToHexaString(raw)
-        else memoDecoded.Lines.Text := raw;
-        lblDecodedMethod.Caption := 'Not encrypted payload';
-      end else if (cbUsingPrivateKeys.Checked) And (UseWallet(raw,Decrypted,WalletKey)) then begin
-        if cbShowAsHexadecimal.Checked then memoDecoded.Lines.Text := TCrypto.ToHexaString(Decrypted)
-        else memoDecoded.Lines.Text := Decrypted;
-        lblDecodedMethod.Caption := 'Encrypted with EC '+TAccountComp.GetECInfoTxt(WalletKey.PrivateKey.EC_OpenSSL_NID);
-      end else if (cbUsingPasswords.Checked) And (UsePassword(raw,Decrypted,PasswordUsed)) then begin
-        if cbShowAsHexadecimal.Checked then memoDecoded.Lines.Text := TCrypto.ToHexaString(Decrypted)
-        else memoDecoded.Lines.Text := Decrypted;
-        lblDecodedMethod.Caption := 'Encrypted with pwd:"'+PasswordUsed+'"';
-      end else begin
-        memoDecoded.Lines.Text := 'CANNOT DECRYPT';
-        lblDecodedMethod.Caption := '';
-        ok := false;
-      end;
-      if ok then begin
-        memoDecoded.Font.Color := clBlack;
-        memoDecoded.Color := clWhite;
-      end else begin
-        memoDecoded.Font.Color := clRed;
-        memoDecoded.Color := clBtnFace;
-      end;
+  raw := FOpResume.OriginalPayload;
+  if raw<>'' then begin
+    // First try to a human readable...
+    if (cbMethodPublicPayload.Checked) and (TCrypto.IsHumanReadable(raw)) then begin
+      if cbShowAsHexadecimal.Checked then memoDecoded.Lines.Text := TCrypto.ToHexaString(raw)
+      else memoDecoded.Lines.Text := raw;
+      lblDecodedMethod.Caption := 'Not encrypted payload';
+    end else if (cbUsingPrivateKeys.Checked) And (UseWallet(raw,Decrypted,WalletKey)) then begin
+      if cbShowAsHexadecimal.Checked then memoDecoded.Lines.Text := TCrypto.ToHexaString(Decrypted)
+      else memoDecoded.Lines.Text := Decrypted;
+      lblDecodedMethod.Caption := 'Encrypted with EC '+TAccountComp.GetECInfoTxt(WalletKey.PrivateKey.EC_OpenSSL_NID);
+    end else if (cbUsingPasswords.Checked) And (UsePassword(raw,Decrypted,PasswordUsed)) then begin
+      if cbShowAsHexadecimal.Checked then memoDecoded.Lines.Text := TCrypto.ToHexaString(Decrypted)
+      else memoDecoded.Lines.Text := Decrypted;
+      lblDecodedMethod.Caption := 'Encrypted with pwd:"'+PasswordUsed+'"';
     end else begin
-      memoDecoded.Lines.Text := '(No payload)';
-      memoDecoded.Font.Color := clDkGray;
-      memoDecoded.Color := clLtGray;
+      memoDecoded.Lines.Text := 'CANNOT DECRYPT';
       lblDecodedMethod.Caption := '';
+      ok := false;
+    end;
+    if ok then begin
+      memoDecoded.Font.Color := clBlack;
+      memoDecoded.Color := clWhite;
+    end else begin
+      memoDecoded.Font.Color := clRed;
+      memoDecoded.Color := clBtnFace;
     end;
   end else begin
-    memoDecoded.Lines.Text := '';
+    memoDecoded.Lines.Text := '(No payload)';
+    memoDecoded.Font.Color := clDkGray;
+    memoDecoded.Color := clLtGray;
     lblDecodedMethod.Caption := '';
   end;
 end;

+ 1 - 1
Units/Forms/UFRMPendingOperations.pas

@@ -78,7 +78,7 @@ end;
 procedure TFRMPendingOperations.miFindOperationbyOpHashClick(Sender: TObject);
 var ophash:AnsiString;
 begin
-  if Not TUserInterface.AskUserEnterString(Self, 'Search operation by OpHash','Insert Operation Hash value (OpHash)',ophash)
+  if Not TUserInterface.AskEnterString(Self, 'Search operation by OpHash','Insert Operation Hash value (OpHash)',ophash)
     then exit;
 
   TUserInterface.ShowOperationInfoDialog(Self, ophash);

+ 1319 - 591
Units/Forms/UFRMWalletKeys.lfm

@@ -1,252 +1,99 @@
 object FRMWalletKeys: TFRMWalletKeys
-  Left = 628
-  Height = 478
-  Top = 282
-  Width = 569
-  BorderIcons = [biSystemMenu]
-  BorderStyle = bsSingle
-  Caption = 'Wallet keys'
-  ClientHeight = 478
-  ClientWidth = 569
-  Color = clBtnFace
-  Font.Color = clWindowText
-  Font.Height = -11
-  Font.Name = 'Tahoma'
+  Left = 198
+  Height = 477
+  Top = 373
+  Width = 661
+  Caption = 'Wallet Keys'
+  ClientHeight = 477
+  ClientWidth = 661
   OnCreate = FormCreate
+  OnDestroy = FormDestroy
   Position = poOwnerFormCenter
   LCLVersion = '1.6.4.0'
+  object lbWalletKeys: TListBox
+    Left = 24
+    Height = 210
+    Top = 80
+    Width = 612
+    Anchors = [akTop, akLeft, akRight, akBottom]
+    ItemHeight = 0
+    OnClick = lbWalletKeysClick
+    PopupMenu = pmKeyMenu
+    ScrollWidth = 344
+    TabOrder = 0
+  end
   object lblEncryptionTypeCaption: TLabel
-    Left = 30
-    Height = 13
-    Top = 298
-    Width = 80
-    Caption = 'Encryption type:'
+    Left = 55
+    Height = 15
+    Top = 305
+    Width = 50
+    Anchors = [akLeft, akBottom]
+    Caption = 'Key Type:'
     ParentColor = False
   end
   object lblEncryptionType: TLabel
-    Left = 125
-    Height = 13
-    Top = 298
-    Width = 54
+    Left = 115
+    Height = 15
+    Top = 304
+    Width = 521
+    Anchors = [akLeft, akRight, akBottom]
+    AutoSize = False
     Caption = '000000000'
     ParentColor = False
   end
   object lblKeyNameCaption: TLabel
-    Left = 30
-    Height = 13
-    Top = 317
-    Width = 51
-    Caption = 'Key name:'
+    Left = 48
+    Height = 15
+    Top = 328
+    Width = 57
+    Anchors = [akLeft, akBottom]
+    Caption = 'Key Name:'
     ParentColor = False
   end
   object lblKeyName: TLabel
-    Left = 125
-    Height = 13
-    Top = 317
-    Width = 313
+    Left = 115
+    Height = 15
+    Top = 328
+    Width = 521
+    Anchors = [akLeft, akRight, akBottom]
     AutoSize = False
     Caption = '000000000'
     ParentColor = False
   end
   object lblPrivateKeyCaption: TLabel
-    Left = 30
-    Height = 13
-    Top = 336
+    Left = 47
+    Height = 15
+    Top = 352
     Width = 58
-    Caption = 'Private key:'
-    ParentColor = False
-  end
-  object lblPrivateKeyCaption2: TLabel
-    Left = 30
-    Height = 13
-    Top = 355
-    Width = 80
-    Caption = '(In hexa format)'
-    ParentColor = False
-  end
-  object lblKeysEncrypted: TLabel
-    Left = 30
-    Height = 39
-    Top = 15
-    Width = 259
-    AutoSize = False
-    Caption = 'lblKeysEncrypted'
-    Font.Color = clBlack
-    Font.Height = -16
-    Font.Name = 'Tahoma'
-    Font.Style = [fsBold]
+    Anchors = [akLeft, akBottom]
+    Caption = 'Public Key:'
     ParentColor = False
-    ParentFont = False
-    WordWrap = True
-  end
-  object lbWalletKeys: TListBox
-    Left = 30
-    Height = 227
-    Top = 60
-    Width = 346
-    ItemHeight = 0
-    OnClick = lbWalletKeysClick
-    ScrollWidth = 344
-    TabOrder = 0
-  end
-  object bbExportPrivateKey: TBitBtn
-    Left = 382
-    Height = 36
-    Top = 136
-    Width = 159
-    Caption = 'Export Private key'
-    Glyph.Data = {
-      76060000424D7606000000000000360400002800000018000000180000000100
-      0800000000004002000000000000000000000001000000010000FF00FF005251
-      5100565758005A5958005B5D5D005D5E5E006361610066666600696969006C6B
-      6B0073706F0072707000747271000E80AA001788AF000B86B2000C85B000098A
-      B700078CBA00198EB7000E91BE001E94BC002898BA003E99BB000493C4000997
-      C7000A9ECF00229BC20035A0C30030AACA0032AACE003DAACC003FB0CB0036A9
-      D0003BB1D9003DBDDA0039B8DE0029BBE0004DBBD90068B0CA0019C7F1001BD4
-      FE002FC6E7003ECDE9002CD3F9002ED8FE003CE0FE0054C0D40059C4D70059C2
-      DD006FC2D6007CC0D50078C1D80049DDFE0054DFFE0061C6E5006CD4EE0064D9
-      E90076DFE9007DDFE90055E0FF0058E0FE006BE3F40063E6FE0060ECFE0075E2
-      FA0077E6FF007BE8FF0071F2FE0088828000928E8C0096908F00969291009794
-      94009E969400A09C9B00A19F9E00ACA09E00A6A2A100A6A4A400ADA5A300AAA5
-      A400ABA8A800ADAAA900B0A5A300B2A7A500B2ABAB00B4ABA900BBB1AE00BEB1
-      AF00BAB3B200BAB4B200BEB6B400C4B8B600C1BCBB0083DFE9008ADAEB0094DF
-      E90089DDF100A4DFEA009AE2F40095EBFD0095EDFE009EEDFF0084F3F90080F5
-      FC008FF6FB0083F8FE0093F2FE0097F9FE0094FDFE0099FFFE009EFFFE00AAEF
-      FD00B4EEF300A4FFFE00A8F9FE00ADFBFE00AAFFFE00B6F1FF00BCF2F800B3F9
-      FF00B3FFFE00B9FFFE00C7C2C100C7C6C600CCC4C200CAC7C600CFCCCC00D1C7
-      C500D4CBC900D1CDCD00D5CFCE00D8D0CE00D7D1D000D9D5D400DCD7D600DFD8
-      D600E3DEDD00C3DFEA00CCF6FF00C9FFFE00CFFFFF00D1F7FF00DBF8FE00DFFF
-      FF00E7E3E200E9E5E500ECE9E900EFEEED00F1EBEA00F1EFEE00E5FFFF00F3F1
-      F100F6F2F000F8F5F300F8F5F400F0F7FA00F5FFFF00FBF8F800FAFFFF00FFFE
-      FE00000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0007070707000000000000000000000000000000000000000746967E07000000
-      0000000000000000000000000000000D085E489A5E080D0D0000000000000000
-      00000000000D0D2626075E48A1071F130D0D000000000000000000000D163940
-      3F35075E4C93070707100D000000000000000000123A6B402E353D075E519580
-      4E0707070707000000000000123A6B402E293D42075E4EA19289858281550700
-      00000000123A6B402E292D4266075E4C9689865A475D4D0700000000123A6B40
-      2E292D3C6671077D928A7D0A0A58580700000000123A6B402E292D3C4371079A
-      958007035151550700000000123A6D6C6667778C8F90079A860701574C024A07
-      0000000012727860311E1B151C3407A17E0B534C000445070000000011322023
-      2A282C36426407539A8882040404570700000000103169402E292D3643716207
-      5393825A515A5A0700000000123A6B402E292D3C436662370707070708070700
-      00000000123A6B402E292D3C43663837222117000000000000000000123A6B40
-      2E292D3C436638231A180D000000000000000000123A6B402E292D3C43663822
-      1A180D000000000000000000123A6B402E292D3C436638231A180D0000000000
-      00000000123B757975756F6F6F6F6A3E25190D000000000000000000128BA190
-      8E79736F6F6F6F6D442B0D00000000000000000012279D9D908E796F6F6F6F6F
-      691E0D000000000000000000001214333363615F3B3A2F2F0E0D000000000000
-      0000000000000014121212121212121200000000000000000000
-    }
-    OnClick = bbExportPrivateKeyClick
-    TabOrder = 4
   end
-  object memoPrivateKey: TMemo
-    Left = 125
-    Height = 80
-    Top = 336
-    Width = 416
+  object memoPublicKey: TMemo
+    Left = 115
+    Height = 61
+    Top = 352
+    Width = 522
+    Anchors = [akLeft, akRight, akBottom]
     Color = clBtnFace
     Font.Color = clBlack
-    Font.Height = -16
+    Font.Height = -11
     Font.Name = 'Tahoma'
     Lines.Strings = (
-      'memoPrivateKey'
+      'memoPublicKey'
     )
     ParentFont = False
     ReadOnly = True
-    TabOrder = 9
+    TabOrder = 1
     TabStop = False
   end
-  object bbChangeName: TBitBtn
-    Left = 440
-    Height = 25
-    Top = 305
-    Width = 101
-    Caption = 'Change Name'
-    OnClick = bbChangeNameClick
-    TabOrder = 8
-  end
-  object bbImportPrivateKey: TBitBtn
-    Left = 382
-    Height = 36
-    Top = 98
-    Width = 159
-    Caption = 'Import Private key'
-    Glyph.Data = {
-      76060000424D7606000000000000360400002800000018000000180000000100
-      0800000000004002000000000000000000000001000000010000FF00FF000571
-      0A0008750D0024B53B0029B942002ABA44002EBD4A002FBF4C0033C1500034C2
-      520035C3540037C5570039C659003BC85C003CC95E003FCC630040CC650045D0
-      6B0046D16C0049D472004BD675004ED8790050D97B0051DA7E000E80AA001788
-      AF000B86B200098AB700078CBA00198EB700118EB9000E91BE001E94BC002898
-      BA0055DD810056DF850058E087000493C4000997C7000C9BCB000A9DCE00229B
-      C20015AFD90026A0C80021AACF0035A0C30030AACA0032AACE003DAACC003FB0
-      CB0031AED7003DBDDA0039B8DE0029BBE00056B1CE0052BDDB0068B0CA006BBD
-      D70019C7F1001BD4FE002FC6E70026C2E9003ECDE9002CD3F9002ED8FE003CE0
-      FE0054C0D40059C4D70059C2DD006FC2D60062C3DE007CC0D5007AC6DF0043C8
-      E90054DFFE0060CEEA0079CFE9006CD4EE0064D9E90076DFE9007DDFE90055E0
-      FF006BE3F40060ECFE0075E2FA007BE8FF0071F2FE008FD0E60083DFE9008ADA
-      EB0094DFE90081DBF100A4DFEA0095EBFD0095EEFE009EEDFF0084F3F90080F5
-      FC008FF6FB0083F8FE0093F2FE0097F9FE0094FDFE0099FFFE009EFFFE00AFE8
-      F600B4EEF300A4FFFE00A8F9FE00ADFBFE00AAFFFE00B6F1FF00BCF2F800B3F9
-      FF00B3FFFE00B9FFFE00C3DFEA00CCF6FF00C9FFFE00CFFFFF00D1F6FE00DFFF
-      FF00E5FFFF00F0F7FA00F5FFFF00FAFFFF000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000202020200000000000000000000000000000000000000
-      0002040302000000000000000000001818181818181818180002060402000000
-      000000000018182C2C2A3D494B46301D18020906020000000000000018214E53
-      413B4051555D4D3427020D0902000000000000001C4F6353413B405102020202
-      02020F0D02020202020200001C4F6353413B405102242317151311100D090906
-      040200001C4F6353413B40510224242323151311100F0D09060200001C4F6353
-      413B4051020101010102171302010101020100001C4F6353413B4051555D4D34
-      2702231702000000000000001C4F65645D5F6F757878694C3202242302000000
-      000000001C6A7059442F29202D3639485702242402000000000000001B453134
-      3C3A3F4A545B372B1E02242402000000000000001A436153413B4051555D4D34
-      2701020202000000000000001C4F6353413B4051555D4D342725180000000000
-      000000001C4F6353413B4051555D4D342725180000000000000000001C4F6353
-      413B4051555D4D342725180000000000000000001C4F6353413B4051555D4D34
-      2825180000000000000000001C4F6353413B4051555D4D342725180000000000
-      000000001C506D716D6D6767676762523527180000000000000000001C747D7A
-      77716B6767676765563E180000000000000000001C387B7C7977716767676767
-      612F18000000000000000000001C1F47475C5A58504F42421918000000000000
-      000000000000001C1C1C1C1C1C1C1C1C00000000000000000000
-    }
-    OnClick = bbImportPrivateKeyClick
-    TabOrder = 3
-  end
-  object bbExportPublicKey: TBitBtn
-    Left = 382
+  object btnBackupWallet: TBitBtn
+    Left = 24
     Height = 36
-    Top = 212
-    Width = 159
-    Caption = 'Export Public key'
+    Top = 426
+    Width = 193
+    Anchors = [akBottom]
+    Caption = 'Backup Wallet'
     Glyph.Data = {
       F6060000424DF606000000000000360000002800000018000000180000000100
       180000000000C0060000120B0000120B00000000000000000000FF00FFFF00FF
@@ -305,15 +152,16 @@ object FRMWalletKeys: TFRMWalletKeys
       89B88989B88989B88989B88989B88989B88989B88989B88989FF00FFFF00FFFF
       00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
     }
-    OnClick = bbExportPublicKeyClick
-    TabOrder = 6
+    OnClick = btnBackupWalletClick
+    TabOrder = 2
   end
-  object bbImportPublicKey: TBitBtn
-    Left = 382
+  object btnRestoreBackup: TBitBtn
+    Left = 432
     Height = 36
-    Top = 174
-    Width = 159
-    Caption = 'Import Public key'
+    Top = 426
+    Width = 206
+    Anchors = [akRight, akBottom]
+    Caption = 'Restore Backup'
     Glyph.Data = {
       F6060000424DF606000000000000360000002800000018000000180000000100
       180000000000C0060000120B0000120B00000000000000000000FF00FFFF00FF
@@ -372,43 +220,80 @@ object FRMWalletKeys: TFRMWalletKeys
       FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF0C85180C85180C85180C85180C
       8518FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
     }
-    OnClick = bbImportPublicKeyClick
-    TabOrder = 5
+    OnClick = btnRestoreBackupClick
+    TabOrder = 3
   end
-  object bbGenerateNewKey: TBitBtn
-    Left = 382
-    Height = 36
-    Top = 60
-    Width = 159
-    Caption = 'Generate a new Key'
+  object btnCopyClipboard: TSpeedButton
+    Left = 81
+    Height = 24
+    Top = 376
+    Width = 24
+    Anchors = [akLeft, akBottom]
     Glyph.Data = {
-      76060000424D7606000000000000360400002800000018000000180000000100
-      0800000000004002000000000000000000000001000000010000FF00FF007D33
-      2F00993300000C35EB000335FB001342FB00224EFB00325BFC005274FC000E80
-      AA001788AF000B86B200098AB700078CBA00078EBD00118EB9000E91BE001E94
-      BC002898BA000493C4000997C7000A9DCE00229BC20015AFD90026A0C80021AA
-      CF0035A0C30030AACA0032AACE003FB0CB003DBDDA0039B8DE0029BBE00046A6
-      C90056B1CE0052BDDB0068B0CA006BBDD700718DFC0019C7F1001BD4FE002FC6
-      E70026C2E9003ECDE9002CD3F9002ED8FE003CE0FE0054C0D40059C4D70059C2
-      DD006FC2D6007CC0D50076C4DF007AC6DF0043C8E90054DFFE0060CEEA006CD4
-      EE0064D9E90076DFE9007DDFE90055E0FF006BE3F40060ECFE0075E2FA007BE8
-      FF0071F2FE008099FC00A0B2FD00AFBFFD008FD0E60083DFE9008ADAEB0094DF
-      E90081DBF100A4DFEA0095EBFD0095EEFE009EEDFF0084F3F90080F5FC008FF6
-      FB0083F8FE0093F2FE0097F9FE0094FDFE0099FFFE009EFFFE00B4EEF300A4FF
-      FE00A8F9FE00ADFBFE00AAFFFE00B6F1FF00BCF2F800B3F9FF00B3FFFE00B9FF
-      FE00C3DFEA00CFD8FD00DFE5FE00CCF6FF00C9FFFE00CFFFFF00D1F7FF00DFFF
-      FF00EEF1FE00E5FFFF00F0F7FA00F5FFFF00FAFFFF00FEFEFE00000000000000
+      36090000424D3609000000000000360000002800000018000000180000000100
+      2000000000000009000064000000640000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
+      0003000000080000000800000008000000080000000800000008000000080000
+      0008000000080000000800000003000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
+      006B000000CB000000CE000000CE000000CE000000CE000000CE000000CE0000
+      00CE000000CE000000CB0000007B000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
+      00C70000007D0000003C0000003C0000003C0000003C0000003C0000003C0000
+      003C0000003C00000099000000F8000000000000000000000000000000000000
+      0000000000000000002300000036000000360000003600000036000000360000
+      00DB000000550000000000000000000000000000000000000000000000000000
+      0000000000000000007A000000F9000000000000000000000000000000000000
+      000000000000000000E3000000FF000000FF000000FF000000FF000000FF0000
+      00FF000000550000000000000000000000000000000000000000000000000000
+      0000000000000000007A000000F9000000000000000000000000000000000000
+      000000000000000000FF000000FF000000FF000000FF000000FF000000FF0000
+      00FF000000550000000000000000000000000000000000000000000000000000
+      0000000000000000007A000000F9000000000000000000000000000000000000
+      000000000000000000FF000000FF000000FF000000FF000000FF000000FF0000
+      00FF000000550000000000000000000000000000000000000000000000000000
+      0000000000000000007A000000F9000000000000000000000000000000000000
+      000000000000000000FF000000FF000000FF000000FF000000FF000000FF0000
+      00FF000000550000000000000000000000000000000000000000000000000000
+      0000000000000000007A000000F9000000000000000000000000000000000000
+      000000000000000000FF000000FF000000FF000000FF000000FF000000FF0000
+      00FF000000550000000000000000000000000000000E0000003B0000003D0000
+      003D0000003D0000009A000000E9000000000000000000000000000000000000
+      000000000000000000FF000000FF000000FF000000FF000000FF000000FF0000
+      00FF0000005500000000000000000000000000000085000000F0000000CC0000
+      00CC000000DA000000FF0000005C000000000000000000000000000000000000
+      000000000000000000FF000000FF000000FF000000FF000000FF000000FF0000
+      00FF00000055000000000000000000000000000000A8000000BF000000000000
+      000E0000009B0000007000000004000000000000000000000000000000000000
+      000000000000000000FF000000FF000000FF000000FF000000FF000000FF0000
+      00FF00000055000000000000000000000000000000A8000000BF0000002F0000
+      00B4000000800000000A00000000000000000000000000000000000000000000
+      000000000000000000FF000000FF000000FF000000FF000000FF000000FF0000
+      00FF00000056000000010000000100000001000000A9000000E3000000CB0000
+      005F000000050000000000000000000000000000000000000000000000000000
+      000000000000000000FF000000FF000000FF000000FF000000FF000000FF0000
+      00FF000000930000005E0000005E0000005E000000D0000000EF0000005D0000
+      0004000000000000000000000000000000000000000000000000000000000000
+      000000000000000000FF000000FF000000FF000000FF000000FF000000FF0000
+      00FF000000FF000000FF000000FF000000FF000000FF000000C3000000040000
       0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000FF000000FF000000E3000000D3000000D3000000D30000
+      00D3000000D3000000D3000000D8000000F7000000FF000000BF000000000000
       0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000FF000000FF000000530000000200000002000000020000
+      000200000002000000020000001B000000CC000000FF000000BF000000000000
       0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000EB000000F9000000EF000000EA000000EA000000EA0000
+      00EA000000EA000000EA000000EC000000F6000000F9000000AC000000000000
       0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000350000006E0000006E0000006E0000006E0000006E0000
+      006E0000006E0000006E0000006E0000006E0000006D0000001A000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
@@ -416,377 +301,1220 @@ object FRMWalletKeys: TFRMWalletKeys
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      000000020202020202020202020200000000000000000000000000026F6F6F6F
-      64076A6F6F0200000000000000090909090909026F6F6F450504446F6F020000
-      00000009091919172A3638026F6F26040404066F6F020000000009123A3F2E28
-      2D3D41026A070404260504456F02000000000D3B523F2E282D3D410206040545
-      6F4304066F02000000000D3B523F2E282D3D41024407636F6F6A050443020000
-      00000D3B523F2E282D3D41026F6F6F6F6F6F44040401000000000D3B523F2E28
-      2D3D41026F6F6F6F6F6F6F080403000000000D3B523F2E282D3D41026F6F6F6F
-      6F6F6F6A0704040000000D3B54534D4E5D656802020202020202020201030404
-      00000D585E48311C16111A2225354634090000000000040404000C321D1E2927
-      2C37404A23180F21090000000000000404040B30503F2E282D3D414D391E150D
-      090000000000000000000D3B523F2E282D3D414D391E15130900000000000000
-      00000D3B523F2E282D3D414D391F1513090000000000000000000D3B523F2E28
-      2D3D414D391F1513090000000000000000000D3B523F2E282D3D414D391E1513
-      090000000000000000000D3B523F2E282D3D414D391F15130900000000000000
-      00000D3C5B5F5B5B56565656513E2014090000000000000000000D626F69675F
-      595656565654422B090000000000000000000D246C6D69675F5656565656501C
-      09000000000000000000000D1033334B49473C3B2F2F0A090000000000000000
-      00000000000D0D0D0D0D0D0D0D0D000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000
     }
-    OnClick = bbGenerateNewKeyClick
-    TabOrder = 2
+    OnClick = btnCopyClipboardClick
   end
-  object bbDelete: TBitBtn
-    Left = 382
-    Height = 36
-    Top = 251
-    Width = 159
-    Caption = 'Delete'
+  object btnAddKey: TSpeedButton
+    Left = 604
+    Height = 32
+    Top = 40
+    Width = 32
+    Anchors = [akTop, akRight]
     Glyph.Data = {
-      F6060000424DF606000000000000360000002800000018000000180000000100
-      180000000000C0060000120B0000120B00000000000000000000FF00FFFF00FF
-      FF00FFFF00FFFF00FFFF00FFFF00FFFF00FF00009A00009A00039D020DA4020D
-      A400039D00009A00009AFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
-      00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF00009A020DA4041FB3072FC0
-      0732C20732C20732C20732C2072FC0041FB3020DA400009AFF00FFFF00FFFF00
-      FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF00009A01079F0526B807
-      32C20732C20732C20732C20732C20732C20732C20732C20732C20732C20526B8
-      01079F00009AFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF00009A0210
-      A7062FC50732C50732C20732C20732C20732C20732C20732C20732C20732C207
-      32C20732C20732C2072FC00210A700009AFF00FFFF00FFFF00FFFF00FFFF00FF
-      00009A0210A80633D00633CF0632CA0732C60732C20732C20732C20732C20732
-      C20732C20732C20732C20732C20732C20732C20732C20210A700009AFF00FFFF
-      00FFFF00FFFF00FF01079F0530D70533DA0633D50633D00632CB0732C70732C3
-      0732C20732C20732C20732C20732C20732C20732C20732C20732C20732C2072F
-      C001079FFF00FFFF00FFFF00FF00009A0427CC0534E40533DF0533DB022FD512
-      3DD44868DA042FC70430C30732C20732C20631C2002BC03E5FD01F46C8012CC0
-      0732C20732C20732C20526B800009AFF00FFFF00FF010DA90434EC0434EA0534
-      E50533E1113ADDB3C1F3FEFEFF7F95E50029C7042FC40631C20026BE5F7BD7F9
-      FAFDCED6F32146C80732C20732C20732C20732C2020DA4FF00FF00009A0321CB
-      0335F50434F00434EB0534E6224AE5EFF2FDFFFFFFFFFFFF7E95E60029C80024
-      C25F7AD7F9FAFEFFFFFFFFFFFF4464D10732C20732C20732C20732C2041FB300
-      009A00009A0431E90335FA0335F60434F10434EC002DE64164EAEBEEFCFFFFFF
-      FFFFFF718AE35875DCF9FAFEFFFFFFFCFCFE6781D9022CC00732C20732C20732
-      C20732C2072FC000009A00039E0737F30839FB0537FB0335F70434F20434ED00
-      28E64063EAEAEEFDFFFFFFFDFDFFFCFCFFFFFFFFFBFBFE6781DA0027BE0531C2
-      0732C20732C20732C20732C20732C200039D010DAC1241FB1E4AFB0C3CFB0335
-      FB0335F80435F30434EE0027E7385EEBE9EDFDFFFFFFFFFFFFF8F9FE5F7CDF00
-      25C50631C30732C20732C20732C20732C20732C20732C2020DA4020EAD224EFB
-      456AFC204CFB0335FB0335FB0335F90333F50029EF5272F1ECF0FDFFFFFFFFFF
-      FFF8F9FE718BE5002ACD0430CA0732C50732C20732C20732C20732C20732C202
-      0DA400039F2852F86785FD3E65FC0738FB0335FB0234FB002AFA5D7CF9F9FAFF
-      FFFFFFF4F6FEEEF1FDFFFFFFFFFFFF7E96E8002ACE0430CB0732C60732C30732
-      C20732C20732C200039D00009A2048F37792FD6B88FD1946FB0335FB0130FB5D
-      7DFDF9FAFFFFFFFFFCFCFF5978F3395DEDEBEEFDFFFFFFFFFFFF7F96E90631D1
-      0632CC0732C80732C30732C2072FC000009A00009A112ED76B88FD9AAEFD466B
-      FC093AFB214CFBFAFBFFFFFFFFFCFCFF6482FB002AF20027EC4063EEEBEEFDFF
-      FFFFFFFFFF4466E00633D20633CD0732C90732C4041FB300009AFF00FF0511B2
-      456AFCA8B9FE8FA5FD2E58FC0835FB92A7FDF1F4FF6583FD002AFB0234F90435
-      F40028ED4064EFE6EBFCABBAF5113ADE0633D80633D30633CF0632C9020DA4FF
-      00FFFF00FF00009A1B3DE57A94FDBFCCFE89A1FD2A54FC0637FB2652FC0030FB
-      0234FB0335FB0335FA0335F6002DF01F4AEE0A39E70130E20533DE0533D90633
-      D40526BF00009AFF00FFFF00FFFF00FF0108A72F56F792A8FDCDD7FE97ACFD45
-      6AFC1745FB0637FB0335FB0335FB0335FB0335FA0335F70434F20535ED0535E8
-      0534E40533DF0530D301079FFF00FFFF00FFFF00FFFF00FF00009A0717BA3A61
-      FC95AAFDCFD8FEB6C4FE7A94FD456AFC2752FC1745FB103FFB103FFB1543FB1B
-      48F91A46F40D3BEF0434E90533DF0210A900009AFF00FFFF00FFFF00FFFF00FF
-      FF00FF00009A0717BA3158F7839CFDC0CCFECDD7FEB8C6FE99ADFD7E97FD6C89
-      FD6583FD607FFC5073FC2E58FA0F3DF40431E60210AB00009AFF00FFFF00FFFF
-      00FFFF00FFFF00FFFF00FFFF00FF00009A0209A81F40E65073FC819AFDA1B4FE
-      AEBEFEA9BAFE9AAEFD839CFD6281FD3860FC1644F90529D90107A200009AFF00
-      FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF00009A07
-      13B41733DA2C53F73A61FB4066FC3961FC2A54F81741F00826D2010DAD00009A
-      FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
-      FFFF00FFFF00FFFF00FF00009A00009A0105A0020EB1010DB00003A000009A00
-      009AFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+      36040000424D3604000000000000360000002800000010000000100000000100
+      2000000000000004000064000000640000000000000000000000000000000000
+      0000000000000000000000000000503E2C03503E2CD3503E2CFF503E2CFF503E
+      2C8B000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000503E2C14503E2CFF503E2CFF503E2CFF503E
+      2CFF000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000503E2C14503E2CFF503E2CFF503E2CFF503E
+      2CFF000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000503E2C14503E2CFF503E2CFF503E2CFF503E
+      2CFF000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000503E2C14503E2CFF503E2CFF503E2CFF503E
+      2CFF000000000000000000000000000000000000000000000000503E2C03503E
+      2C14503E2C14503E2C14503E2C14503E2C3B503E2CFF503E2CFF503E2CFF503E
+      2CFF503E2C14503E2C14503E2C14503E2C14503E2C1200000000503E2CD3503E
+      2CFF503E2CFF503E2CFF503E2CFF503E2CFF503E2CFF503E2CFF503E2CFF503E
+      2CFF503E2CFF503E2CFF503E2CFF503E2CFF503E2CFF503E2C64503E2CFF503E
+      2CFF503E2CFF503E2CFF503E2CFF503E2CFF503E2CFF503E2CFF503E2CFF503E
+      2CFF503E2CFF503E2CFF503E2CFF503E2CFF503E2CFF503E2C85503E2CFF503E
+      2CFF503E2CFF503E2CFF503E2CFF503E2CFF503E2CFF503E2CFF503E2CFF503E
+      2CFF503E2CFF503E2CFF503E2CFF503E2CFF503E2CFF503E2C83503E2C8B503E
+      2CFF503E2CFF503E2CFF503E2CFF503E2CFF503E2CFF503E2CFF503E2CFF503E
+      2CFF503E2CFF503E2CFF503E2CFF503E2CFF503E2CF9503E2C38000000000000
+      0000000000000000000000000000503E2C14503E2CFF503E2CFF503E2CFF503E
+      2CFF000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000503E2C14503E2CFF503E2CFF503E2CFF503E
+      2CFF000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000503E2C14503E2CFF503E2CFF503E2CFF503E
+      2CFF000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000503E2C14503E2CFF503E2CFF503E2CFF503E
+      2CFF000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000503E2C12503E2CFF503E2CFF503E2CFF503E
+      2CF9000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000503E2C64503E2C85503E2C83503E
+      2C38000000000000000000000000000000000000000000000000
     }
-    OnClick = bbDeleteClick
-    TabOrder = 7
+    OnClick = btnAddKeyClick
+  end
+  object lblKeysEncrypted: TLabel
+    Left = 97
+    Height = 32
+    Top = 40
+    Width = 496
+    Alignment = taCenter
+    AutoSize = False
+    Caption = 'lblKeysEncrypted'
+    Font.Color = clBlack
+    Font.Height = -16
+    Font.Name = 'Tahoma'
+    Font.Style = [fsBold]
+    ParentColor = False
+    ParentFont = False
+    WordWrap = True
   end
-  object bbUpdatePassword: TBitBtn
-    Left = 382
-    Height = 38
+  object btnLock: TSpeedButton
+    Left = 25
+    Height = 64
     Top = 8
-    Width = 159
-    Caption = 'Password'
+    Width = 64
     Font.Color = clWindowText
     Font.Height = -13
     Font.Name = 'Tahoma'
     Font.Style = [fsBold]
-    Glyph.Data = {
-      76060000424D7606000000000000360400002800000018000000180000000100
-      0800000000004002000000000000000000000001000000010000000000000101
-      0100020202000303030004040400050505000606060007070700080808000909
-      09000A0A0A000B0B0B000C0C0C000D0D0D000E0E0E000F0F0F00101010001111
-      1100121212001313130014141400151515001616160017171700181818001919
-      19001A1A1A001B1B1B001C1C1C001D1D1D001E1E1E001F1F1F00202020002121
-      2100222222002323230024242400252525002626260027272700282828002929
-      29002A2A2A002B2B2B002C2C2C002D2D2D002E2E2E002F2F2F00303030003131
-      3100323232003333330034343400353535003636360037373700383838003939
-      39003A3A3A003B3B3B003C3C3C003D3D3D003E3E3E003F3F3F00404040004141
-      4100424242004343430044444400454545004646460047474700484848004949
-      49004A4A4A004B4B4B004C4C4C004D4D4D004E4E4E004F4F4F00505050005151
-      5100525252005353530054545400555555005656560057575700585858005959
-      59005A5A5A005B5B5B005C5C5C005D5D5D005E5E5E00685968007C4F7C009441
-      9400B72CB700DD15DD00F506F500FD01FD00FE00FE00FE00FE00FE00FE00FE00
-      FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00
-      FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00
-      FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00
-      FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00
-      FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00
-      FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00
-      FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00
-      FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00
-      FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00
-      FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00
-      FE00FE00FE00FE00FE00FE00FE00F008F900D517F000BD24E800A830E1007B4B
-      D0005065C1003774B7002B7DB100237FAC001F82AD001C83AD001785AE001687
-      AF001489B100128AB300108CB6000F8EB9000D91BB000C94BF000A97C3000A99
-      C5000A9AC7000B9BC8000B9CCA000C9ECC000C9FCD000DA0CE000DA1CE000EA2
-      CF0011A3CF0015A4CF0018A5CF001CA7D10021A9D1002AAAD00035AACD0035AD
-      D00035AFD30035B1D60037B5D8003AB8DB003EB9DC0040BBDD0045BEDE004CC1
-      E00055C6E3005BC8E40061CAE40066CBE3006BCCE30072D3E60078D8EB0080D8
-      EE0083D9F10085DCF40088DBF5008BDBF6008EDAF70091DAF70095DCF70097E0
-      F7009EE3F800A4E7F900A9E9F900AEE9F900B5EBF900B2EBF800919191919191
-      919191919191919191919191919191919191919191919191D5E7E8E7E3DED591
-      919191919191919191919191919191D6DDF7F8F8F7F6F4EEE6D5919191919191
-      919191919191D7DADEF8F8F6F7F6EDF1F8F1E69191919191919191919191DADE
-      DFFAFAF8F7F7E9EDF7F7F8EB91919191919191919191DDE5E3FCFCFAFAEEE0E9
-      F3F7F7F7DC919191919191919191DEE7E4FEFEFCFCEDC5E0EFF7F6F6DC919191
-      919191919191DEEAE7FEFEFEFDFBC4C4F5F7F6F6DC919191919191919191E3EC
-      E9FEFEFEFEFEE0C3F9F7F6F6DC919191919191919191E3E9E3F8F8F1F1F8FBFB
-      FCFAF7F6DC919191919191919191DCEAEAE0E1E9E5E3DEE4EBF2FAF9DC919191
-      919191919191DBF3EEC5C5EFF3EBE5DDD9D6E6F5DC91919191919191919191D5
-      E8EDF1FAF6F0EAE4DAD1D2DBDC919191919191919191919191DBE8F0F3F3F3E4
-      D0CFE4D8DC919191919191919191919191919191D5DEE4DED2CFD4D491919191
-      91919191919191919191919191919191D2CE9191919191919191919191919191
-      91C8C89191919191D2CE919191919191919191919191919191D9D09191919191
-      D2CE919191919191919191919191919191E6E39191919191D2CE919191919191
-      919191919191919191E0F3CE91919191D2CE9191919191919191919191919191
-      9191EFF6E1C9C8CDD9CC91919191919191919191919191919191C9EDF9F3F3EB
-      DC91919191919191919191919191919191919191CBE0E1CF9191919191919191
-      9191919191919191919191919191919191919191919191919191
-    }
-    OnClick = bbUpdatePasswordClick
+    OnClick = btnLockClick
     ParentFont = False
-    TabOrder = 1
   end
-  object bbExportAllWalletKeys: TBitBtn
-    Left = 30
+  object btnChangePassword: TBitBtn
+    Left = 228
     Height = 36
-    Top = 425
-    Width = 225
-    Caption = 'Export all Wallet Keys to a file'
+    Top = 426
+    Width = 193
+    Anchors = [akLeft, akBottom]
+    Caption = 'Change Password'
     Glyph.Data = {
-      F6060000424DF606000000000000360000002800000018000000180000000100
-      180000000000C0060000120B0000120B00000000000000000000FF00FFFF00FF
-      FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
-      FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
-      00FFFF00FFFF00FF019ACF019ACF019ACF019ACFFF00FFFF00FFFF00FFFF00FF
-      FF00FFFF00FFFF00FFFF00FFFF00FFFF00FF0C8518FF00FFFF00FFFF00FFFF00
-      FFFF00FFFF00FFFF00FFFF00FF0D9FD18BD4EE6BD3F845C0ED28B0E0019ACF01
-      9ACF019ACF019ACFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF0C85180C8518
-      FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF069CD076C8E5A9E9FE6DD8
-      FF75DBFF77DCFF77DBFF63D1F930B3E3029BD0019ACF019ACF019ACF019ACFFF
-      00FF0C85181399220C8518FF00FFFF00FFFF00FFFF00FFFF00FFFF00FF019ACF
-      34AFD9BCE9F86ED8FF6FD8FE70D8FE70D8FE71D8FF0C85180C85180C85180C85
-      180C85180C85180C85180C85181DAC31139A220C8518FF00FFFF00FFFF00FFFF
-      00FFFF00FF019ACF1FA9D68FD3EB97E4FF6FD9FE71D9FE71D9FE71D9FE0C8518
-      57E38851DD7E4AD77443D0693BC95E34C1522BBA4725B33C1EAE33149B230C85
-      18FF00FFFF00FFFF00FFFF00FF019ACF31B1DC49B7DEBDEEFB71DDFE77DEFE77
-      DEFE77DEFE0C85185EE89059E48953DE804CD87645D16C3DCA6035C2542DBB49
-      26B53F1FAF35149B250C8518FF00FFFF00FFFF00FF019ACF52C2E71DA7D5ADE2
-      F38FE8FF7CE2FE7CE3FE7CE3FE0C851861EB955FE9925AE58B54DF824DD97846
-      D26D3ECB6237C4562FBD4C27B64021B037159B250C8518FF00FFFF00FF019ACF
-      60CAEF1FA8D85EC1E1C2E6ED8ACEE08FCFE18ECFE10C851861EB9561EB955FEA
-      935CE58D56E0844FDB7A48D47040CD6538C65931BF4D1DA3320C8518FF00FFFF
-      00FFFF00FF019ACF65CFF53EB7E52CA9D4C5EFF8ACF3FEA5F2FFA5F2FF0C8518
-      61EB9561EB9561EB9561EB945CE68E57E18650DC7C49D57242CE6727AD410C85
-      18FF00FFFF00FFFF00FFFF00FF019ACF69D1F855C4F32A9CC673CBE7D6FEFDB1
-      FBFDB2FBFD0C85180C85180C85180C85180C85180C85180C85180C851852DD7F
-      32B6500C851898FAFF019ACFFF00FFFF00FFFF00FF019ACF77D5FC5CC8FB748E
-      A224A8D5B9E7F3D5F5F9D5F6F9D6F6FADCFAFBCDFDFCB9FCFCAFFAFCB0FAFCB1
-      FAFC0C85183ABE5C0C85189FFCFFA4FFFF43C1E2019ACFFF00FFFF00FF019ACF
-      8BDBFF5FCDFFB7898973C3DD18A2D218A2D216A2D215A1D21AA4D391D7EBEBFE
-      FDDBFDFCC5FBFBC2FBFB0C85180C851883E4F3B6FDFFBAFFFFB5FCFD019ACFFF
-      00FFFF00FF019ACF99E2FF67D3FFB88989FEF5ECFDF3EBF0EFEAE5EBE8D6E5E6
-      A4D2E025A6D34DB9DDE5F8FBF5FDFCEBFCFB0C8518C4FBFF9CE4F2DAFEFFD9FE
-      FFE3FFFFADE9F5019ACFFF00FF019ACF9FE9FF70DCFFB88989FEF3E9FFF2E6FE
-      F3E9FEF3E9FEF3E9FEF3E9D4E4E439ADD422A5D49DD8ECF1F9FBEEEFEFE9FDFF
-      CEEEF7F8FFFFF7FFFFFEFFFFE9F9FD019ACFFF00FF019ACFA7EFFF76E5FFB889
-      89FFF2E5FFF0E2FFF2E5FFF2E5FFF2E5FFF2E5FFF2E5EAEBE38EC9DA44B0D501
-      9ACF019ACF019ACF019ACF019ACF019ACF019ACF019ACF019ACFFF00FF019ACF
-      ABF6FF7EEDFFB88989FFF0E2FFEFDFFFF0E2FFF0E2FFF0E2FFF0E2FFF0E2FEEE
-      E0FBECDEFAEBDEF6E6D9B8898993F7FF019ACFFF00FFFF00FFFF00FFFF00FFFF
-      00FFFF00FF019ACFC7FFFF82F5FFB88989FFEEDFFFECDBFFEEDFFFEEDFFFEEDF
-      FFEEDFF9E8D9DECCC1D9CABDCFBDB4C8B3ACB88989B5FFFF019ACFFF00FFFF00
-      FFFF00FFFF00FFFF00FFFF00FF019ACFA4E0F0A0FDFFB88989FFECDBFFEBD8FF
-      ECDBFFECDBFFECDBFFECDBF5E2D2C4ABA7C2A8A5BBA39FC2AFA9B88989019ACF
-      FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF019ACFECFFFFB889
-      89FFEBD8FFEAD5FFEBD8FFEBD8FFEBD8FFEBD8FFEBD8D9C8C5FEFEFDFEF6EFDE
-      C9C0B88989FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
-      FF00FF019ACFB88989FFE9D5FFE8D3FFE9D5FFE9D5FFE9D5FFE9D5FFE9D5C6AD
-      A9FEF8F2E8D4CACD9999FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
-      00FFFF00FFFF00FFFF00FFFF00FFB88989FFE7D1FFE7D0FFE7D1FFE7D1FFE7D1
-      FFE7D1E7CEBFD3BFB9E8D5CCCD9999FF00FFFF00FFFF00FFFF00FFFF00FFFF00
-      FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFB88989FFE6CFFFE6CFFF
-      E6CFFFE6CFFFE6CFFFE6CFD5BBB2E0CCC5CD9999FF00FFFF00FFFF00FFFF00FF
-      FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFB889
-      89B88989B88989B88989B88989B88989B88989B88989B88989FF00FFFF00FFFF
-      00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+      76060000424D7606000000000000360400002800000018000000180000000100
+      0800000000004002000000000000000000000001000000010000FF00FF005251
+      5100565758005A5958005B5D5D005D5E5E006361610066666600696969006C6B
+      6B0073706F0072707000747271000E80AA001788AF000B86B2000C85B000098A
+      B700078CBA00198EB7000E91BE001E94BC002898BA003E99BB000493C4000997
+      C7000A9ECF00229BC20035A0C30030AACA0032AACE003DAACC003FB0CB0036A9
+      D0003BB1D9003DBDDA0039B8DE0029BBE0004DBBD90068B0CA0019C7F1001BD4
+      FE002FC6E7003ECDE9002CD3F9002ED8FE003CE0FE0054C0D40059C4D70059C2
+      DD006FC2D6007CC0D50078C1D80049DDFE0054DFFE0061C6E5006CD4EE0064D9
+      E90076DFE9007DDFE90055E0FF0058E0FE006BE3F40063E6FE0060ECFE0075E2
+      FA0077E6FF007BE8FF0071F2FE0088828000928E8C0096908F00969291009794
+      94009E969400A09C9B00A19F9E00ACA09E00A6A2A100A6A4A400ADA5A300AAA5
+      A400ABA8A800ADAAA900B0A5A300B2A7A500B2ABAB00B4ABA900BBB1AE00BEB1
+      AF00BAB3B200BAB4B200BEB6B400C4B8B600C1BCBB0083DFE9008ADAEB0094DF
+      E90089DDF100A4DFEA009AE2F40095EBFD0095EDFE009EEDFF0084F3F90080F5
+      FC008FF6FB0083F8FE0093F2FE0097F9FE0094FDFE0099FFFE009EFFFE00AAEF
+      FD00B4EEF300A4FFFE00A8F9FE00ADFBFE00AAFFFE00B6F1FF00BCF2F800B3F9
+      FF00B3FFFE00B9FFFE00C7C2C100C7C6C600CCC4C200CAC7C600CFCCCC00D1C7
+      C500D4CBC900D1CDCD00D5CFCE00D8D0CE00D7D1D000D9D5D400DCD7D600DFD8
+      D600E3DEDD00C3DFEA00CCF6FF00C9FFFE00CFFFFF00D1F7FF00DBF8FE00DFFF
+      FF00E7E3E200E9E5E500ECE9E900EFEEED00F1EBEA00F1EFEE00E5FFFF00F3F1
+      F100F6F2F000F8F5F300F8F5F400F0F7FA00F5FFFF00FBF8F800FAFFFF00FFFE
+      FE00000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0007070707000000000000000000000000000000000000000746967E07000000
+      0000000000000000000000000000000D085E489A5E080D0D0000000000000000
+      00000000000D0D2626075E48A1071F130D0D000000000000000000000D163940
+      3F35075E4C93070707100D000000000000000000123A6B402E353D075E519580
+      4E0707070707000000000000123A6B402E293D42075E4EA19289858281550700
+      00000000123A6B402E292D4266075E4C9689865A475D4D0700000000123A6B40
+      2E292D3C6671077D928A7D0A0A58580700000000123A6B402E292D3C4371079A
+      958007035151550700000000123A6D6C6667778C8F90079A860701574C024A07
+      0000000012727860311E1B151C3407A17E0B534C000445070000000011322023
+      2A282C36426407539A8882040404570700000000103169402E292D3643716207
+      5393825A515A5A0700000000123A6B402E292D3C436662370707070708070700
+      00000000123A6B402E292D3C43663837222117000000000000000000123A6B40
+      2E292D3C436638231A180D000000000000000000123A6B402E292D3C43663822
+      1A180D000000000000000000123A6B402E292D3C436638231A180D0000000000
+      00000000123B757975756F6F6F6F6A3E25190D000000000000000000128BA190
+      8E79736F6F6F6F6D442B0D00000000000000000012279D9D908E796F6F6F6F6F
+      691E0D000000000000000000001214333363615F3B3A2F2F0E0D000000000000
+      0000000000000014121212121212121200000000000000000000
     }
-    OnClick = bbExportAllWalletKeysClick
-    TabOrder = 10
+    OnClick = btnChangePasswordClick
+    TabOrder = 4
   end
-  object bbImportKeysFile: TBitBtn
-    Left = 264
-    Height = 36
-    Top = 424
-    Width = 209
-    Caption = 'Import a Wallet Keys File'
-    Glyph.Data = {
-      F6060000424DF606000000000000360000002800000018000000180000000100
-      180000000000C0060000120B0000120B00000000000000000000FF00FFFF00FF
-      FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
-      FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
-      00FFFF00FFFF00FF019ACF019ACF019ACF019ACFFF00FFFF00FFFF00FFFF00FF
-      FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
-      FFFF00FFFF00FFFF00FFFF00FF0D9FD18BD4EE6BD3F845C0ED28B0E0019ACF01
-      9ACF019ACF019ACFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
-      FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF069CD076C8E5A9E9FE6DD8
-      FF75DBFF77DCFF77DBFF63D1F930B3E3029BD0019ACF019ACF019ACF019ACFFF
-      00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF019ACF
-      34AFD9BCE9F86ED8FF6FD8FE70D8FE70D8FE71D8FF74DBFF7ADEFF79DDFF73D9
-      FF5CCCF522ACDD019ACF019ACF019ACFFF00FFFF00FFFF00FFFF00FFFF00FFFF
-      00FFFF00FF019ACF1FA9D68FD3EB97E4FF6FD9FE71D9FE71D9FE71D9FE71D9FE
-      71D9FE71D9FE73DAFE76DCFF7BDFFF7ADEFF78DCFF77DCFF019ACFFF00FFFF00
-      FFFF00FFFF00FFFF00FFFF00FF019ACF31B1DC49B7DEBDEEFB71DDFE77DEFE77
-      DEFE77DEFE77DEFE77DEFE77DEFE77DEFE76DEFE76DEFE76DEFE78DFFF7CE1FF
-      65D2F8019ACFFF00FFFF00FFFF00FFFF00FFFF00FF019ACF52C2E71DA7D5ADE2
-      F38FE8FF7CE2FE7CE3FE7CE3FE7CE3FE7CE3FE7CE3FE7CE3FE7CE3FE7CE3FE7C
-      E3FE7DE4FE7DE3FE5ED1F3019ACFFF00FFFF00FFFF00FFFF00FFFF00FF019ACF
-      60CAEF1FA8D85EC1E2BBF4FE7DE7FE82E8FE81E8FE81E8FE81E8FE81E8FE81E8
-      FE81E8FE81E8FE81E8FE82E8FE84E9FE5ED3F18DEEFF019ACFFF00FFFF00FFFF
-      00FFFF00FF019ACF65CFF53EB7E529ACD8BFEEF88DEFFF85EDFF85EDFF85EDFF
-      85EDFF86EDFF86EDFF86EDFF86EDFF86EDFF87EDFF89EEFF65D9F396F5FF019A
-      CFFF00FFFF00FFFF00FFFF00FF019ACF69D1F855C4F31FA7D773CBE7C5FCFF93
-      F7FF93F7FF92F6FF8DF4FF89F3FF89F2FF8BF2FF8BF2FF8BF2FF8BF2FF8EF3FF
-      6ADEF395F8FF98FAFF019ACFFF00FFFF00FFFF00FF019ACF77D5FC5CC8FB3EB8
-      E920A7D5B6E6F3D0F4FAD1F5FAD2F6FAD5F9FCB9FBFE9BF8FF8FF6FF91F6FF92
-      F6FF93F7FF6BD0B70C85188BEAE0A4FFFF43C1E2019ACFFF00FFFF00FF019ACF
-      8BDBFF5FCDFF64CDFE2CAFE30D9FD30FA0D310A0D310A0D317A3D38ED7ECE2FD
-      FEC3FAFFA5F8FFA3F8FF84DDCF0C851838B5570C8518ABF3EBB5FCFD019ACFFF
-      00FFFF00FF019ACF99E2FF67D3FF6DD4FE6CD4FE69D1FE64CEFB61CDF95BC9F5
-      48BEEB17A3D54BB8DDDFF7FBE8FCFFB1E7DD0C85184ACE7361EB9541C1640C85
-      18D6F6F0ADE9F5019ACFFF00FF019ACF9FE9FF70DCFF76DDFE76DDFE76DDFE75
-      DCFE74DCFE73DCFE73DBFE61CEF61CA8D91CA5D58CCED70C851842C5665BE68C
-      59E1895DE78F3EBD600C8518DBF1EF019ACFFF00FF019ACFA7EFFF76E5FF7CE5
-      FF7CE5FF7CE5FF7CE5FF7DE5FF7DE5FF7DE5FF7DE3FF72DDFB40B8D20C85182D
-      AD474AD47250D97B55DE8359E1885AE38B33AF510C85180197C3FF00FF019ACF
-      ABF6FF7EEDFF85ECFF85ECFF85ECFF85ECFF84ECFF80ECFF7CECFF7DECFF7EEC
-      FF0C85180C85180C85180C851840C7634FDA7A55DF830C85180C85180C85180C
-      8518FF00FF019ACFC7FFFF82F5FF8FF5FF8FF5FF8FF5FF8EF5FF8DF4FFA0FDFF
-      B7FFFFAFFFFFAEFFFFA6F9F4A5FBF8A3FCFA4CB07732B74F48D6704AD3720C85
-      18FF00FFFF00FFFF00FFFF00FF019ACFA4E0F0A0FDFF8AFCFF90FCFF90FCFF90
-      FCFF99FDFF86E8F5019ACF019ACF019ACF019ACF019ACF019ACF0486642CB347
-      41D16636BC540C8518FF00FFFF00FFFF00FFFF00FFFF00FF019ACFECFFFFBCFF
-      FFBCFFFFBCFFFFC0FFFF9DF5FB019ACFFF00FFFF00FFFF00FFFF00FFFF00FFFF
-      00FF0C85182BB74538C9580C8518FF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
-      FF00FF019ACF019ACF019ACF019ACF019ACF019ACFFF00FFFF00FFFF00FFFF00
-      FFFF00FFFF00FFFF00FF0C851828BB4126B13E0C8518FF00FFFF00FFFF00FFFF
-      00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
-      FF00FFFF00FFFF00FFFF00FFFF00FF0C851814A4241CAE310C8518FF00FFFF00
-      FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
-      00FFFF00FFFF00FFFF00FFFF00FFFF00FF0C85180C85180C96170D991A0C8518
-      FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
-      FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF0C85180C85180C85180C85180C
-      8518FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+  object ilIcons: TImageList
+    Height = 64
+    Width = 64
+    left = 489
+    top = 136
+    Bitmap = {
+      4C69020000004000000040000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000C6C6A909CDCDAE29CEC9AF73CDCBAFC0CDC9ADE4CEC9
+      ADFACDC9ADFECDC9ADFEC6C0A2FEBEB797FEBEB797FEBEB797FEBEB797FEC1B9
+      9AFAC1BB9BEAC2BB9B97C3B99B33C8C8A30EFFFFFF0100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00007F7F7F02D1CAB027CDC8AD8CCDC9ADEFCECAAEFFCECAAEFFCECAAEFFCECA
+      AEFFCECAAEFFCECAAEFFC6C0A2FFBFB897FFBFB897FFBFB897FFBFB897FFBFB8
+      97FFBFB897FFBFB897FFC0B998F9C2BA9BB0C0BA9A56BFBF9F08000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000000000000000000FFFF
+      FF01CFC9AE56CECAAEC1CDC9ADF8CECAAEFFCECAAEFFCECAAEFFCECAAEFFCECA
+      AEFFCECAAEFFCECAAEFFC6C0A2FFBFB897FFBFB897FFBFB897FFBFB897FFBFB8
+      97FFBFB897FFBFB897FFBFB897FFBFB897FFC0B999F3C1BC9A96C9BFAA180000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000000000000000000CFCC
+      B155CEC9AEE6CDC9ADFECECAAEFFCECAAEFFCECAAEFFCECAAEFFCECAAEFFCECA
+      AEFFCECAAEFFCECAAEFFC6C0A2FFBFB897FFBFB897FFBFB897FFBFB897FFBFB8
+      97FFBFB897FFBFB897FFBFB897FFBFB897FFBFB897FFBFB897FAC1BC9A99BFBF
+      BF04000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000CBCBAE23CDC9
+      AEE3CECAAEFFCECAAEFFCECAAEFFCECAAEFFCECAAEFFCECAAEFFCECAAEFFCECA
+      AEFFCECAAEFFCECAAEFFC6C0A2FFBFB897FFBFB897FFBFB897FFBFB897FFBFB8
+      97FFBFB897FFBFB897FFBFB897FFBFB897FFBFB897FFBFB897FFC0B999ECC6C0
+      A356000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000000000000000000000C6C6A909CDCAADB3CDC9
+      ADFDCECAAEFFCECAAEFFCECAAEFFCECAAEFFCDCAADF8CDCAADBFCDC9AD6DD2C9
+      AE39CFC9AF30CFC9AF30CDC9AF43C6BD9F55C6BD9F55C5BFA15DC6C0A383C5BF
+      A0BAC1BB9AE5BFB897FABFB897FFBFB897FFBFB897FFBFB897FFBFB897FFC1BB
+      99A9C1C1A3190000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000AAAAAA03CEC9AC73CECAADF1CECA
+      AEFFCECAAEFFCECAAEFFCDC9ADFECEC9ADD1CECBAD5EFFFF7F02000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000B2B2990AC4BE9D7EBFB898E5BFB897FFBFB897FFBFB897FFBFB897FFBFB9
+      98F9C0BA9B52AAAAAA0300000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000D3CAAF1DCECAAEC1CECAAEFFCECA
+      AEFFCECAAEFFCECAAEFFCDCAAED0CDC9AE39FFFF7F0200000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000BFBF7F04C2BB9A6DBFB898EEBFB897FFBFB897FFBFB897FFBFB8
+      97FFC1BB9CABC3B4961100000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000CECAAE49CEC9AEE1CECAAEFFCECA
+      AEFFCECAAEFFCDCAADF2CECBAE69B6B6B6070000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000C3C3A511C0BB9BC0BFB897FDBFB897FFBFB897FFBFB8
+      97FFC1BB9BE9BCBC971B00000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000CEC9AE5FCDC9ADF2CECAAEFFCECA
+      AEFFCECAAEFFCEC9ADD8CECAAF3A000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000C4BE9F93BFB897F9BFB897FFBFB897FFBFB8
+      97FFC1B99AFAC1B89E1D00000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000CFCBAE6CCECAAEFBCECAAEFFCECA
+      AEFFCECAAEFFCECAAEC1C8C8A921000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000C8C0A162BFB897F4BFB897FFBFB897FFBFB8
+      97FFBFB897FFC3BB991E00000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000FFFFFF01CCC8AC75CECAAEFFCECAAEFFCECA
+      AEFFCECAAEFFCDCAADB3CFCFAF10000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000C5C19E3ABFB796F0BFB897FFBFB897FFBFB8
+      97FFBFB897FFBDB79A2B00000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000FFFFFF01CCC8AC75CECAAEFFCECAAEFFCECA
+      AEFFCECAAEFFCDCAADB3CFCFAF10000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000C5C19E3ABFB796F0BFB897FFBFB897FFBFB8
+      97FFBFB897FFBDB79A2B00000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000FFFFFF01CCC8AC75CECAAEFFCECAAEFFCECA
+      AEFFCECAAEFFCDCAADB3CFCFAF10000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000C5C19E3ABFB796F0BFB897FFBFB897FFBFB8
+      97FFBFB897FFBDB79A2B00000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000FFFFFF01CCC8AC75CECAAEFFCECAAEFFCECA
+      AEFFCECAAEFFCDCAADB3CFCFAF10000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000C5C19E3ABFB796F0BFB897FFBFB897FFBFB8
+      97FFBFB897FFBDB79A2B00000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000FFFFFF01CCC8AC75CECAAEFFCECAAEFFCECA
+      AEFFCECAAEFFCDCAADB3CFCFAF10000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000C5C19E3ABFB796F0BFB897FFBFB897FFBFB8
+      97FFBFB897FFBDB79A2B00000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000FFFFFF01CCC8AC75CECAAEFFCECAAEFFCECA
+      AEFFCECAAEFFCDCAADB3CFCFAF10000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000C5C19E3ABFB796F0BFB897FFBFB897FFBFB8
+      97FFBFB897FFBDB79A2B00000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000FFFFFF01CCC8AC75CECAAEFFCECAAEFFCECA
+      AEFFCECAAEFFCDCAADB3CFCFAF10000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000C5C19E3ABFB796F0BFB897FFBFB897FFBFB8
+      97FFBFB897FFBDB79A2B00000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000FFFFFF01CCC8AC75CECAAEFFCECAAEFFCECA
+      AEFFCECAAEFFCDCAADB3CFCFAF10000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000C5C19E3ABFB796F0BFB897FFBFB897FFBFB8
+      97FFBFB897FFBDB79A2B00000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000FFFFFF01C1C6B075AFC0B6FF9CB9BCFF90B5
+      BFFF90B5BFFF80AFC3CD2B92D8631A8DDF581A8DDF581A8DDF581A8DDF581A8D
+      DF581A8DDF581A8DDF581A8DDF581A8DDF581A8DDF581A8DDF581A8DDF581A8D
+      DF581A8DDF581A8DDF581A8DDF584C9DCC7E84A7B0F586A8AFFF86A8AFFF8BAA
+      AEFF98AEA8FF93ADA83200000001000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000198DE1801E88D7EB2289D5FF2088D6FF1F88
+      D6FF1F88D6FF1C87D7FB1684D8F41684D8F31684D8F31684D8F31684D8F31684
+      D8F31684D8F31684D8F31684D8F31684D8F31684D8F31684D8F31684D8F31684
+      D8F31684D8F31684D8F31684D8F31784D7F61D86D5FE1E87D5FF1E87D5FF1E87
+      D5FF2087D4FF1886D8ED178ADCC22AAAD4060000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000001A8ADE9C1684D8FD1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FE188ADCB10000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000099FF051785DAF21684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1686D9D72A7FD40600000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000001F94E918198ADEF81684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8DF1B88DA1C00000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000249AEC1C1D95E7F8198BDEFF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8E0178BE02100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000249AEC1C1E96E8F81E94E6FF1889DDFF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8E0178BE02100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000249AEC1C1E96E8F81F96E8FF1D93E5FF1888DBFF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8E0178BE02100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000249AEC1C1E96E8F81F96E8FF2298EAFF1D92E4FF1787DAFF1684
+      D8FF1684D8FF1684D8FF1684D8FF1683D7FF1681D3FF1681D3FF1681D3FF1681
+      D3FF1681D3FF1681D3FF1681D3FF167FD0FF0F5286FF104975FF167BC8FF145E
+      97FF092E4BFF1776C0FF1683D7FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8E0178BE02100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000249AEC1C1E96E8F82499EBFF37A5F6FF279BEDFF1D91E4FF1888
+      DCFF1684D8FF1684D8FF1682D5FF1262A0FF0E4B79FF0E4977FF0E4977FF0E49
+      77FF0E4977FF0E4977FF0E4977FF0E4773FF092B47FF0A2B46FF0E4672FF092B
+      46FF051C2DFF0E456FFF115B94FF1574BCFF1683D6FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8E0178BE02100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000249AEC1C1E96E8F8259AECFF3DA8F9FF299CEEFF1F96E8FF1D93
+      E5FF1888DCFF1684D7FF1465A4FF092A43FF041928FF041827FF041827FF0418
+      27FF041827FF041827FF041827FF041827FF041827FF041827FF041827FF0418
+      27FF041827FF041928FF061F32FF092F4DFF146AACFF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8E0178BE02100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000249AEC1C1E96E8F8259AECFF3DA8F9FF299CEEFF1F96E8FF1F96
+      E8FF1D93E5FF177CC7FF0E3C61FF082135FF082137FF082035FF082137FF0821
+      37FF082137FF082137FF082137FF082137FF082137FF082137FF082137FF0820
+      35FF082034FF061B2CFF041827FF041827FF0B3454FF1683D6FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8E0178BE02100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000249AEC1C1E96E8F8259AECFF3DA8F9FF299CEEFF1F96E8FF1F96
+      E8FF1F96E8FF1D8FDFFF1A7FCCFF197DC9FF197DC9FF197DC9FF177DCCFF177D
+      CCFF167ECDFF177DCCFF197DC9FF197DC9FF197DC9FF197DC9FF197DC9FF197D
+      C9FF1679C4FF104D7DFF041827FF041827FF07253CFF1683D6FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8E0178BE02100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000249AEC1C1E96E8F8259AECFF3DA8F9FF299CEEFF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1B8FE1FF1786D9FF1684D8FF1683D6FF186BACFF1962
+      9BFF19629BFF1779C5FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1683D6FF10568CFF041827FF041827FF07253BFF1683D6FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8E0178BE02100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000249AEC1C1E96E8F8259AECFF3DA8F9FF299CEEFF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1B8FE1FF1786DAFF167CCAFF072338FF0418
+      27FF051A2AFF156DB0FF1684D7FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1683D6FF10558AFF041827FF041827FF07253BFF1683D6FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8E0178BE02100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000249AEC1C1E96E8F8259AECFF3DA8F9FF299CEEFF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1C91E3FF1772BAFF041928FF0418
+      27FF071F32FF1569AAFF1777C1FF1777C2FF1678C3FF187AC7FF187BC8FF187B
+      C8FF1670B6FF0D3A5EFF041827FF041827FF07253BFF1683D6FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8E0178BE02100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000249AEC1C1E96E8F8259AECFF3DA8F9FF299CEEFF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1D6CA7FF041828FF0417
+      25FF051929FF082740FF082A44FF082A44FF082A45FF082B46FF092C47FF092C
+      47FF082841FF051C2DFF041827FF041827FF0A3150FF1683D6FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8E0178BE02100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000249AEC1C1E96E8F8259AECFF3DA8F9FF299CEEFF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1C5C89FF051A29FF0418
+      27FF041624FF041826FF041827FF041827FF041827FF041827FF041827FF0418
+      27FF041827FF041827FF041827FF062237FF1668A8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8E0178BE02100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000249AEC1C1E96E8F8259AECFF3DA8F9FF299CEEFF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF0F3B5DFF051B2AFF051A
+      29FF092B46FF0B3759FF071F33FF061D30FF0D3759FF072238FF071F33FF0C39
+      5EFF0B385BFF0D3A5FFF124E7FFF1573BBFF1683D6FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8E0178BE02100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000249AEC1C1E96E8F8259AECFF3DA8F9FF299CEEFF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF2291DEFE082437FF051B2AFF0822
+      36FF176FB1FF187FCDFF0D3555FF0D3F66FF1880D0FF0D446EFF135081FF1681
+      D3FF1683D7FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8E0178BE02100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000249AEC1C1E96E8F8259AECFF3DA8F9FF299CEEFF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF257FC1FF051C2CFF051B2AFF0D34
+      50FF1C81C8FF1C8CDDFF1873B8FF167AC6FF1683D7FF1575BFFF177DCBFF1684
+      D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8E0178BE02100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000249AEC1C1E96E8F8259AECFF3DA8F9FF299CEEFF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1C6397FF051C2BFF051B2AFF1244
+      68FF1F8AD5FF1E94E6FF1B8DDFFF1782D4FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8E0178BE02100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000249AEC1C1E96E8F8259AECFF3DA8F9FF299CEEFF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1E95E7FF124366FF051B2BFF051B2AFF1350
+      7BFF1F90DEFF1F96E8FF1E94E7FF1B8CDEFF1682D4FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8E0178BE02100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000249AEC1C1E96E8F8259AECFF3DA8F9FF299CEEFF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF2091DFFF092840FF051B2AFF061D2DFF155B
+      8DFF1F94E5FF1F96E8FF1F96E8FF1E95E7FF1A89DAFF1683D5FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8E0178BE02100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000249AEC1C1E96E8F8259AECFF3DA8F9FF299CEEFF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF2283C6FF082538FF051D2DFF092539FF186B
+      A6FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1D92E4FF1888DBFF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8E0178BE02100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000249AEC1C1E96E8F8259AECFF3DA8F9FF299CEEFF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F85CDFF145B8CFF125889FF155F92FF1D85
+      CEFF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1D92E5FF1889DDFF1684
+      D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8E0178BE02100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000249AEC1C1E96E8F8259AECFF3DA8F9FF299CEEFF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1D93E5FF1A8C
+      DFFF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8E0178BE02100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000249AEC1C1E96E8F8259AECFF3DA8F9FF299CEEFF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1E95
+      E7FF198BDEFF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8E0178BE02100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000249AEC1C1E96E8F8259AECFF3DA8F9FF299CEEFF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96
+      E8FF1E95E7FF1889DDFF1684D8FF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8E0178BE02100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000001D93EB1A1E96E7F82599EBFF3CA7F8FF299CEDFF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96
+      E8FF1F96E8FF1D93E5FF1888DCFF1684D8FF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1584D8E0188BDE1F00000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000003399CC052095E6E42197E9FF2C9EF0FF2399EBFF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1D92E4FF1888DCFF1684D8FF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1685D9D81F9FFF0800000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000001D93E5951F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1D93E5FF1889DCFF1684D8FF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1787DAC60000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000001E98EA191F96E7D21F96E8FF1F96E8FF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1E94E6FF1888DBFF1684D8FF1684
+      D8FF1684D8FF1684D8FF1684D8FF1989DB500000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000001E92E93B1F96E8D51F96E8FF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96
+      E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1F96E8FF1D93E6FF1787DBFF1684
+      D8FF1684D8FF1684D8FF1989DEA3007FFF040000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000000000FF011E92E7211D94E7811F95E8C31E95
+      E7F01E95E7F21E95E7F21E95E7F21E95E7F21E95E7F21E95E7F21E95E7F21E95
+      E7F21E95E7F21E95E7F21E95E7F21E95E7F21E95E7F21E95E7F21E95E7F21E95
+      E7F21E95E7F21E95E7F21E95E7F21E95E7F21E95E7F21E95E7F21C91E3F21788
+      DAEE1789DCD61A8BE258007FFF04000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000FFFFFF01CECEA915D1CBAD32CBCBAC4ACECBAD54CDCAAD58CDCAAD58CAC5
+      A858C2B99C58BFB99658BFB99658BFB99658BFB99958C0B99751C4C09C39CDCD
+      BA1AE2E2C6090000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000000000000000000D4D4
+      AA06CDCDAF43CFC9AE95CEC9ADC9CECAADEBCECAAEF7CECAAEFCCECAAFFCCAC5
+      A7FCC1BA9AFCBEB796FDBEB796FDBFB896FCBFB897FCBFB797F4C2BA9AD2C5BF
+      A0A4C6C2A471C8C1A22100000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000CCCCA528CECC
+      AC78CECAACC7CEC9AEF5CEC9AEFCCECAAEFFCECAAEFFCECAAEFFCFCBAFFFCAC5
+      A8FFC1BA9BFFBFB796FFBFB897FFBFB897FFBFB897FFBFB897FFBFB897FCBEB7
+      96F8BEB896EAC1BB9AA2C7BEA237BFBFBF040000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000FFFFFF02D4CFB930CFC9B0A8CECA
+      ADF1CECAAEFCCECAAEFFCECAAEFFCECAAEFFCECAAEFFCECAAEFFCFCBAFFFCAC5
+      A8FFC1BA9BFFBFB796FFBFB897FFBFB897FFBFB897FFBFB897FFBFB897FFBFB8
+      97FFBFB897FFBFB896F8C2BA9AB4C5C09E35FFFFFF0200000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000CCC3AA1ECFCAAE9BCEC9ADF5CECA
+      AEFFCECAAEFFCECAAEFFCCC8ABFECBC7ABFCCECAAEFBCECAAEF7CECAAEF7CAC5
+      A7F9C1B99BFBBEB696FBBEB797FBBFB896FCBFB897FDBFB797FEBFB796FFBFB8
+      97FFBFB897FFBFB897FFC0B897FCC3BC9DA2C8C8A22100000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000C6C6A909CECCAD6ACBC8ABE6CECAADFFCECA
+      AEFFCECAAEFFCECAADFBCECCB0DFCECBAEAFCECAAE88CDC9AD77CDCBAF76CBC4
+      A77BC4BC9E87C3BA9B8AC3BA9B8AC2BB9D97C3BC9BB3C2BB9BCDC0B999EFBFB8
+      97FCBFB897FFBFB897FFBFB796FFC1B898EFC4BE9D7EBFBF9F08000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000D6D1B232CFCBAEC8CECAAEFCCECAAEFFCECA
+      AEFFCDC9ADFBCCC8ABC0D3D0B75DD7D7B720C6C6A9090000000000000000FFFF
+      7F02BFBF9F08E2E2A909E2E2A909D2C3A511C4C4A023C4BC9E3DC6C0A07AC2BA
+      9BCDBFB897FFBFB897FFBFB897FFBFB897FFC1BA99CCC5BDA03E000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000BFBFBF04CECAAF74CECAADECCECAAEFFCECAAEFFCECA
+      AEFFCBC9ADD7D1CAB249E2C6C609000000000000000000000000000000000000
+      00000000000000000000000000000000000000000000FFFFFF01D2C3B411C7C2
+      A258C0BA99E2BFB897FFBFB897FFBFB796FFBFB997F5C2BD9C8F000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000C6C6A912CFCBACB1CECAAEFCCECAAEFFCDC9ADFFCBC7
+      ABFEE0DECC7ED2D2A51100000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000000000000000000C9C9
+      9F18C3BD9D9BBFB897FDBFB897FFBFB897FFBFB998FFC1BB9AC4000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000D2D2B422CDCAADD5CDC9ADFFCECAAEFFCDC9ADFFCCC8
+      A9E2E5E1D03CFFFF7F0200000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000000000000000000C6C6
+      A909C4BC9F68BFB898F6BFB897FFBFB897FFBFB998FFC0B897CF000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000D7D1B52DCECBAFDECECAAEFFCECAAEFFCECAAEF8CCC9
+      ACC0D6CBB7190000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000000000000000000FFFF
+      FF02C3C09E45C1B998E0BFB796FFBFB897FFBFB796FFC0B897CF000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000CBC6AD32CDCBAEDFCECAAEFFCECAAEFFCECAAEF8CDCA
+      ADB3C8C8A30E0000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000C5BB9C31C0B997D4BEB796FDBFB897FFBFB796FFC0B897CF000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000C6C1A332CCCAADE0CFCBAFFFCECAAEFFCECAAEF8CDCA
+      ADB3C8C8A30E0000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000C5BB9C31C0B997D4BEB795FDBFB897FFBFB897FFC0B897CF000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000C6C1A332CCCAADE0CFCBAFFFCECAAEFFCECAAEF8CDCA
+      ADB3C8C8A30E0000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000C5BB9C31C0B997D4BEB795FDBFB897FFBFB897FFC0B897CF000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000C6C1A332CCCAADE0CFCBAFFFCECAAEFFCECAAEF8CDCA
+      ADB3C8C8A30E0000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000C5BB9C31C0B997D4BEB795FDBFB897FFBFB897FFC0B897CF000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000C6C1A332CCCAADE0CFCBAFFFCECAAEFFCECAAEF8CECB
+      ADB2CCCCB20A0000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000C5BB9C31C0BA98D4BFB796FDBFB897FFBFB897FFC0B897CF000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000C6C1A332CCCAADE0D0CBAEFFD0CBAEFFD0CBADF8D0CB
+      ACAEB6B691070000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000C5BB9C31C2B997D6C1B795FDC1B896FFC1B896FFC0B998D0000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000C6C1A332CCCAADE0CDCAB0FFCCCAAFFFD0CBADFBCBCA
+      ACAE3F7FBF080000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000000000000000000FFFF
+      FF01B6B6A023C3BA969FBEB597CEBCB797E0BEB797F4BDB899CE000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000C6C1A332BCC3B0DBA6BDBAFC9BB8BBF99DB9BBF88DB5
+      BFB2389BD4120000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000FFFFFF017F7F
+      FF02A2B9B90BA8B3A22C9FAFA3439BAEA65F99AFA7A1A0B1A4AC000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000CFA68000BF4DA000BEDEA000B
+      EDEA000BEDEA000BEDEA000BEDEA000BEDEA000BEDEA000BEDEA000BEDEA000B
+      EDEA000BEDEA000BEDEA000BEDEA000BEDEA000BEDEA000BEDEA000BEDEA000B
+      EDEA000BEDEA000BEDEA030EECEE0D19E9FC0D1AEAFF0C19EAFE0C19EAFE0715
+      EBF9000CEDEC000BEDEA000CEFE9000DF4C90016F31700000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000017F7F7F02AAAAAA0399CCCC057FAAAA0C9CB0B00D000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000EF67F000CEEF6000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000EF5D50000FF03000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000FF04000CF0C6000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000BEFFE0013FE0D000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000001EFF11000EF7CF000CEFFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000FF533000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000D1AFE130617FED00010FBFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF0011F63B000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000D1AFE130819FED00719FFFF000FFAFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF0011F63B000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000D1AFE130819FED0081AFFFF0719FFFF000FF8FF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF0011F63B000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000D1AFE130819FED0081AFFFF0D1FFFFF0A1BFEFF010F
+      F5FF000CEEFF000CEEFF000CEEFF000CEEFF000CEDFF010DE9FF010CE8FF010C
+      E8FF010CE8FF010CE8FF010CE8FF010CE8FF010CE8FF030ECBFF030A5FFF030E
+      C5FF0510B4FF02074FFF030FC2FF000CEBFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF0011F63B000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000D1AFE130819FED0081AFFFF2F3BFFFF2533FFFF0617
+      FDFF010FF5FF000CEFFF000CEEFF000CEDFF030FCAFF030B8CFF020982FF0209
+      82FF020982FF020982FF020982FF020983FF020983FF030A66FF010438FF0309
+      70FF020859FF00032FFF02086CFF020A94FF020DC1FF010DE7FF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF0011F63B000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000D1AFE130819FED0081AFFFF3640FFFF2B37FFFF081A
+      FFFF0617FEFF010EF5FF000CEEFF020DDDFF050C6AFF010330FF00022BFF0002
+      2BFF00022BFF00022BFF00022BFF00022BFF00022BFF00022BFF00022BFF0002
+      2BFF00022BFF00022BFF00022BFF010331FF02064AFF030DA2FF010DE7FF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF0011F63B000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000D1AFE130819FED0081AFFFF3640FFFF2B37FFFF081A
+      FFFF081AFFFF0718FEFF000EF6FF0A179AFF03073CFF03073AFF03073AFF0307
+      3CFF03073CFF03073CFF03073CFF03073CFF03073CFF03073CFF03073CFF0307
+      3BFF03073AFF030639FF030535FF00022BFF00022BFF02084DFF000CD7FF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF0011F63B000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000D1AFE130819FED0081AFFFF3640FFFF2B37FFFF081A
+      FFFF081AFFFF081AFFFF0819FFFF0516E5FF0512DCFF0512DCFF0512DCFF010D
+      E1FF010DE1FF010DE1FF0410DFFF0512DDFF0612DEFF0612DEFF0512DCFF0512
+      DCFF0512DCFF0411DAFF0714C1FF00022BFF00022BFF01053BFF000BD3FF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF0011F63B000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000D1AFE130819FED0081AFFFF3640FFFF2B37FFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF0718FDFF000DF2FF000CEEFF000CEEFF0916
+      C2FF0915AAFF0915AAFF0613C9FF010DEAFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF0313D7FF00022BFF00022BFF01053BFF000BD2FF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF0011F63B000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000D1AFE130819FED0081AFFFF3640FFFF2B37FFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF0515FCFF010EF3FF010EE9FF0208
+      4BFF00022BFF00022CFF030C91FF010DE8FF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF0515D3FF00022CFF00022BFF01053BFF000BD2FF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF0011F63B000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000D1AFE130819FED0081AFFFF3640FFFF2B37FFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF0515FCFF0715DAFF0104
+      35FF00022AFF010431FF050E91FF0513D2FF0413D4FF0515D6FF0515D7FF0717
+      DAFF0718DBFF0717D0FF061389FF00022BFF00022BFF01053BFF000BD2FF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF0011F63B000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000D1AFE130819FED0081AFFFF3640FFFF2B37FFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF1022C8FF0104
+      33FF00022AFF000229FF02053FFF02064AFF01064BFF02074CFF02074CFF0208
+      4DFF02084EFF03084AFF010535FF00022BFF00022BFF02074CFF010CD6FF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF0011F63B000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000D1AFE130819FED0081AFFFF3640FFFF2B37FFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF0F1FA8FF0205
+      33FF00022BFF00022AFF00022AFF00022BFF00022BFF00022BFF00022BFF0002
+      2BFF00022BFF00022BFF00022BFF00022BFF000435FF020C99FF000CE7FF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF0011F63B000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000D1AFE130819FED0081AFFFF3640FFFF2B37FFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFEFF0A167CFF0105
+      31FF01042EFF01053BFF030C5CFF030740FF00022DFF040E60FF030B52FF0104
+      33FF030A5CFF060F64FF040E61FF061077FF0410B9FF010DE7FF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF0011F63B000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000D1AFE130819FED0081AFFFF3640FFFF2B37FFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF0E22F4FF050C56FF0104
+      2FFF010531FF050F83FF0311E7FF050D75FF050C59FF010DE8FF0411B5FF0712
+      74FF0310D7FF000DEDFF000DEDFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF0011F63B000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000D1AFE130819FED0081AFFFF3640FFFF2B37FFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF1023DCFF040A47FF0104
+      2EFF020636FF0B1AABFF0313FAFF0513D2FF0614D4FF000CEDFF0310E0FF0513
+      D5FF010EEBFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF0011F63B000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000D1AFE130819FED0081AFFFF3640FFFF2B37FFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF1020B9FF04093FFF0104
+      2EFF03073CFF0F21CCFF0618FFFF0111FBFF010DECFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF0011F63B000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000D1AFE130819FED0081AFFFF3640FFFF2B37FFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081596FF020636FF0104
+      2EFF02073FFF0B1DE3FF081AFFFF0618FFFF0111FDFF000DE7FF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF0011F63B000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000D1AFE130819FED0081AFFFF3640FFFF2B37FFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF0A1CF9FF070F75FF010530FF0104
+      2EFF050A4FFF0B1DF5FF081AFFFF081AFFFF081AFFFF0011FDFF000DE8FF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF0011F63B000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000D1AFE130819FED0081AFFFF3640FFFF2B37FFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF0D20E9FF071064FF010431FF0105
+      31FF081275FF081AFEFF081AFFFF081AFFFF081AFFFF0819FFFF010FF6FF000C
+      EFFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF0011F63B000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000D1AFE130819FED0081AFFFF3640FFFF2B37FFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF0B1DEEFF0915ABFF040F96FF0610
+      94FF0918C8FF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF0618FEFF0111
+      F8FF000CEFFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF0011F63B000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000D1AFE130819FED0081AFFFF3640FFFF2B37FFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF0617
+      FEFF0110F9FF000CEFFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF0011F63B000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000D1AFE130819FED0081AFFFF3640FFFF2B37FFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081A
+      FFFF0719FFFF0110F9FF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF0011F63B000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000D1AFE130819FED0081AFFFF3640FFFF2B37FFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081A
+      FFFF081AFFFF081AFFFF0010FAFF000CEEFF000CEEFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF0011F63B000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000E1CFE120819FECF081AFFFF343FFFFF2936FFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF0110F8FF000CEFFF000CEEFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFF0012F538000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000FF03081AFEB9081AFEFD1A29FFFF1525FFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF0719FEFF0210F7FF000CEFFF000CEEFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CEEFE000FFF11000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000000819FF780819FEF6081AFFFF081AFFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF0718FEFF0210F6FF000CEFFF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000CF2ED0000FF03000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000000C18FE15081BFEBC081AFEFE081AFFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF0718FEFF010FF6FF000C
+      EEFF000CEEFF000CEEFF000CEEFF000CEEFF000EF36C0000FF01000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000016FF22071AFEB6081AFFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081A
+      FFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF081AFFFF0618FEFF000D
+      F4FF000CEEFF000CEEFF000CEEFF000EF5B4000EF01200000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000000FF060815FC5E0819
+      FEB50719FEE4081AFEF1081AFEF2081AFEF2081AFEF2081AFEF2081AFEF2081A
+      FEF2081AFEF2081AFEF2081AFEF2081AFEF2081AFEF2081AFEF2081AFEF2081A
+      FEF2081AFEF2081AFEF2081AFEF2081AFEF2081AFEF2081AFEF2081AFEF20618
+      FDF2000CF3F1000CF3E0020EF87D000FF0110000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000
     }
-    OnClick = bbImportKeysFileClick
-    TabOrder = 11
   end
-  object bbLock: TBitBtn
-    Left = 296
-    Height = 38
-    Top = 8
-    Width = 79
-    Caption = 'Lock'
-    Font.Color = clWindowText
-    Font.Height = -13
-    Font.Name = 'Tahoma'
-    Font.Style = [fsBold]
-    Glyph.Data = {
-      76060000424D7606000000000000360400002800000018000000180000000100
-      0800000000004002000000000000000000000001000000010000000000000101
-      0100020202000303030004040400050505000606060007070700080808000909
-      09000A0A0A000B0B0B000C0C0C000D0D0D000E0E0E000F0F0F00101010001111
-      1100121212001313130014141400151515001616160017171700181818001919
-      19001A1A1A001B1B1B001C1C1C001D1D1D001E1E1E001F1F1F00202020002121
-      2100222222002323230024242400252525002626260027272700282828002929
-      29002A2A2A002B2B2B002C2C2C002D2D2D002E2E2E002F2F2F00303030003131
-      3100323232003333330034343400353535003636360037373700383838003939
-      39003A3A3A003B3B3B003C3C3C003D3D3D003E3E3E003F3F3F00404040004141
-      4100424242004343430044444400454545004646460047474700484848004949
-      49004A4A4A004B4B4B004C4C4C004D4D4D004E4E4E004F4F4F00505050005151
-      5100525252005353530054545400555555005656560057575700585858005959
-      59005A5A5A005B5B5B005C5C5C005D5D5D005E5E5E00685968007C4F7C009441
-      9400B72CB700DD15DD00F506F500FD01FD00FE00FE00FE00FE00FE00FE00FE00
-      FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00
-      FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00
-      FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00
-      FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00
-      FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00
-      FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00
-      FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00
-      FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00
-      FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00
-      FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00FE00
-      FE00FE00FE00FE00FE00FE00FE00F008F900D517F000BD24E800A830E1007B4B
-      D0005065C1003774B7002B7DB100237FAC001F82AD001C83AD001785AE001687
-      AF001489B100128AB300108CB6000F8EB9000D91BB000C94BF000A97C3000A99
-      C5000A9AC7000B9BC8000B9CCA000C9ECC000C9FCD000DA0CE000DA1CE000EA2
-      CF0011A3CF0015A4CF0018A5CF001CA7D10021A9D1002AAAD00035AACD0035AD
-      D00035AFD30035B1D60037B5D8003AB8DB003EB9DC0040BBDD0045BEDE004CC1
-      E00055C6E3005BC8E40061CAE40066CBE3006BCCE30072D3E60078D8EB0080D8
-      EE0083D9F10085DCF40088DBF5008BDBF6008EDAF70091DAF70095DCF70097E0
-      F7009EE3F800A4E7F900A9E9F900AEE9F900B5EBF900B2EBF800919191919191
-      919191919191919191919191919191919191919191919191D5E7E8E7E3DED591
-      919191919191919191919191919191D6DDF7F8F8F7F6F4EEE6D5919191919191
-      919191919191D7DADEF8F8F6F7F6EDF1F8F1E69191919191919191919191DADE
-      DFFAFAF8F7F7E9EDF7F7F8EB91919191919191919191DDE5E3FCFCFAFAEEE0E9
-      F3F7F7F7DC919191919191919191DEE7E4FEFEFCFCEDC5E0EFF7F6F6DC919191
-      919191919191DEEAE7FEFEFEFDFBC4C4F5F7F6F6DC919191919191919191E3EC
-      E9FEFEFEFEFEE0C3F9F7F6F6DC919191919191919191E3E9E3F8F8F1F1F8FBFB
-      FCFAF7F6DC919191919191919191DCEAEAE0E1E9E5E3DEE4EBF2FAF9DC919191
-      919191919191DBF3EEC5C5EFF3EBE5DDD9D6E6F5DC91919191919191919191D5
-      E8EDF1FAF6F0EAE4DAD1D2DBDC919191919191919191919191DBE8F0F3F3F3E4
-      D0CFE4D8DC919191919191919191919191919191D5DEE4DED2CFD4D491919191
-      91919191919191919191919191919191D2CE9191919191919191919191919191
-      91C8C89191919191D2CE919191919191919191919191919191D9D09191919191
-      D2CE919191919191919191919191919191E6E39191919191D2CE919191919191
-      919191919191919191E0F3CE91919191D2CE9191919191919191919191919191
-      9191EFF6E1C9C8CDD9CC91919191919191919191919191919191C9EDF9F3F3EB
-      DC91919191919191919191919191919191919191CBE0E1CF9191919191919191
-      9191919191919191919191919191919191919191919191919191
-    }
-    OnClick = bbLockClick
-    ParentFont = False
-    TabOrder = 12
+  object pmKeyMenu: TPopupMenu
+    left = 393
+    top = 168
+    object miChangeName: TMenuItem
+      Caption = 'Change Name'
+      OnClick = miChangeNameClick
+    end
+    object miExportPublicKey: TMenuItem
+      Caption = 'Export Public Key '
+      OnClick = miExportPublicKeyClick
+    end
+    object miExportPrivateKey: TMenuItem
+      Caption = 'Export Private Key'
+      OnClick = miExportPrivateKeyClick
+    end
+    object miSep1: TMenuItem
+      Caption = '-'
+    end
+    object miDeleteKey: TMenuItem
+      Caption = 'Delete'
+      OnClick = miDeleteKeyClick
+    end
   end
   object SaveDialog: TSaveDialog
+    Width = 28
+    Height = 28
     DefaultExt = '.dat'
     Filter = 'Wallet keys file|*.dat|All files|*.*'
     FilterIndex = 0
-    left = 150
-    top = 150
+    left = 145
+    top = 168
   end
   object OpenDialog: TOpenDialog
+    Width = 28
+    Height = 28
     DefaultExt = '.dat'
     Filter = 'Wallet keys file (*.dat)|*.dat|All files (*.*)|*.*'
     FilterIndex = 0
-    left = 205
-    top = 155
+    left = 234
+    top = 183
   end
 end

+ 351 - 415
Units/Forms/UFRMWalletKeys.pas

@@ -2,442 +2,456 @@ unit UFRMWalletKeys;
 
 {$mode delphi}
 
-{ Copyright (c) 2016 by Albert Molina
+{ Copyright (c) 2018 by Herman Schoenfeld
 
   Distributed under the MIT software license, see the accompanying file LICENSE
   or visit http://www.opensource.org/licenses/mit-license.php.
 
-  This unit is a part of Pascal Coin, a P2P crypto currency without need of
-  historical operations.
-
-  If you like it, consider a donation using BitCoin:
-  16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk
-
-  }
+  Acknowledgements:
+  - Albert Molina: portions of code copied from https://github.com/PascalCoin/PascalCoin/blob/master/Units/Forms/UFRMWallet.pas
+}
 
 interface
 
-{$I ./../PascalCoin/config.inc}
-
 uses
-  Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
-  Dialogs, StdCtrls, UCommonUI, UWalletKeys, Buttons,
-  LMessages, clipbrd, UConst, UCommon;
+  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, Messages,
+  Buttons, Menus, UCommonUI, UWallet;
 
-Const
-  CM_PC_WalletKeysChanged = LM_USER + 1;
+const
+  CM_PC_WalletChanged = WM_USER + 1;
 
 type
+
+  { TFRMWalletKeys }
+
   TFRMWalletKeys = class(TApplicationForm)
-    lbWalletKeys: TListBox;
-    bbExportPrivateKey: TBitBtn;
-    lblEncryptionTypeCaption: TLabel;
+    btnChangePassword: TBitBtn;
+    btnBackupWallet: TBitBtn;
+    btnAddKey: TSpeedButton;
+    btnLock: TSpeedButton;
+    btnRestoreBackup: TBitBtn;
+    ilIcons: TImageList;
     lblEncryptionType: TLabel;
-    lblKeyNameCaption: TLabel;
+    lblEncryptionTypeCaption: TLabel;
     lblKeyName: TLabel;
-    lblPrivateKeyCaption: TLabel;
-    memoPrivateKey: TMemo;
-    bbChangeName: TBitBtn;
-    bbImportPrivateKey: TBitBtn;
-    bbExportPublicKey: TBitBtn;
-    bbImportPublicKey: TBitBtn;
-    bbGenerateNewKey: TBitBtn;
-    lblPrivateKeyCaption2: TLabel;
-    bbDelete: TBitBtn;
+    lblKeyNameCaption: TLabel;
     lblKeysEncrypted: TLabel;
-    bbUpdatePassword: TBitBtn;
-    bbExportAllWalletKeys: TBitBtn;
-    SaveDialog: TSaveDialog;
-    bbImportKeysFile: TBitBtn;
+    lblPrivateKeyCaption: TLabel;
+    lbWalletKeys: TListBox;
+    memoPublicKey: TMemo;
+    btnCopyClipboard: TSpeedButton;
+    miDeleteKey: TMenuItem;
+    miExportPublicKey: TMenuItem;
+    miExportPrivateKey: TMenuItem;
+    miChangeName: TMenuItem;
+    miSep1: TMenuItem;
     OpenDialog: TOpenDialog;
-    bbLock: TBitBtn;
+    pmKeyMenu: TPopupMenu;
+    SaveDialog: TSaveDialog;
+    procedure btnAddKeyClick(Sender: TObject);
+    procedure btnBackupWalletClick(Sender: TObject);
+    procedure btnChangePasswordClick(Sender: TObject);
+    procedure btnCopyClipboardClick(Sender: TObject);
+    procedure btnDeleteKeyClick(Sender: TObject);
+    procedure btnLockClick(Sender: TObject);
+    procedure btnRestoreBackupClick(Sender: TObject);
     procedure FormCreate(Sender: TObject);
-    procedure bbChangeNameClick(Sender: TObject);
-    procedure bbExportPrivateKeyClick(Sender: TObject);
-    procedure bbImportPrivateKeyClick(Sender: TObject);
+    procedure FormDestroy(Sender: TObject);
     procedure lbWalletKeysClick(Sender: TObject);
-    procedure bbGenerateNewKeyClick(Sender: TObject);
-    procedure bbExportPublicKeyClick(Sender: TObject);
-    procedure bbDeleteClick(Sender: TObject);
-    procedure bbImportPublicKeyClick(Sender: TObject);
-    procedure bbUpdatePasswordClick(Sender: TObject);
-    procedure bbExportAllWalletKeysClick(Sender: TObject);
-    procedure bbImportKeysFileClick(Sender: TObject);
-    procedure bbLockClick(Sender: TObject);
+    procedure miChangeNameClick(Sender: TObject);
+    procedure miDeleteKeyClick(Sender: TObject);
+    procedure miExportPrivateKeyClick(Sender: TObject);
+    procedure miExportPublicKeyClick(Sender: TObject);
   private
-    //FOldOnChanged : TNotifyEvent;
-    FWalletKeys: TWalletKeys;
-    procedure SetWalletKeys(const Value: TWalletKeys);
-    procedure OnWalletKeysChanged(Sender : TObject);
-    { Private declarations }
-    Procedure UpdateWalletKeys;
-    Procedure UpdateSelectedWalletKey;
-    Function GetSelectedWalletKey(var WalletKey : TWalletKey) : Boolean;
-    Function GetSelectedWalletKeyAndIndex(var WalletKey : TWalletKey; var index : Integer) : Boolean;
-    Procedure CheckIsWalletKeyValidPassword;
-    procedure CM_WalletChanged(var Msg: TMessage); message CM_PC_WalletKeysChanged;
+    { private declarations }
+    procedure CM_WalletChanged(var Msg: TMessage); message CM_PC_WalletChanged;
+    procedure OnWalletChanged(Sender: TObject);
+    procedure RefreshUI;
+    function GetSelectedWalletKey(var WalletKey: TWalletKey): Boolean;
+    function GetSelectedWalletKeyAndIndex(var WalletKey: TWalletKey; var index: Integer): Boolean;
+  protected
+    function CheckIsWalletKeyValidPassword : boolean;
+    procedure ToggleWalletLock;
+    procedure AddNewKey;
+    procedure DeleteSelectedKey;
+    procedure UpdateSelectedWalletKey;
+    procedure ChangeSelectedKeyName;
+    procedure ExportSelectedPrivateKey;
+    procedure ExportSelectedPublicKey(notify:boolean);
+    procedure ChangeWalletPassword;
+    procedure BackupWallet;
+    procedure RestoreWallet;
   public
-    { Public declarations }
-    Property WalletKeys : TWalletKeys read FWalletKeys write SetWalletKeys;
-    Destructor Destroy; override;
+    { public declarations }
   end;
 
-implementation
 
-uses
-  LCLIntf, LCLType, UCrypto, UAccounts, UUserInterface, UFRMNewPrivateKeyType, UAES;
+implementation
 
 {$R *.lfm}
 
-{ TFRMWalletKeys }
+uses  LCLIntf, Clipbrd, UUserInterface, USettings, UCommon, UAccounts, UWIZAddKey, UAutoScope;
 
-procedure TFRMWalletKeys.bbChangeNameClick(Sender: TObject);
-Var wk : TWalletKey;
-  s : String;
-  index : integer;
+{%region Form life-cycle}
+
+procedure TFRMWalletKeys.FormCreate(Sender: TObject);
 begin
-  if not GetSelectedWalletKeyAndIndex(wk,index) then exit;
-  s := wk.Name;
-  if InputQuery('Change name','Input new key name:',s) then begin
-    WalletKeys.SetName(index,s);
-    UpdateWalletKeys;
+  TWallet.Keys.OnChanged.Add(OnWalletChanged);
+  RefreshUI;
+end;
+
+procedure TFRMWalletKeys.FormDestroy(Sender: TObject);
+begin
+  TWallet.Keys.OnChanged.Remove(OnWalletChanged);
+end;
+
+{%endregion}
+
+{%region Methods}
+
+procedure TFRMWalletKeys.ToggleWalletLock;
+begin
+  if NOT TWallet.Keys.HasPassword then exit;
+  if TWallet.Keys.IsValidPassword then begin
+    TWallet.Keys.LockWallet;
+  end else begin
+    TUserInterface.UnlockWallet(Self);
   end;
 end;
 
-procedure TFRMWalletKeys.bbDeleteClick(Sender: TObject);
-Var wk : TWalletKey;
+procedure TFRMWalletKeys.AddNewKey;
+var
+  Scoped : TScoped;
+  wiz : TWIZAddKeyWizard;
+  model : TWizAddKeyModel;
+begin
+  wiz := Scoped.AddObject(TWIZAddKeyWizard.Create(nil)) as TWIZAddKeyWizard;
+  model := Scoped.AddObject(TWIZAddKeyModel.Create(nil)) as TWizAddKeyModel;
+  wiz.Start(model);
+end;
+
+procedure TFRMWalletKeys.DeleteSelectedKey;
+Var
+  wk : TWalletKey;
   index : Integer;
-  s : String;
+  prompt : String;
 begin
   if Not GetSelectedWalletKeyAndIndex(wk,index) then exit;
-  s := 'Are you sure you want to delete the selected private key?'+#10+wk.Name+#10+#10+
+
+  if (TSettings.MinerPrivateKeyType = mpk_Selected) AND (TSettings.MinerSelectedPrivateKey = TAccountComp.AccountKey2RawString(wk.AccountKey)) then begin
+    TUserInterface.ShowError(Self, 'Delete Key Faied',
+    'This key is used for mining and cannot be deleted.' + #10 + #10 +
+    'De-select this key from options and try again.');
+    exit;
+  end;
+
+  prompt := 'Are you sure you want to delete the selected private key?'+#10+wk.Name+#10+#10+
     'Please note that this will forever remove access to accounts using this key...';
-  if Application.MessageBox(Pchar(s),PChar('Delete key'),
-    MB_YESNO+MB_DEFBUTTON2+MB_ICONWARNING)<>Idyes then exit;
-  if Application.MessageBox(PChar('Are you sure you want to delete?'),PChar('Delete key'),
-    MB_YESNO+MB_DEFBUTTON2+MB_ICONWARNING)<>Idyes then exit;
-  WalletKeys.Delete(index);
-  UpdateWalletKeys;
+  if TUserInterface.AskQuestion(Self, mtWarning, 'Confirm Delete', prompt, mbYesNo) = mbYes then
+    if TUserInterface.AskQuestion(Self, mtWarning, 'Confirm Delete', 'ARE YOU ABSOLUTELY SURE?', mbYesNo) = mbYes then
+      TWallet.DeleteKey(wk);
 end;
 
-procedure TFRMWalletKeys.bbExportAllWalletKeysClick(Sender: TObject);
-Var efn : String;
-  fs : TFileStream;
+procedure TFRMWalletKeys.UpdateSelectedWalletKey;
+Var
+  wk : TWalletKey;
+  ok : Boolean;
 begin
-  if WalletKeys.Count<=0 then raise Exception.Create('Your wallet is empty. No keys!');
-  if ((WalletKeys.IsValidPassword) And (WalletKeys.WalletPassword='')) then begin
-    if Application.MessageBox(PChar('Your wallet has NO PASSWORD'+#10+#10+
-      'It is recommend to protect your wallet with a password prior to exporting it!'+#10+#10+
-      'Continue without password protection?'),PChar(Application.Title),MB_YESNO+MB_ICONWARNING+MB_DEFBUTTON2)<>IdYes then exit;
-  end;
-
-  if Not SaveDialog.Execute then exit;
-  efn := SaveDialog.FileName;
-  if FileExists(efn) then begin
-    if Application.MessageBox(PChar('This file exists:'+#10+efn+#10#10+'Overwrite?'),PChar(Application.Title),MB_YESNO+MB_ICONQUESTION+MB_DEFBUTTON2)<>IdYes then exit;
-  end;
-  fs := TFileStream.Create(efn,fmCreate);
+  ok := false;
+  wk := CT_TWalletKey_NUL;
   try
-    fs.Size := 0;
-    WalletKeys.SaveToStream(fs);
+    if Not GetSelectedWalletKey(wk) then exit;
+    ok := true;
+    lblEncryptionType.Caption := TAccountComp.GetECInfoTxt( wk.AccountKey.EC_OpenSSL_NID );
+    if wk.Name='' then lblKeyName.Caption := '(No Name)'
+    else lblKeyName.Caption := wk.Name;
+    memoPublicKey.Lines.Text := TAccountComp.AccountPublicKeyExport(wk.AccountKey);
+    memoPublicKey.Font.Color := clBlack;
   finally
-    fs.Free;
+    lblEncryptionTypeCaption.Enabled := ok;
+    lblEncryptionType.Enabled := ok;
+    lblKeyNameCaption.Enabled := ok;
+    lblKeyName.Enabled := (ok) And (wk.Name<>'');
+    lblPrivateKeyCaption.Enabled := ok;
+    memoPublicKey.Enabled := ok;
+    btnCopyClipboard.Enabled := ok;
+    if not ok then begin
+      lblEncryptionType.Caption := '';
+      lblKeyName.Caption := '';
+      memoPublicKey.Lines.Clear;
+    end;
   end;
-  Application.MessageBox(PChar('Wallet key exported to a file:'+#10+efn),PChar(Application.Title),MB_OK+MB_ICONINFORMATION);
 end;
 
-procedure TFRMWalletKeys.bbExportPrivateKeyClick(Sender: TObject);
+procedure TFRMWalletKeys.ChangeSelectedKeyName;
+Var wk : TWalletKey;
+  s : String;
+  index : integer;
+begin
+  if not GetSelectedWalletKeyAndIndex(wk,index) then exit;
+  s := wk.Name;
+  if TUserInterface.AskEnterString(Self, 'Change name','Input new key name:',s) then begin
+    TWallet.Keys.SetName(index,s);
+  end;
+end;
+
+procedure TFRMWalletKeys.ExportSelectedPrivateKey;
 Var wk : TWalletKey;
   pwd1,pwd2, enc : String;
 begin
-  CheckIsWalletKeyValidPassword;
+  if not CheckIsWalletKeyValidPassword then exit;
   if Not GetSelectedWalletKey(wk) then exit;
   if Assigned(wk.PrivateKey) then begin
-    if InputQuery('Export private key','Insert a password to export',pwd1) then begin
-      if InputQuery('Export private key','Repeat the password to export',pwd2) then begin
+    if TUserInterface.AskEnterProtectedString(Self, 'Export Private Key','Enter a password to encrypt private key',pwd1) then begin
+      if TUserInterface.AskEnterProtectedString(Self, 'Export Private Key','Re-enter the password',pwd2) then begin
         if pwd1<>pwd2 then raise Exception.Create('Passwords does not match!');
-        enc := TCrypto.ToHexaString( TAESComp.EVP_Encrypt_AES256( wk.PrivateKey.ExportToRaw,pwd1) );
+        enc := TWallet.ExportPrivateKey(wk, pwd1);
         Clipboard.AsText := enc;
-        Application.MessageBox(PChar('The password has been encrypted with your password and copied to the clipboard.'+
+        TUserInterface.ShowInfo(Self, 'Completed',
+         'The private key has been encrypted with your password and copied to the clipboard.'+
           #10+#10+
-          'Password: "'+pwd1+'"'+#10+
-          #10+
           'Encrypted key value (Copied to the clipboard):'+#10+
           enc+
-          #10+#10+'Length='+Inttostr(length(enc))+' bytes'),
-          PChar(Application.Title),MB_OK+MB_ICONINFORMATION);
+          #10+#10+'Length='+Inttostr(length(enc))+' bytes');
       end else raise Exception.Create('Cancelled operation');
     end;
   end;
 end;
 
-procedure TFRMWalletKeys.bbExportPublicKeyClick(Sender: TObject);
+procedure TFRMWalletKeys.ExportSelectedPublicKey(notify:boolean);
 Var wk : TWalletKey;
   s : String;
 begin
-  CheckIsWalletKeyValidPassword;
   if Not GetSelectedWalletKey(wk) then exit;
-  s := TAccountComp.AccountPublicKeyExport(wk.AccountKey);
+  s := TWallet.ExportPublicKey(wk);
   Clipboard.AsText := s;
-  Application.MessageBox(PChar('The public key has been copied to the clipboard'+#10+#10+
-    'Public key value:'+#10+
-    s+#10+#10+
-    'Length='+Inttostr(length(s))+' bytes'),
-          PChar(Application.Title),MB_OK+MB_ICONINFORMATION);
+  if notify then
+    TUserInterface.ShowInfo(Self, 'Completed',
+      'The public key has been copied to the clipboard'+#10+#10+
+      'Public key value:'+#10+
+      s+#10+#10+
+      'Length='+Inttostr(length(s))+' bytes');
 end;
 
-procedure TFRMWalletKeys.bbGenerateNewKeyClick(Sender: TObject);
-Var FRM : TFRMNewPrivateKeyType;
+procedure TFRMWalletKeys.ChangeWalletPassword;
 begin
-  CheckIsWalletKeyValidPassword;
-  FRM := TFRMNewPrivateKeyType.Create(Self);
-  try
-    FRM.WalletKeys := WalletKeys;
-    FRM.ShowModal;
-    UpdateWalletKeys;
-  finally
-    FRM.Free;
-  end;
+  if not CheckIsWalletKeyValidPassword
+    then exit;
+  TUserInterface.ChangeWalletPassword(Self);
 end;
 
-procedure TFRMWalletKeys.bbImportKeysFileClick(Sender: TObject);
-Var wki : TWalletKeys;
-  ifn,pwd : String;
-  i : Integer;
-  cPrivatekeys, cPublicKeys : Integer;
+procedure TFRMWalletKeys.BackupWallet;
+var
+  filename : String;
 begin
-  if Not OpenDialog.Execute then exit;
-  ifn := OpenDialog.FileName;
-  if Not FileExists(ifn) then raise Exception.Create('Cannot find file '+ifn);
+  if TWallet.Keys.Count<=0 then begin
+    TUserInterface.ShowError(self, 'Error', 'Your wallet is empty. No keys!');
+    exit;
+  end;
+  if NOT TWallet.Keys.HasPassword then
+    if TUserInterface.AskQuestion(self, mtWarning,
+      'No Password', 'Your wallet has NO PASSWORD'+#10+#10+
+      'It is recommend to protect your wallet with a password prior to exporting it!'+#10+#10+
+      'Continue without password protection?', mbYesNo) <> mbYes then exit;
+  if Not SaveDialog.Execute
+    then exit;
+  filename := SaveDialog.FileName;
+  if FileExists(filename) then
+    if TUserInterface.AskQuestion(self, mtConfirmation, 'Overwrite', 'This file exists:'+#10+filename+#10#10+'Overwrite?', mbYesNo)<> mbYes then
+         exit;
+  TWallet.BackupWallet(filename);
+  TUserInterface.ShowInfo(self, 'Completed', 'Wallet key exported to a file:'+#10+filename);
+end;
 
-  wki := TWalletKeys.Create(Self);
-  try
-    wki.WalletFileName := ifn;
-    if wki.Count<=0 then raise Exception.Create('Wallet file has no valid data');
-    pwd := '';
-    While (Not wki.IsValidPassword) do begin
-      if Not InputQuery('Import','Enter the wallet file password:',pwd) then exit;
-      wki.WalletPassword := pwd;
-      if not wki.IsValidPassword then begin
-        If Application.MessageBox(PChar('Password entered is not valid, retry?'),PChar(Application.Title),MB_ICONERROR+MB_YESNO)<>Idyes then exit;
-      end;
-    end;
-    cPrivatekeys := 0;
-    cPublicKeys := 0;
-    if wki.IsValidPassword then begin
-      for i := 0 to wki.Count - 1 do begin
-        if WalletKeys.IndexOfAccountKey(wki.Key[i].AccountKey)<0 then begin
-          If Assigned(wki.Key[i].PrivateKey) then begin
-            WalletKeys.AddPrivateKey(wki.Key[i].Name,wki.Key[i].PrivateKey);
-            inc(cPrivatekeys);
-          end else begin
-            WalletKeys.AddPublicKey(wki.Key[i].Name,wki.Key[i].AccountKey);
-            inc(cPublicKeys);
-          end;
-        end;
-      end;
-    end;
-    if (cPrivatekeys>0) Or (cPublicKeys>0) then begin
-      Application.MessageBox(PChar('Wallet file imported successfully'+#10+#10+
-        'File:'+ifn+#10+#10+
-        'Total keys in wallet: '+inttostr(wki.Count)+#10+
-        'Imported private keys: '+IntToStr(cPrivatekeys)+#10+
-        'Imported public keys only: '+IntToStr(cPublicKeys)+#10+
-        'Duplicated (not imported): '+InttoStr(wki.Count - cPrivatekeys - cPublicKeys)),
-        PChar(Application.Title),MB_OK+MB_ICONINFORMATION);
+procedure TFRMWalletKeys.RestoreWallet;
+Var
+  filename,password : String;
+  restoreResult : TRestoreWalletResult;
+begin
+  if not CheckIsWalletKeyValidPassword then exit;
+  if not OpenDialog.Execute then exit;
+  filename := OpenDialog.FileName;
+  if Not FileExists(filename) then
+    raise Exception.Create('Cannot find file '+filename);
+  repeat
+    if NOT TUserInterface.AskEnterProtectedString(Self, 'Restore Wallet', 'Please enter password used to secure the imported wallet', password) then
+      exit;
+    restoreResult := TWallet.RestoreWallet(filename, password);
+    if (not restoreResult.Success) AND (TUserInterface.AskQuestion(self, mtError, 'Wrong Password', 'Password entered is not valid, retry?', mbYesNo) <> mbYes) then
+      exit;
+  until restoreResult.Success;
+  if restoreResult.Success then begin
+    if (restoreResult.ImportedPrivateKeys>0) Or (restoreResult.ImportedPublicKeys>0) then begin
+      TUserInterface.ShowInfo(self,
+      'Completed',
+      'Wallet file imported successfully'+#10+#10+
+        'File: '+filename+#10+#10+
+        'Total keys in wallet: '+inttostr(restoreResult.TotalKeysFound)+#10+
+        'Imported private keys: '+IntToStr(restoreResult.ImportedPrivateKeys)+#10+
+        'Imported watch-only keys: '+IntToStr(restoreResult.ImportedPublicKeys)+#10+
+        'Duplicates (discarded): '+InttoStr(restoreResult.Duplicates));
     end else begin
-      Application.MessageBox(PChar('Wallet file keys were already in your wallet. Nothing imported'+#10+#10+
-        'File:'+ifn+#10+#10+
-        'Total keys in wallet: '+inttostr(wki.Count)),
-        PChar(Application.Title),MB_OK+MB_ICONWARNING);
+      TUserInterface.ShowWarning(Self,
+      'No New Keys',
+      'Wallet file keys were already in your wallet. Nothing imported'+#10+#10+
+        'File: '+filename+#10+#10+
+        'Total keys in wallet: '+inttostr(restoreResult.TotalKeysFound));
     end;
-  finally
-    wki.Free;
   end;
 end;
 
-procedure TFRMWalletKeys.bbImportPrivateKeyClick(Sender: TObject);
-var s : String;
- desenc, enc : AnsiString;
- EC : TECPrivateKey;
- i : Integer;
- wk : TWalletKey;
- parseResult : Boolean;
-
-  function ParseRawKey(EC_OpenSSL_NID : Word) : boolean;
-  begin
-    FreeAndNil(EC); ParseRawKey := False;
-    EC := TECPrivateKey.Create;
-    Try
-      EC.SetPrivateKeyFromHexa(EC_OpenSSL_NID, TCrypto.ToHexaString(enc));
-      ParseRawKey := True;
-    Except
-      On E:Exception do begin
-        FreeAndNil(EC);
-        Raise;
-      end;
-    end;
-  end;
+{%endregion}
 
-  function ParseEncryptedKey : boolean;
-  begin
-      Repeat
-        s := '';
-        desenc := '';
-        if InputQuery('Import private key','Enter the password:',s) then begin
-          If (TAESComp.EVP_Decrypt_AES256(enc,s,desenc)) then begin
-            if (desenc<>'') then begin
-              EC := TECPrivateKey.ImportFromRaw(desenc);
-              ParseEncryptedKey := True;
-              Exit;
-            end else begin
-              if Application.MessageBox(PChar('Invalid password!'),'',MB_RETRYCANCEL+MB_ICONERROR)<>IDRETRY then begin
-                ParseEncryptedKey := False;
-                Exit;
-              end;
-              desenc := '';
-            end;
-          end else begin
-            if Application.MessageBox(PChar('Invalid password or corrupted data!'),'',MB_RETRYCANCEL+MB_ICONERROR)<>IDRETRY then begin
-              ParseEncryptedKey := False;
-              Exit;
-            end;
-          end;
-        end else begin
-          ParseEncryptedKey := false;
-          Exit;
-        end;
-      Until (desenc<>'');
-  end;
+{%region Aux}
 
+procedure TFRMWalletKeys.RefreshUI;
+var
+  lasti,i : Integer;
+  selected_wk,wk : TWalletKey;
+  keyName : AnsiString;
 begin
-  EC := Nil;
-  CheckIsWalletKeyValidPassword;
-  if Not Assigned(WalletKeys) then exit;
-  if InputQuery('Import private key','Insert the password protected private key or raw private key',s) then begin
-    s := trim(s);
-    if (s='') then raise Exception.Create('No valid key');
-    enc := TCrypto.HexaToRaw(s);
-    if (enc='') then raise Exception.Create('Invalid text... You must enter an hexadecimal value ("0".."9" or "A".."F")');
-    case Length(enc) of
-         32: parseResult := ParseRawKey(CT_NID_secp256k1);
-         35,36: parseResult := ParseRawKey(CT_NID_sect283k1);
-         48: parseResult := ParseRawKey(CT_NID_secp384r1);
-         65,66: parseResult := ParseRawKey(CT_NID_secp521r1);
-         64, 80, 96: parseResult := ParseEncryptedKey;
-         else Exception.Create('Invalidly formatted private key string. Ensure it is an encrypted private key export or raw private key hexstring.');
+  GetSelectedWalletKeyAndIndex(wk,lasti);
+  lbWalletKeys.Items.BeginUpdate;
+  Try
+    lbWalletKeys.Items.Clear;
+    lblKeysEncrypted.Caption := '';
+
+    If NOT TWallet.Keys.HasPassword then begin
+      // NO PASSWORD
+      lblKeysEncrypted.Caption := 'Wallet has no password';
+      ilIcons.GetBitmap(1, btnLock.Glyph);
+      btnLock.Enabled := false;
+      btnChangePassword.Enabled := true;
+      btnAddKey.Visible := true;
+      btnChangePassword.Caption := 'Set Password';
+      btnChangePassword.Enabled := true;
+      btnRestoreBackup.Enabled := true;
+      miChangeName.Enabled := true;
+      miExportPrivateKey.Enabled := true;
+      miDeleteKey.Enabled := true;
+    end else if TWallet.Keys.IsValidPassword then begin
+      // UNLOCKED
+      lblKeysEncrypted.Caption := 'Wallet is unlocked';
+      ilIcons.GetBitmap(1, btnLock.Glyph);
+      btnLock.Enabled := true;
+      btnChangePassword.Enabled := true;
+      btnAddKey.Enabled := true;
+      btnAddKey.Visible := true;
+      btnChangePassword.Caption := 'Change Password';
+      btnChangePassword.Enabled := true;
+      btnRestoreBackup.Enabled := true;
+      miChangeName.Enabled := true;
+      miExportPrivateKey.Enabled := true;
+      miDeleteKey.Enabled := true;
+    end else begin
+      // LOCKED
+      lblKeysEncrypted.Caption := 'Wallet is locked';
+      ilIcons.GetBitmap(0, btnLock.Glyph);
+      btnLock.Enabled := true;
+      btnChangePassword.Enabled := false;
+      btnAddKey.Visible := false;
+      btnAddKey.Enabled := false;
+      btnChangePassword.Caption := 'Change Password';
+      btnChangePassword.Enabled := false;
+      btnRestoreBackup.Enabled := false;
+      miChangeName.Enabled := false;
+      miExportPrivateKey.Enabled := false;
+      miDeleteKey.Enabled := false;
     end;
-    if (parseResult = False) then
-       exit;
-    Try
-      // EC is assigned by ParseRawKey/ImportEncryptedKey
-      if Not Assigned(EC) then begin
-        Application.MessageBox(PChar('Invalid password and/or corrupted data!'),'', MB_OK);
-        exit;
-      end;
-      i := WalletKeys.IndexOfAccountKey(EC.PublicKey);
-      if (i>=0) then begin
-        wk := WalletKeys.Key[i];
-        if Assigned(wk.PrivateKey) And (Assigned(wk.PrivateKey.PrivateKey)) then raise Exception.Create('This key is already in your wallet!');
+    for i := 0 to TWallet.Keys.Count - 1 do begin
+      wk := TWallet.Keys.Key[i];
+      if (wk.Name='') then begin
+        keyName := '(No Name)';
+      end else begin
+        keyName := wk.Name;
       end;
-      s := 'Imported '+DateTimeToStr(now);
-      s := InputBox('Set a name','Name for this private key:',s);
-      i := WalletKeys.AddPrivateKey(s,EC);
-      Application.MessageBox(PChar('Imported private key'),PChar(Application.Title),MB_OK+MB_ICONINFORMATION);
-    Finally
-      EC.Free;
-    End;
-    UpdateWalletKeys;
-  end;
+      if Not wk.HasPrivateKey then
+        keyName:=keyName+' (watch-only)';
+      lbWalletKeys.Items.AddObject(keyName,TObject(i));
+    end;
+    i := lbWalletKeys.Items.IndexOfObject(TObject(lasti));
+    lbWalletKeys.ItemIndex := i;
+  Finally
+    lbWalletKeys.Items.EndUpdate;
+  End;
+  UpdateSelectedWalletKey;
 end;
 
-procedure TFRMWalletKeys.bbImportPublicKeyClick(Sender: TObject);
-var s : String;
- raw : AnsiString;
- EC : TECPrivateKey;
- account : TAccountKey;
- errors : AnsiString;
+function TFRMWalletKeys.CheckIsWalletKeyValidPassword : boolean;
 begin
-  CheckIsWalletKeyValidPassword;
-  if Not Assigned(WalletKeys) then exit;
-  if Not InputQuery('Import publick key','Insert the public key in hexa format or imported format',s) then exit;
-  If not TAccountComp.AccountPublicKeyImport(s,account,errors) then begin
-    raw := TCrypto.HexaToRaw(s);
-    if trim(raw)='' then raise Exception.Create('Invalid public key value (Not hexa or not an imported format)'+#10+errors);
-    account := TAccountComp.RawString2Accountkey(raw);
-  end;
-  If not TAccountComp.IsValidAccountKey(account,errors) then raise Exception.Create('This data is not a valid public key'+#10+errors);
-  if WalletKeys.IndexOfAccountKey(account)>=0 then raise exception.Create('This key exists on your wallet');
-  s := 'Imported public key '+DateTimeToStr(now);
-  if InputQuery('Set a name','Name for this private key:',s) then begin
-    WalletKeys.AddPublicKey(s,account);
-    UpdateWalletKeys;
-    Application.MessageBox(PChar('Imported public key'),PChar(Application.Title),MB_OK+MB_ICONINFORMATION);
-  end;
+  if NOT TWallet.Keys.IsValidPassword then begin
+    TUserInterface.ShowError(Self, 'Unable to continue', 'Wallet is locked. Please unlock the wallet to perform this task.');
+    Result := false;
+  end else
+    Result := true;
 end;
 
-procedure TFRMWalletKeys.bbLockClick(Sender: TObject);
+function TFRMWalletKeys.GetSelectedWalletKey(var WalletKey: TWalletKey): Boolean;
+Var i : Integer;
 begin
-  FWalletKeys.LockWallet;
+  Result := GetSelectedWalletKeyAndIndex(WalletKey,i);
 end;
 
-procedure TFRMWalletKeys.bbUpdatePasswordClick(Sender: TObject);
+function TFRMWalletKeys.GetSelectedWalletKeyAndIndex(var WalletKey: TWalletKey; var index: Integer): Boolean;
 begin
-  if FWalletKeys.IsValidPassword then begin
-    TUserInterface.ChangeWalletPassword(Self, FWalletKeys);
-  end else begin
-    TUserInterface.UnlockWallet(Self, FWalletKeys);
+  index := -1;
+  Result := false;
+  if lbWalletKeys.ItemIndex<0 then exit;
+  index := Integer(lbWalletKeys.Items.Objects[ lbWalletKeys.ItemIndex ]);
+  if (index>=0) And (index<TWallet.Keys.Count) then begin
+    WalletKey := TWallet.Keys.Key[index];
+    Result := true;
   end;
-  UpdateWalletKeys;
 end;
 
-procedure TFRMWalletKeys.CheckIsWalletKeyValidPassword;
-begin
-  if Not Assigned(FWalletKeys) then exit;
+{%endregion}
 
-  if Not FWalletKeys.IsValidPassword then begin
-    Application.MessageBox(PChar('Wallet key is encrypted!'+#10+#10+'You must enter password to continue...'),
-      PCHar(Application.Title),MB_OK+MB_ICONWARNING);
-    bbUpdatePasswordClick(Nil);
-    if Not FWalletKeys.IsValidPassword then raise Exception.Create('Cannot continue without valid password');
-  end;
+{%region Event Handlers}
+
+procedure TFRMWalletKeys.btnLockClick(Sender: TObject);
+begin
+  ToggleWalletLock;
 end;
 
 procedure TFRMWalletKeys.CM_WalletChanged(var Msg: TMessage);
 begin
-  UpdateWalletKeys;
+  RefreshUI;
 end;
 
-destructor TFRMWalletKeys.Destroy;
+procedure TFRMWalletKeys.OnWalletChanged(Sender: TObject);
 begin
-  if Assigned(FWalletKeys) then FWalletKeys.OnChanged.Remove(OnWalletKeysChanged);
-  inherited;
+  // Ensure handled in UI thread
+  PostMessage(Self.Handle,CM_PC_WalletChanged,0,0);
 end;
 
-procedure TFRMWalletKeys.FormCreate(Sender: TObject);
+procedure TFRMWalletKeys.btnAddKeyClick(Sender: TObject);
 begin
-  lbWalletKeys.Sorted := true;
-  FWalletKeys := Nil;
-  UpdateWalletKeys;
+  AddNewKey;
 end;
 
-function TFRMWalletKeys.GetSelectedWalletKey(var WalletKey: TWalletKey): Boolean;
-Var i : Integer;
+procedure TFRMWalletKeys.btnBackupWalletClick(Sender: TObject);
 begin
-  Result := GetSelectedWalletKeyAndIndex(WalletKey,i);
+ BackupWallet;
 end;
 
-function TFRMWalletKeys.GetSelectedWalletKeyAndIndex(var WalletKey: TWalletKey; var index: Integer): Boolean;
+procedure TFRMWalletKeys.btnChangePasswordClick(Sender: TObject);
 begin
-  index := -1;
-  Result := false;
-  if Not Assigned(WalletKeys) then exit;
-  if lbWalletKeys.ItemIndex<0 then exit;
-  index := Integer(lbWalletKeys.Items.Objects[ lbWalletKeys.ItemIndex ]);
-  if (index>=0) And (index<WalletKeys.Count) then begin
-    WalletKey := WalletKeys.Key[index];
-    Result := true;
-  end;
+  ChangeWalletPassword;
+end;
+
+procedure TFRMWalletKeys.btnCopyClipboardClick(Sender: TObject);
+begin
+  ExportSelectedPublicKey(false);
+end;
+
+procedure TFRMWalletKeys.btnDeleteKeyClick(Sender: TObject);
+begin
+  DeleteSelectedKey;
+end;
+
+procedure TFRMWalletKeys.btnRestoreBackupClick(Sender: TObject);
+begin
+ RestoreWallet;
 end;
 
 procedure TFRMWalletKeys.lbWalletKeysClick(Sender: TObject);
@@ -445,105 +459,27 @@ begin
   UpdateSelectedWalletKey;
 end;
 
-procedure TFRMWalletKeys.OnWalletKeysChanged(Sender : TObject);
+procedure TFRMWalletKeys.miChangeNameClick(Sender: TObject);
 begin
-  PostMessage(Self.Handle,CM_PC_WalletKeysChanged,0,0);
+  ChangeSelectedKeyName;
 end;
 
-procedure TFRMWalletKeys.SetWalletKeys(const Value: TWalletKeys);
+procedure TFRMWalletKeys.miDeleteKeyClick(Sender: TObject);
 begin
-  if FWalletKeys=Value then exit;
-  if Assigned(FWalletKeys) then FWalletKeys.OnChanged.Remove(OnWalletKeysChanged);
-  FWalletKeys := Value;
-  if Assigned(FWalletKeys) then begin
-    FWalletKeys.OnChanged.Add(OnWalletKeysChanged);
-  end;
-  UpdateWalletKeys;
+  DeleteSelectedKey;
 end;
 
-procedure TFRMWalletKeys.UpdateSelectedWalletKey;
-Var
-  wk : TWalletKey;
-  ok : Boolean;
+procedure TFRMWalletKeys.miExportPrivateKeyClick(Sender: TObject);
 begin
-  ok := false;
-  wk := CT_TWalletKey_NUL;
-  try
-    if Not GetSelectedWalletKey(wk) then exit;
-    ok := true;
-    lblEncryptionType.Caption := TAccountComp.GetECInfoTxt( wk.AccountKey.EC_OpenSSL_NID );
-    if wk.Name='' then lblKeyName.Caption := '(No name)'
-    else lblKeyName.Caption := wk.Name;
-    if Assigned(wk.PrivateKey) then begin
-      memoPrivateKey.Lines.Text :=  TCrypto.PrivateKey2Hexa(wk.PrivateKey.PrivateKey);
-      memoPrivateKey.Font.Color := clBlack;
-    end else begin
-      memoPrivateKey.Lines.Text := '(No private key)';
-      memoPrivateKey.Font.Color := clRed;
-    end;
-  finally
-    lblEncryptionTypeCaption.Enabled := ok;
-    lblEncryptionType.Enabled := ok;
-    lblKeyNameCaption.Enabled := ok;
-    lblKeyName.Enabled := (ok) And (wk.Name<>'');
-    lblPrivateKeyCaption.Enabled := ok;
-    memoPrivateKey.Enabled := ok;
-    bbExportPrivateKey.Enabled := ok;
-    bbExportPublicKey.Enabled := ok;
-    bbChangeName.Enabled := ok;
-    lblPrivateKeyCaption2.Enabled := ok;
-    bbDelete.Enabled := ok;
-    if not ok then begin
-      lblEncryptionType.Caption := '';
-      lblKeyName.Caption := '';
-      memoPrivateKey.Lines.Clear;
-    end;
-  end;
-
+  ExportSelectedPrivateKey;
 end;
 
-procedure TFRMWalletKeys.UpdateWalletKeys;
-Var lasti,i : Integer;
-  selected_wk,wk : TWalletKey;
-  s : AnsiString;
+procedure TFRMWalletKeys.miExportPublicKeyClick(Sender: TObject);
 begin
-  GetSelectedWalletKeyAndIndex(wk,lasti);
-  lbWalletKeys.Items.BeginUpdate;
-  Try
-    lbWalletKeys.Items.Clear;
-    lblKeysEncrypted.Caption := '';
-    if not assigned(FWalletKeys) then exit;
-    bbLock.Enabled := (FWalletKeys.IsValidPassword) And (FWalletKeys.WalletPassword<>'');
-    If FWalletKeys.IsValidPassword then begin
-      if FWalletKeys.WalletPassword='' then lblKeysEncrypted.Caption := 'Wallet without password'
-      else lblKeysEncrypted.Caption := 'Wallet is password protected';
-      lblKeysEncrypted.font.Color := clGreen;
-      bbUpdatePassword.Caption := 'Change password';
-    end else begin
-      lblKeysEncrypted.Caption := 'Wallet is encrypted... need password!';
-      lblKeysEncrypted.font.Color := clRed;
-      bbUpdatePassword.Caption := 'Input password';
-    end;
-    for i := 0 to WalletKeys.Count - 1 do begin
-      wk := WalletKeys.Key[i];
-      if (wk.Name='') then begin
-        s := 'Sha256='+TCrypto.ToHexaString( TCrypto.DoSha256( TAccountComp.AccountKey2RawString(wk.AccountKey) ) );
-      end else begin
-        s := wk.Name;
-      end;
-      if Not Assigned(wk.PrivateKey) then begin
-        if wk.CryptedKey<>'' then s:=s+' (Encrypted, need password)';
-        s:=s+' (* without key)';
-      end;
-      lbWalletKeys.Items.AddObject(s,TObject(i));
-    end;
-    i := lbWalletKeys.Items.IndexOfObject(TObject(lasti));
-    lbWalletKeys.ItemIndex := i;
-  Finally
-    lbWalletKeys.Items.EndUpdate;
-  End;
-  UpdateSelectedWalletKey;
+  ExportSelectedPublicKey(true);
 end;
 
+{%endregion}
+
 end.
 

+ 0 - 35
Units/Forms/UFRMWalletKeys2.pas

@@ -1,35 +0,0 @@
-unit UFRMWalletKeys2;
-
-{$mode delphi}
-
-{ Copyright (c) 2018 by Herman Schoenfeld
-
-  Distributed under the MIT software license, see the accompanying file LICENSE
-  or visit http://www.opensource.org/licenses/mit-license.php.
-}
-
-
-interface
-
-{$I ./../PascalCoin/config.inc}
-
-uses
-  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, UConst;
-
-type
-  TFRMWalletKeys2 = class(TApplicationForm)
-  private
-    { private declarations }
-  public
-    { public declarations }
-  end;
-
-var
-  FRMWalletKeys2: TFRMWalletKeys2;
-
-implementation
-
-{$R *.lfm}
-
-end.
-

+ 132 - 221
Units/Forms/UUserInterface.pas

@@ -17,7 +17,7 @@ interface
 
 uses
   SysUtils, Classes, Forms, Controls, Windows, ExtCtrls, Dialogs,
-  UCommonUI, UBlockChain, UAccounts, UNode, UWalletKeys, UAppParams, UConst, UFolderHelper, UGridUtils, URPC, UPoolMining,
+  UCommonUI, UBlockChain, UAccounts, UNode, UWallet, UConst, UFolderHelper, UGridUtils, URPC, UPoolMining,
   ULog, UThread, UNetProtocol, UCrypto,
   UFRMMainForm, UFRMSyncronizationForm, UFRMAccountExplorer, UFRMOperationExplorer, UFRMPendingOperations, UFRMOperation,
   UFRMLogs, UFRMMessages, UFRMNodes, UFRMBlockExplorer, UFRMWalletKeys;
@@ -27,10 +27,6 @@ type
 
   TLoadDatabaseThread = class;
 
-  { TMinerPrivateKey }
-
-  TMinerPrivateKey = (mpk_NewEachTime, mpk_Random, mpk_Selected);
-
   { TUserInterface }
 
   TUserInterface = class
@@ -50,12 +46,9 @@ type
       // Components
       FRPCServer : TRPCServer; static;
       FPoolMiningServer : TPoolMiningServer; static;
-      FMinerPrivateKeyType : TMinerPrivateKey; static;
-      FWalletKeys : TWalletKeysExt; static;
 
       // Local fields
       FStarted : boolean; static;
-      FAppParams : TAppParams; static;
       FMainForm : TFRMMainForm; static;
       FIsActivated : Boolean; static;
       FUpdating : Boolean; static;
@@ -72,7 +65,6 @@ type
 
       // Methods
       class procedure RefreshConnectionStatusDisplay;
-      class function GetAccountKeyForMiner: TAccountKey;
 
       // Getters/Setters
       class procedure SetStatusBar0Text(const text : AnsiString); static;
@@ -84,17 +76,13 @@ type
 
       // Aux methods
       class procedure FinishedLoadingDatabase;
-      class procedure LoadAppParams;
-      class procedure SaveAppParams;
-
-      // Notifiers
-      class procedure NotifyConfigChanged;
 
       // Handlers
       class procedure OnTimerUpdateStatusTimer(Sender: TObject);
       class procedure OnSubFormDestroyed(Sender: TObject);
 
       // Backend Handlers (TODO: refactor this out with TNotifyManyEvents)
+      class procedure OnSettingsChanged(Sender: TObject);
       class procedure OnAccountsChanged(Sender: TObject);
       class procedure OnBlocksChanged(Sender: TObject);
       class procedure OnReceivedHelloMessage(Sender: TObject);
@@ -110,9 +98,7 @@ type
       class property Started : boolean read FStarted;
       class property Node : TNode read FNode;
       class property Log : TLog read FLog;
-      class property AppParams : TAppParams read FAppParams;
       class property PoolMiningServer : TPoolMiningServer read FPoolMiningServer;
-      class property WalletKeys : TWalletKeysExt read FWalletKeys;
       class property MainFormMode : TFRMMainFormMode read GetMainFormMode write SetMainFormMode;
       class property StatusBar0Text : AnsiString read FStatusBar0Text write SetStatusBar0Text;
       class property StatusBar1Text : AnsiString read FStatusBar1Text write SetStatusBar1Text;
@@ -132,14 +118,17 @@ type
       class procedure ShowOperationInfoDialog(parentForm: TForm; const ophash : AnsiString);
       class procedure ShowOperationInfoDialog(parentForm: TForm; const operation : TOperationResume); overload;
       class procedure ShowNewOperationDialog(parentForm : TForm; accounts : TOrderedCardinalList; defaultFee : Cardinal);
-      class procedure ShowWalletKeysDialog(parentForm : TForm);
       class procedure ShowSeedNodesDialog(parentForm : TForm);
       class procedure ShowPrivateKeysDialog(parentForm: TForm);
       class procedure ShowMemoText(parentForm: TForm; const ATitle : AnsiString; text : TStrings);
-      class procedure UnlockWallet(parentForm: TForm;  walletKeys : TWalletKeys);
-      class procedure ChangeWalletPassword(parentForm: TForm; walletKeys : TWalletKeys);
-      class function AskQuestion(parentForm: TForm; const ACaption, APrompt : String; buttons: TMsgDlgButtons) : TMsgDlgBtn;
-      class function AskUserEnterString(parentForm: TForm; const ACaption, APrompt : String; var Value : String) : Boolean;
+      class procedure UnlockWallet(parentForm: TForm);
+      class procedure ChangeWalletPassword(parentForm: TForm);
+      class procedure ShowInfo(parentForm : TForm; const ACaption, APrompt : String);
+      class procedure ShowWarning(parentForm : TForm; const ACaption, APrompt : String);
+      class procedure ShowError(parentForm : TForm; const ACaption, APrompt : String);
+      class function AskQuestion(parentForm: TForm; AType:TMsgDlgType; const ACaption, APrompt : String; buttons: TMsgDlgButtons) : TMsgDlgBtn;
+      class function AskEnterString(parentForm: TForm; const ACaption, APrompt : String; var Value : String) : Boolean;
+      class function AskEnterProtectedString(parentForm: TForm; const ACaption, APrompt : String; var Value : String) : Boolean;
 
       // Show sub-forms
       class procedure ShowAccountExplorer;
@@ -164,7 +153,7 @@ implementation
 
 uses
   UFRMAbout, UFRMNodesIp, UFRMPascalCoinWalletConfig, UFRMPayloadDecoder, UFRMMemoText,
-  UOpenSSL, UFileStorage, UTime, UCommon;
+  UOpenSSL, UFileStorage, UTime, UCommon, USettings;
 
 {%region UI Lifecyle}
 
@@ -218,31 +207,23 @@ begin
     If Not ForceDirectories(TFolderHelper.GetPascalCoinDataFolder) then
       raise Exception.Create('Cannot create dir: '+TFolderHelper.GetPascalCoinDataFolder);
 
-    // Open AppParams
-    TUserInterface.FAppParams := TAppParams.Create(FMainForm);
-    TUserInterface.FAppParams.FileName := TFolderHelper.GetPascalCoinDataFolder+PathDelim+'AppParams.prm';
+    // Load settings
+    TSettings.Load;
+    TSettings.OnChanged.Add(OnSettingsChanged);
 
     // Open Wallet
-    Try
-      FWalletKeys := TWalletKeysExt.Create(FMainForm);  // On Activate, this will be populated
-      FWalletKeys.WalletFileName := TFolderHelper.GetPascalCoinDataFolder+PathDelim+'WalletKeys.dat';
-    Except
-      On E:Exception do begin
-        E.Message := 'Cannot open your wallet... Perhaps another instance of Pascal Coin is active!'+#10+#10+E.Message;
-        Raise;
-      end;
-    End;
+    TWallet.Load;
 
     // Load peer list
-    ips := FAppParams.ParamByName[CT_PARAM_TryToConnectOnlyWithThisFixedServers].GetAsString('');
+    ips := TSettings.TryConnectOnlyWithThisFixedServers;
     TNode.DecodeIpStringToNodeServerAddressArray(ips,nsarr);
     TNetData.NetData.DiscoverFixedServersOnly(nsarr);
     setlength(nsarr,0);
 
     // Start Node
     FNode := TNode.Node;
-    FNode.NetServer.Port := FAppParams.ParamByName[CT_PARAM_InternetServerPort].GetAsInteger(CT_NetServer_Port);
-    FNode.PeerCache := FAppParams.ParamByName[CT_PARAM_PeerCache].GetAsString('')+';'+CT_Discover_IPs;
+    FNode.NetServer.Port := TSettings.InternetServerPort;
+    FNode.PeerCache := TSettings.PeerCache+';'+CT_Discover_IPs;
 
     // Subscribe to Node events (TODO refactor with FNotifyEvents)
     FNodeNotifyEvents := TNodeNotifyEvents.Create(FMainForm);
@@ -251,10 +232,10 @@ begin
 
     // Start RPC server
     FRPCServer := TRPCServer.Create;
-    FRPCServer.WalletKeys := WalletKeys;
-    FRPCServer.Active := FAppParams.ParamByName[CT_PARAM_JSONRPCEnabled].GetAsBoolean(false);
-    FRPCServer.ValidIPs := FAppParams.ParamByName[CT_PARAM_JSONRPCAllowedIPs].GetAsString('127.0.0.1');
-    WalletKeys.SafeBox := FNode.Bank.SafeBox;
+    FRPCServer.WalletKeys := TWallet.Keys;
+    FRPCServer.Active := TSettings.RpcPortEnabled;
+    FRPCServer.ValidIPs := TSettings.RpcAllowedIPs;
+    TWallet.Keys.SafeBox := FNode.Bank.SafeBox;
 
     // Initialise Database
     FNode.Bank.StorageClass := TFileStorage;
@@ -276,9 +257,6 @@ begin
     FTimerUpdateStatus.Interval := 1000;
     FTimerUpdateStatus.Enabled := true;
 
-    // Load app params
-    LoadAppParams;
-
     // open the sync dialog
     FMainForm.SyncControl.UpdateBlockChainState;   //TODO fix this work-flow
     RefreshConnectionStatusDisplay;
@@ -309,11 +287,12 @@ begin
   // Show sync dialog
   ShowSyncDialog;
 
-  // Show about box if first time load
-  if FAppParams.ParamByName[CT_PARAM_FirstTime].GetAsBoolean(true) then begin
-    FAppParams.ParamByName[CT_PARAM_FirstTime].SetAsBoolean(false);
+  // Final loading sequence
+  TSettings.RunCount := TSettings.RunCount + 1;
+  if TSettings.RunCount = 1 then begin
     ShowAboutBox(nil);
   end;
+  TSettings.Save;
 end;
 
 class procedure TUserInterface.ExitApplication;
@@ -324,8 +303,9 @@ begin
   // Exit application
   TLog.NewLog(ltinfo,Classname,'Quit Application - START');
   Try
-    step := 'Saving params';
-    SaveAppParams;
+    step := 'Saving Settings';
+    TSettings.OnChanged.Remove(OnSettingsChanged);
+    TSettings.Save;
 
     // Destroys root form, non-modal forms and all their attached components
     step := 'Destroying UI graph';
@@ -339,8 +319,6 @@ begin
     FNodesForm := nil;  // destroyed by FWallet
     FMessagesForm := nil;  // destroyed by FWallet
     FTrayIcon := nil; // destroyed by FWallet
-    FAppParams := nil; // destroyed by FWallet
-    FWalletKeys := nil; // destroyed by FWallet
     FNodeNotifyEvents := nil; // destroyed by FWallet
 
     step := 'Destroying components';
@@ -407,11 +385,11 @@ end;
 class procedure TUserInterface.FinishedLoadingDatabase;
 begin
   FPoolMiningServer := TPoolMiningServer.Create;
-  FPoolMiningServer.Port := FAppParams.ParamByName[CT_PARAM_JSONRPCMinerServerPort].GetAsInteger(CT_JSONRPCMinerServer_Port);
-  FPoolMiningServer.MinerAccountKey := GetAccountKeyForMiner;
-  FPoolMiningServer.MinerPayload := FAppParams.ParamByName[CT_PARAM_MinerName].GetAsString('');
-  FNode.Operations.AccountKey := GetAccountKeyForMiner;
-  FPoolMiningServer.Active := FAppParams.ParamByName[CT_PARAM_JSONRPCMinerServerActive].GetAsBoolean(true);
+  FPoolMiningServer.Port := TSettings.MinerServerRpcPort;
+  FPoolMiningServer.MinerAccountKey := TWallet.MiningKey;
+  FPoolMiningServer.MinerPayload := TSettings.MinerName;
+  FNode.Operations.AccountKey := TWallet.MiningKey;
+  FPoolMiningServer.Active := TSettings.MinerServerRpcActive;
   FPoolMiningServer.OnMiningServerNewBlockFound := OnMiningServerNewBlockFound;
   FMainForm.SyncControl.OnFinishedLoadingDatabase;
   FMainForm.OnFinishedLoadingDatabase;
@@ -437,12 +415,7 @@ class procedure TUserInterface.ShowOptionsDialog(parentForm: TForm);
 begin
   With TFRMPascalCoinWalletConfig.Create(parentForm) do
   try
-    AppParams := FAppParams;
-    WalletKeys := FWalletKeys;
-    if ShowModal=MrOk then begin
-      SaveAppParams;
-      NotifyConfigChanged;
-    end;
+    ShowModal
   finally
     Free;
   end;
@@ -452,7 +425,7 @@ class procedure TUserInterface.ShowOperationInfoDialog(parentForm: TForm; const
 begin
   with TFRMPayloadDecoder.Create(parentForm) do
   try
-    Init(CT_TOperationResume_NUL, TUserInterface.WalletKeys,TUserInterface.AppParams);
+    Init(CT_TOperationResume_NUL);
     if ophash <> '' then
       DoFind(ophash);
     ShowModal;
@@ -465,7 +438,7 @@ class procedure TUserInterface.ShowOperationInfoDialog(parentForm: TForm; const
 begin
   with TFRMPayloadDecoder.Create(parentForm) do
   try
-    Init(operation, TUserInterface.WalletKeys,TUserInterface.AppParams);
+    Init(operation);
     ShowModal;
   finally
     Free;
@@ -481,25 +454,12 @@ begin
   Try
     SenderAccounts.CopyFrom(accounts);
     DefaultFee := defaultFee;
-    WalletKeys := FWalletKeys;
     ShowModal;
   Finally
     Free;
   End;
 end;
 
-class procedure TUserInterface.ShowWalletKeysDialog(parentForm : TForm);
-var FRM : TFRMWalletKeys;
-begin
-  FRM := TFRMWalletKeys.Create(parentForm);
-  Try
-    FRM.WalletKeys := FWalletKeys;
-    FRM.ShowModal;
-  Finally
-    FRM.Free;
-  End;
-end;
-
 class procedure TUserInterface.ShowSeedNodesDialog(parentForm : TForm);
 Var FRM : TFRMNodesIp;
 begin
@@ -515,12 +475,12 @@ class procedure TUserInterface.ShowPrivateKeysDialog(parentForm: TForm);
 Var FRM : TFRMWalletKeys;
 begin
   FRM := TFRMWalletKeys.Create(parentForm);
-  Try
-    FRM.WalletKeys := FWalletKeys;
+  try
+    //FRM.WalletKeys := FWalletKeys;
     FRM.ShowModal;
-  Finally
+  finally
     FRM.Free;
-  End;
+  end;
 end;
 
 class procedure TUserInterface.ShowMemoText(parentForm: TForm; const ATitle : AnsiString; text : TStrings);
@@ -536,40 +496,63 @@ begin
   end;
 end;
 
-class procedure TUserInterface.ChangeWalletPassword(parentForm: TForm; walletKeys : TWalletKeys);
-Var s,s2 : String;
+class procedure TUserInterface.ChangeWalletPassword(parentForm: TForm);
+var
+  s,s2 : String;
+  locked : boolean;
 begin
-  if walletKeys = nil then walletKeys := FWalletKeys;
   s := ''; s2 := '';
-  if Not InputQuery('Change password','Enter new password',s) then exit;
-  if trim(s)<>s then raise Exception.Create('Password cannot start or end with a space character');
-  if Not InputQuery('Change password','Enter new password again',s2) then exit;
-  if s<>s2 then raise Exception.Create('Two passwords are different!');
-
-  walletKeys.WalletPassword := s;
-  Application.MessageBox(PChar('Password changed!'+#10+#10+
-    'Please note that your new password is "'+s+'"'+#10+#10+
-    '(If you lose this password, you will lose your wallet forever!)'),
-    PChar(Application.Title),MB_ICONWARNING+MB_OK);
-end;
-
-class procedure TUserInterface.UnlockWallet(parentForm: TForm; walletKeys : TWalletKeys);
+  locked := (NOT TWallet.Keys.HasPassword) OR (NOT TWallet.Keys.IsValidPassword);
+  if Not AskEnterProtectedString(parentForm, 'Change password','Enter new password',s)
+    then exit;
+  if trim(s)<>s then
+    raise Exception.Create('Password cannot start or end with a space character');
+  if Not AskEnterProtectedString(parentForm, 'Change password', 'Enter new password again',s2)
+    then exit;
+  if s<>s2 then
+    raise Exception.Create('Two passwords are different!');
+  TWallet.Keys.WalletPassword := s;
+  if locked then
+    TWallet.Keys.LockWallet;
+
+  ShowWarning(parentform,
+  'Password Changed',
+  'Your password has been changed.' + #10+#10 +
+  'Please ensure you remember your password.'+#10+
+  'If you lose your password your accounts and funds will be lost forever.');
+end;
+
+class procedure TUserInterface.UnlockWallet(parentForm: TForm);
 Var s : String;
 begin
-  if walletKeys = nil then walletKeys := FWalletKeys;
   s := '';
   Repeat
-    if Not InputQuery('Wallet password','Enter wallet password',s) then exit;
-    walletKeys.WalletPassword := s;
-    if Not walletKeys.IsValidPassword then Application.MessageBox(PChar('Invalid password'),PChar(Application.Title),MB_ICONERROR+MB_OK);
-  Until walletKeys.IsValidPassword;
-  //UpdateWalletKeys;
+    if Not AskEnterProtectedString(parentForm, 'Wallet password','Enter wallet password',s) then exit;
+    TWallet.Keys.WalletPassword := s;
+    if Not TWallet.Keys.IsValidPassword then
+      ShowError(parentForm, 'Invalid Password', 'The password you have entered is incorrect.');
+  Until TWallet.Keys.IsValidPassword;
 end;
 
-class function TUserInterface.AskQuestion(parentForm: TForm; const ACaption, APrompt : String; buttons: TMsgDlgButtons) : TMsgDlgBtn;
+class procedure TUserInterface.ShowInfo(parentForm : TForm; const ACaption, APrompt : String);
+begin
+  MessageDlg(ACaption, APrompt, mtInformation, [mbOK], 0, mbOK);
+end;
+
+class procedure TUserInterface.ShowWarning(parentForm : TForm; const ACaption, APrompt : String);
+begin
+  MessageDlg(ACaption, APrompt, mtWarning, [mbOK], 0, mbOK);
+end;
+
+class procedure TUserInterface.ShowError(parentForm : TForm; const ACaption, APrompt : String);
+begin
+  MessageDlg(ACaption, APrompt, mtError, [mbOK], 0, mbOK);
+end;
+
+class function TUserInterface.AskQuestion(parentForm: TForm; AType:TMsgDlgType; const ACaption, APrompt : String; buttons: TMsgDlgButtons) : TMsgDlgBtn;
 var modalResult : TModalResult;
 begin
-  modalResult := MessageDlg(ACaption, APrompt, mtConfirmation, Buttons, 0, mbNo);
+  modalResult := MessageDlg(ACaption, APrompt, AType, Buttons, 0, mbNo);
   case modalResult of
     mrYes: Result := mbYes;
     mrNo: Result := mbNo;
@@ -586,11 +569,16 @@ begin
   end;
 end;
 
-class function TUserInterface.AskUserEnterString(parentForm: TForm; const ACaption, APrompt : String; var Value : String) : Boolean;
+class function TUserInterface.AskEnterString(parentForm: TForm; const ACaption, APrompt : String; var Value : String) : Boolean;
 begin
   Result := InputQuery(ACaption, APrompt, Value);
 end;
 
+class function TUserInterface.AskEnterProtectedString(parentForm: TForm; const ACaption, APrompt : String; var Value : String) : Boolean;
+begin
+  Result := InputQuery(ACaption, APrompt, true, Value);
+end;
+
 {%endregion}
 
 {%region Show Forms}
@@ -732,41 +720,6 @@ begin
   end;
 end;
 
-class function TUserInterface.GetAccountKeyForMiner: TAccountKey;
-Var PK : TECPrivateKey;
-  i : Integer;
-  PublicK : TECDSA_Public;
-begin
-  Result := CT_TECDSA_Public_Nul;
-  if Not Assigned(FWalletKeys) then exit;
-  if Not Assigned(FAppParams) then exit;
-  case FMinerPrivateKeyType of
-    mpk_NewEachTime: PublicK := CT_TECDSA_Public_Nul;
-    mpk_Selected: begin
-      PublicK := TAccountComp.RawString2Accountkey(FAppParams.ParamByName[CT_PARAM_MinerPrivateKeySelectedPublicKey].GetAsString(''));
-    end;
-  else
-    // Random
-    PublicK := CT_TECDSA_Public_Nul;
-    if FWalletKeys.Count>0 then PublicK := FWalletKeys.Key[Random(FWalletKeys.Count)].AccountKey;
-  end;
-  i := FWalletKeys.IndexOfAccountKey(PublicK);
-  if i>=0 then begin
-    if (FWalletKeys.Key[i].CryptedKey='') then i:=-1;
-  end;
-  if i<0 then begin
-    PK := TECPrivateKey.Create;
-    try
-      PK.GenerateRandomPrivateKey(CT_Default_EC_OpenSSL_NID);
-      FWalletKeys.AddPrivateKey('New for miner '+DateTimeToStr(Now), PK);
-      PublicK := PK.PublicKey;
-    finally
-      PK.Free;
-    end;
-  end;
-  Result := PublicK;
-end;
-
 class procedure TUserInterface.RefreshConnectionStatusDisplay;
 var errors : AnsiString;
 begin
@@ -791,49 +744,8 @@ end;
 
 {%endregion}
 
-{%region Auxillary methods}
-
-class procedure TUserInterface.SaveAppParams;
-Var ms : TMemoryStream;
-  s : AnsiString;
-begin
-  // Disabled in V2 (Herman)
-  FAppParams.ParamByName[CT_PARAM_GridAccountsStream].SetAsString('');
-  //ms := TMemoryStream.Create;
-  //Try
-  //  AccountExplorer.AccountsGrid.SaveToStream(ms);
-  //  ms.Position := 0;
-  //  setlength(s,ms.Size);
-  //  ms.ReadBuffer(s[1],ms.Size);
-  //  FAppParams.ParamByName[CT_PARAM_GridAccountsStream].SetAsString(s);
-  //Finally
-  //  ms.Free;
-  //End;
-end;
 
-class procedure TUserInterface.LoadAppParams;
-Var
-  s : AnsiString;
-  fvi : TFileVersionInfo;
-begin
-  // Disabled in V2 (HS)
-  //ms := TMemoryStream.Create;
-  //Try
-  //  s := FAppParams.ParamByName[CT_PARAM_GridAccountsStream].GetAsString('');
-  //  ms.WriteBuffer(s[1],length(s));
-  //  ms.Position := 0;
-  //  // Disabled on V2: FAccountsGrid.LoadFromStream(ms);
-  //Finally
-  //  ms.Free;
-  //End;
-  If FAppParams.FindParam(CT_PARAM_MinerName)=Nil then begin
-    // New configuration... assigning a new random value
-    fvi := TFolderHelper.GetTFileVersionInfo(Application.ExeName);
-    FAppParams.ParamByName[CT_PARAM_MinerName].SetAsString('New Node '+DateTimeToStr(Now)+' - '+
-      fvi.InternalName+' Build:'+fvi.FileVersion);
-  end;
-  NotifyConfigChanged;
-end;
+{%region Auxillary methods}
 
 class procedure TUserInterface.SetMainFormMode(AMode: TFRMMainFormMode);
 begin
@@ -850,42 +762,6 @@ begin
   Result := FMainForm.Mode;
 end;
 
-class procedure TUserInterface.NotifyConfigChanged;
-Var wa : Boolean;
-  i : Integer;
-begin
-  if FAppParams.ParamByName[CT_PARAM_SaveLogFiles].GetAsBoolean(false) then begin
-    if FAppParams.ParamByName[CT_PARAM_SaveDebugLogs].GetAsBoolean(false) then FLog.SaveTypes := CT_TLogTypes_ALL
-    else FLog.SaveTypes := CT_TLogTypes_DEFAULT;
-    FLog.FileName := TFolderHelper.GetPascalCoinDataFolder+PathDelim+'PascalCointWallet.log';
-  end else begin
-    FLog.SaveTypes := [];
-    FLog.FileName := '';
-  end;
-  if Assigned(FNode) then begin
-    wa := FNode.NetServer.Active;
-    FNode.NetServer.Port := FAppParams.ParamByName[CT_PARAM_InternetServerPort].GetAsInteger(CT_NetServer_Port);
-    FNode.NetServer.Active := wa;
-    FNode.Operations.BlockPayload := FAppParams.ParamByName[CT_PARAM_MinerName].GetAsString('');
-    FNode.NodeLogFilename := TFolderHelper.GetPascalCoinDataFolder+PathDelim+'blocks.log';
-  end;
-  if Assigned(FPoolMiningServer) then begin
-    if FPoolMiningServer.Port<>FAppParams.ParamByName[CT_PARAM_JSONRPCMinerServerPort].GetAsInteger(CT_JSONRPCMinerServer_Port) then begin
-      FPoolMiningServer.Active := false;
-      FPoolMiningServer.Port := FAppParams.ParamByName[CT_PARAM_JSONRPCMinerServerPort].GetAsInteger(CT_JSONRPCMinerServer_Port);
-    end;
-    FPoolMiningServer.Active :=FAppParams.ParamByName[CT_PARAM_JSONRPCMinerServerActive].GetAsBoolean(true);
-    FPoolMiningServer.UpdateAccountAndPayload(GetAccountKeyForMiner,FAppParams.ParamByName[CT_PARAM_MinerName].GetAsString(''));
-  end;
-  if Assigned(FRPCServer) then begin
-    FRPCServer.Active := FAppParams.ParamByName[CT_PARAM_JSONRPCEnabled].GetAsBoolean(false);
-    FRPCServer.ValidIPs := FAppParams.ParamByName[CT_PARAM_JSONRPCAllowedIPs].GetAsString('127.0.0.1');
-  end;
-  i := FAppParams.ParamByName[CT_PARAM_MinerPrivateKeyType].GetAsInteger(Integer(mpk_Random));
-  if (i>=Integer(Low(TMinerPrivatekey))) And (i<=Integer(High(TMinerPrivatekey))) then FMinerPrivateKeyType := TMinerPrivateKey(i)
-  else FMinerPrivateKeyType := mpk_Random;
-end;
-
 class procedure TUserInterface.SetStatusBar0Text(const text : AnsiString); static;
 begin
   FStatusBar0Text := text;
@@ -921,6 +797,41 @@ end;
 
 {%region Handlers -- TODO: many need to be refactored out with TNotifyManyEvent}
 
+class procedure TUserInterface.OnSettingsChanged(Sender: TObject);
+Var wa : Boolean;
+  i : Integer;
+begin
+  if TSettings.SaveLogFiles then begin
+    if TSettings.SaveDebugLogs then
+      FLog.SaveTypes := CT_TLogTypes_ALL
+    else
+      FLog.SaveTypes := CT_TLogTypes_DEFAULT;
+    FLog.FileName := TFolderHelper.GetPascalCoinDataFolder+PathDelim+'PascalCointWallet.log';
+  end else begin
+    FLog.SaveTypes := [];
+    FLog.FileName := '';
+  end;
+  if Assigned(FNode) then begin
+    wa := FNode.NetServer.Active;
+    FNode.NetServer.Port := TSettings.InternetServerPort;
+    FNode.NetServer.Active := wa;
+    FNode.Operations.BlockPayload := TSettings.MinerName;
+    FNode.NodeLogFilename := TFolderHelper.GetPascalCoinDataFolder+PathDelim+'blocks.log';
+  end;
+  if Assigned(FPoolMiningServer) then begin
+    if FPoolMiningServer.Port <> TSettings.MinerServerRpcPort then begin
+      FPoolMiningServer.Active := false;
+      FPoolMiningServer.Port := TSettings.MinerServerRpcPort;
+    end;
+    FPoolMiningServer.Active :=TSettings.MinerServerRpcActive;
+    FPoolMiningServer.UpdateAccountAndPayload(TWallet.MiningKey, TSettings.MinerName);
+  end;
+  if Assigned(FRPCServer) then begin
+    FRPCServer.Active := TSettings.RpcPortEnabled;
+    FRPCServer.ValidIPs := TSettings.RpcAllowedIPs;
+  end;
+end;
+
 class procedure TUserInterface.OnAccountsChanged(Sender: TObject);
 begin
   FUILock.Acquire;
@@ -976,7 +887,7 @@ begin
     if (s<>'') then s := s+';';
     s := s + nsarr[i].ip+':'+IntToStr( nsarr[i].port );
   end;
-  FAppParams.ParamByName[CT_PARAM_PeerCache].SetAsString(s);
+  TSettings.PeerCache := s;
   TNode.Node.PeerCache := s;
 end;
 
@@ -1038,7 +949,7 @@ end;
 class procedure TUserInterface.OnMiningServerNewBlockFound(Sender: TObject);
 begin
   // No lock required
-  FPoolMiningServer.MinerAccountKey := GetAccountKeyForMiner;
+  FPoolMiningServer.MinerAccountKey := TWallet.MiningKey;
 end;
 
 class procedure TUserInterface.OnTimerUpdateStatusTimer(Sender: TObject);

+ 92 - 0
Units/Forms/Wizards/UWIZAddKey.pas

@@ -0,0 +1,92 @@
+unit UWIZAddKey;
+
+{$mode delphi}
+
+{ Copyright (c) 2018 by Herman Schoenfeld
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+}
+
+interface
+
+uses
+  Classes, SysUtils, Forms, UWizard;
+
+type
+
+  { TFRMAddKeyModel }
+  TWIZAddKeyAction = (akaGenerateKey, akaImportPrivateKey, akaImportPublicKey);
+  TWIZAddKeyModel = class(TComponent)
+    public
+      Name : String;
+      KeyText : String;
+      Password : String;
+      EncryptionTypeNID : word;
+      Action : TWIZAddKeyAction;
+  end;
+
+  { TWIZAddKeyWizard }
+
+  TWIZAddKeyWizard = class(TWizard<TWIZAddKeyModel>)
+    public
+      constructor Create(AOwner: TComponent); override;
+      function DetermineHasNext : boolean; override;
+      function DetermineHasPrevious : boolean;  override;
+      function FinishRequested(out message : AnsiString) : boolean; override;
+      function CancelRequested(out message : AnsiString) : boolean; override;
+  end;
+
+implementation
+
+uses
+  UCrypto,
+  UWallet,
+  UWIZAddKey_Start,
+  UWIZAddKey_GenerateOrImport,
+  UWIZAddKey_ImportPubKey,
+  UWIZAddKey_ImportPrivKey,
+  UWIZAddKey_EnterName;
+
+constructor TWIZAddKeyWizard.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner, [TWIZAddKey_Start, TWIZAddKey_EnterName]);
+  TitleText := 'Add Key';
+  FinishText := 'Add Key';
+end;
+
+function TWIZAddKeyWizard.DetermineHasNext : boolean;
+begin
+  Result := NOT (CurrentScreen is TWIZAddKey_EnterName);
+end;
+
+function TWIZAddKeyWizard.DetermineHasPrevious : boolean;
+begin
+  Result := inherited DetermineHasPrevious;
+end;
+
+function TWIZAddKeyWizard.FinishRequested(out message : AnsiString) : boolean;
+begin
+  // Execute the key addition here
+  try
+    Result := true;
+    case Model.Action of
+      akaGenerateKey: TWallet.GenerateNewKey(Model.Name, Model.EncryptionTypeNID);
+      akaImportPrivateKey: TWallet.ImportPrivateKey(Model.Name, Model.KeyText, Model.Password);
+      akaImportPublicKey: TWallet.ImportPublicKey(Model.Name, Model.KeyText);
+    end;
+  except
+      On E:Exception do begin
+        Result := false;
+        message := E.ToString;
+      end;
+  end;
+end;
+
+function TWIZAddKeyWizard.CancelRequested(out message : AnsiString) : boolean;
+begin
+  Result := true;
+end;
+
+end.
+

+ 28 - 0
Units/Forms/Wizards/UWIZAddKey_EnterName.lfm

@@ -0,0 +1,28 @@
+object WIZAddKey_EnterName: TWIZAddKey_EnterName
+  Left = -665
+  Height = 100
+  Top = 643
+  Width = 334
+  Caption = 'WIZAddKey_EnterName'
+  ClientHeight = 100
+  ClientWidth = 334
+  LCLVersion = '1.6.4.0'
+  object Label2: TLabel
+    Left = 17
+    Height = 15
+    Top = 16
+    Width = 130
+    Caption = 'Enter a name for this key'
+    ParentColor = False
+    WordWrap = True
+  end
+  object txtName: TEdit
+    Left = 17
+    Height = 23
+    Top = 40
+    Width = 299
+    Anchors = [akTop, akLeft, akRight]
+    AutoSize = False
+    TabOrder = 0
+  end
+end

+ 55 - 0
Units/Forms/Wizards/UWIZAddKey_EnterName.pas

@@ -0,0 +1,55 @@
+unit UWIZAddKey_EnterName;
+
+{$mode delphi}
+
+{ Copyright (c) 2018 by Herman Schoenfeld
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+}
+
+interface
+
+uses
+  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
+  ExtCtrls, UWizard, UWIZAddKey;
+
+type
+
+  { TWIZAddKey_EnterName }
+
+  TWIZAddKey_EnterName = class(TWizardForm<TWIZAddKeyModel>)
+    txtName: TEdit;
+    Label2: TLabel;
+  public
+    procedure OnPresent; override;
+    procedure OnNext; override;
+    function Validate(out message : AnsiString) : boolean; override;
+  end;
+
+implementation
+
+{$R *.lfm}
+
+{ TWIZAddKey_EnterName }
+
+procedure TWIZAddKey_EnterName.OnPresent;
+begin
+  txtName.Clear;
+  txtName.SetFocus;
+end;
+
+procedure TWIZAddKey_EnterName.OnNext;
+begin
+  Model.Name := Trim(txtName.Text);
+end;
+
+function TWIZAddKey_EnterName.Validate(out message : AnsiString) : boolean;
+begin
+  Result := Length(Trim(txtName.Text)) > 0;
+  if not result then
+    message := 'Name is empty or whitespace';
+end;
+
+end.
+

+ 65 - 0
Units/Forms/Wizards/UWIZAddKey_GenerateOrImport.lfm

@@ -0,0 +1,65 @@
+object WIZAddKey_GenerateOrImport: TWIZAddKey_GenerateOrImport
+  Left = 500
+  Height = 285
+  Top = 383
+  Width = 448
+  Caption = 'Add Key'
+  ClientHeight = 285
+  ClientWidth = 448
+  LCLVersion = '1.6.4.0'
+  object rbPrivateKey: TRadioButton
+    Left = 32
+    Height = 19
+    Top = 56
+    Width = 175
+    Caption = 'Generate a new private key'
+    Checked = True
+    Font.Style = [fsBold]
+    ParentFont = False
+    TabOrder = 0
+    TabStop = True
+  end
+  object rbPublicKey: TRadioButton
+    Left = 32
+    Height = 19
+    Top = 168
+    Width = 188
+    Caption = 'Import an existing private key'
+    Font.Style = [fsBold]
+    ParentFont = False
+    TabOrder = 1
+  end
+  object Label1: TLabel
+    Left = 32
+    Height = 32
+    Top = 16
+    Width = 370
+    Anchors = [akTop, akLeft, akRight]
+    AutoSize = False
+    Caption = 'How will the private key be added into your wallet?'
+    ParentColor = False
+    WordWrap = True
+  end
+  object Label2: TLabel
+    Left = 52
+    Height = 64
+    Top = 80
+    Width = 352
+    Anchors = [akTop, akLeft, akRight]
+    AutoSize = False
+    Caption = 'Use this option to generate a brand new private key which will only exist on your machine. You will then be able to export this key and import it into other machines.'
+    ParentColor = False
+    WordWrap = True
+  end
+  object Label3: TLabel
+    Left = 48
+    Height = 66
+    Top = 192
+    Width = 350
+    Anchors = [akTop, akLeft, akRight]
+    AutoSize = False
+    Caption = 'Use this option to import a private key that you have exported from another wallet.'
+    ParentColor = False
+    WordWrap = True
+  end
+end

+ 49 - 0
Units/Forms/Wizards/UWIZAddKey_GenerateOrImport.pas

@@ -0,0 +1,49 @@
+unit UWIZAddKey_GenerateOrImport;
+
+{$mode delphi}
+
+{ Copyright (c) 2018 by Herman Schoenfeld
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+}
+
+interface
+
+uses
+  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
+  UWizard, UWIZAddKey;
+
+type
+
+  { TWIZAddKey_GenerateOrImport }
+
+  TWIZAddKey_GenerateOrImport = class(TWizardForm<TWIZAddKeyModel>)
+    Label1: TLabel;
+    Label2: TLabel;
+    Label3: TLabel;
+    rbPrivateKey: TRadioButton;
+    rbPublicKey: TRadioButton;
+  public
+    procedure OnNext; override;
+  end;
+
+implementation
+
+{$R *.lfm}
+
+uses UWIZAddKey_ImportPrivKey, UWIZAddKey_SelectEncryption, UWIZAddKey_EnterName;
+
+procedure TWIZAddKey_GenerateOrImport.OnNext;
+begin
+  if rbPrivateKey.Checked then begin
+    Model.Action := akaGenerateKey;
+    UpdatePath(ptReplaceAllNext, [TWIZAddKey_SelectEncryption, TWIZAddKey_EnterName])
+  end else begin
+    Model.Action := akaImportPrivateKey;
+    UpdatePath(ptReplaceAllNext, [TWIZAddKey_ImportPrivKey, TWIZAddKey_EnterName])
+  end;
+end;
+
+end.
+

+ 51 - 0
Units/Forms/Wizards/UWIZAddKey_ImportPrivKey.lfm

@@ -0,0 +1,51 @@
+object WIZAddKey_ImportPrivKey: TWIZAddKey_ImportPrivKey
+  Left = -679
+  Height = 225
+  Top = 316
+  Width = 438
+  Caption = 'WIZAddKey_ImportPrivKey'
+  ClientHeight = 225
+  ClientWidth = 438
+  LCLVersion = '1.6.4.0'
+  object Label1: TLabel
+    Left = 32
+    Height = 32
+    Top = 16
+    Width = 362
+    Anchors = [akTop, akLeft, akRight]
+    AutoSize = False
+    Caption = 'Enter the encrypted private key that you have exported from another wallet. '
+    ParentColor = False
+    WordWrap = True
+  end
+  object Label2: TLabel
+    Left = 25
+    Height = 24
+    Top = 160
+    Width = 362
+    Anchors = [akTop, akLeft, akRight]
+    AutoSize = False
+    Caption = 'Enter the password used to encrypt the key when it was exported.'
+    ParentColor = False
+    WordWrap = True
+  end
+  object txtPassword: TEdit
+    Left = 24
+    Height = 23
+    Top = 184
+    Width = 386
+    Anchors = [akTop, akLeft, akRight]
+    AutoSize = False
+    EchoMode = emPassword
+    PasswordChar = '*'
+    TabOrder = 1
+  end
+  object txtPrivateKey: TMemo
+    Left = 24
+    Height = 88
+    Top = 56
+    Width = 385
+    Anchors = [akTop, akLeft, akRight]
+    TabOrder = 0
+  end
+end

+ 66 - 0
Units/Forms/Wizards/UWIZAddKey_ImportPrivKey.pas

@@ -0,0 +1,66 @@
+unit UWIZAddKey_ImportPrivKey;
+
+{$mode delphi}
+
+{ Copyright (c) 2018 by Herman Schoenfeld
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+}
+
+interface
+
+uses
+  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
+  UWizard, UWIZAddKey;
+
+type
+
+  { TWIZAddKey_ImportPrivKey }
+
+  TWIZAddKey_ImportPrivKey = class(TWizardForm<TWIZAddKeyModel>)
+    txtPassword: TEdit;
+    Label1: TLabel;
+    Label2: TLabel;
+    txtPrivateKey: TMemo;
+  public
+    procedure OnPresent; override;
+    procedure OnNext; override;
+    function Validate(out message : AnsiString) : boolean; override;
+  end;
+
+implementation
+
+{$R *.lfm}
+
+uses UCrypto, UWallet;
+
+{ TWIZAddKey_ImportPrivKey }
+
+procedure TWIZAddKey_ImportPrivKey.OnPresent;
+begin
+  txtPrivateKey.Clear;
+  txtPassword.Clear;
+  txtPrivateKey.SetFocus;
+end;
+
+procedure TWIZAddKey_ImportPrivKey.OnNext;
+begin
+  Model.KeyText := txtPrivateKey.Text;
+  Model.Password := txtPassword.Text;
+end;
+
+function TWIZAddKey_ImportPrivKey.Validate(out message : AnsiString) : boolean;
+var
+  privateKey : TECPrivateKey;
+begin
+  try
+    Result := TWallet.TryDecryptPrivateKey(txtPrivateKey.Text, txtPassword.Text, privateKey, message);
+  finally
+    if Assigned(privateKey) then
+      privateKey.Free;
+  end;
+end;
+
+end.
+

+ 29 - 0
Units/Forms/Wizards/UWIZAddKey_ImportPubKey.lfm

@@ -0,0 +1,29 @@
+object WIZAddKey_ImportPubKey: TWIZAddKey_ImportPubKey
+  Left = -722
+  Height = 253
+  Top = 31
+  Width = 429
+  Caption = 'WIZAddKey_ImportPubKey'
+  ClientHeight = 253
+  ClientWidth = 429
+  LCLVersion = '1.6.4.0'
+  object Label1: TLabel
+    Left = 32
+    Height = 32
+    Top = 16
+    Width = 370
+    Anchors = [akTop, akLeft, akRight]
+    AutoSize = False
+    Caption = 'Enter the public key either in the PascalCoin encoding format or raw hex format.'
+    ParentColor = False
+    WordWrap = True
+  end
+  object txtPublicKey: TMemo
+    Left = 24
+    Height = 160
+    Top = 56
+    Width = 379
+    Anchors = [akTop, akLeft, akRight, akBottom]
+    TabOrder = 0
+  end
+end

+ 59 - 0
Units/Forms/Wizards/UWIZAddKey_ImportPubKey.pas

@@ -0,0 +1,59 @@
+unit UWIZAddKey_ImportPubKey;
+
+{$mode delphi}
+
+{ Copyright (c) 2018 by Herman Schoenfeld
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+}
+
+interface
+
+uses
+  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
+  UWizard, UWIZAddKey;
+
+type
+
+  { TWIZAddKey_ImportPubKey }
+
+  TWIZAddKey_ImportPubKey = class(TWizardForm<TWIZAddKeyModel>)
+    Label1: TLabel;
+    txtPublicKey: TMemo;
+  public
+    procedure OnPresent; override;
+    procedure OnNext; override;
+    function Validate(out message : AnsiString) : boolean; override;
+  end;
+
+
+implementation
+
+{$R *.lfm}
+
+uses UAccounts;
+
+{ TWIZAddKey_ImportPubKey }
+
+
+procedure TWIZAddKey_ImportPubKey.OnPresent;
+begin
+  txtPublicKey.Clear;
+  txtPublicKey.SetFocus;
+end;
+
+procedure TWIZAddKey_ImportPubKey.OnNext;
+begin
+  Model.KeyText := txtPublicKey.Text;
+end;
+
+function TWIZAddKey_ImportPubKey.Validate(out message : AnsiString) : boolean;
+var
+  accountKey : TAccountKey;
+begin
+   Result := TAccountComp.AccountPublicKeyImport(txtPublicKey.Text, accountKey, message);
+end;
+
+end.
+

+ 33 - 0
Units/Forms/Wizards/UWIZAddKey_SelectEncryption.lfm

@@ -0,0 +1,33 @@
+object WIZAddKey_SelectEncryption: TWIZAddKey_SelectEncryption
+  Left = -1207
+  Height = 240
+  Top = 90
+  Width = 320
+  Caption = 'WIZAddKey_SelectEncryption'
+  ClientHeight = 240
+  ClientWidth = 320
+  OnCreate = FormCreate
+  LCLVersion = '1.6.4.0'
+  object rgKeyType: TRadioGroup
+    Left = 24
+    Height = 209
+    Top = 16
+    Width = 278
+    Anchors = [akTop, akLeft, akRight, akBottom]
+    AutoFill = True
+    Caption = 'Select the type of encryption:'
+    ChildSizing.LeftRightSpacing = 6
+    ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
+    ChildSizing.EnlargeVertical = crsHomogenousChildResize
+    ChildSizing.ShrinkHorizontal = crsScaleChilds
+    ChildSizing.ShrinkVertical = crsScaleChilds
+    ChildSizing.Layout = cclLeftToRightThenTopToBottom
+    ChildSizing.ControlsPerLine = 1
+    ClientHeight = 189
+    ClientWidth = 274
+    Items.Strings = (
+      'asdf'
+    )
+    TabOrder = 0
+  end
+end

+ 62 - 0
Units/Forms/Wizards/UWIZAddKey_SelectEncryption.pas

@@ -0,0 +1,62 @@
+unit UWIZAddKey_SelectEncryption;
+
+{$mode delphi}
+
+interface
+
+uses
+  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls, UWizard, UWIZAddKey;
+
+type
+
+  { TWIZAddKey_SelectEncryption }
+
+  TWIZAddKey_SelectEncryption = class(TWizardForm<TWIZAddKeyModel>)
+    rgKeyType: TRadioGroup;
+    procedure FormCreate(Sender: TObject);
+  public
+    procedure OnNext; override;
+    function Validate(out message : AnsiString) : boolean; override;
+  end;
+
+implementation
+
+{$R *.lfm}
+
+uses UAccounts;
+
+{ TWIZAddKey_SelectEncryption }
+
+procedure TWIZAddKey_SelectEncryption.FormCreate(Sender: TObject);
+var
+  i : Integer;
+  availableEncryptionTypes : TList;
+begin
+  rgKeyType.Items.Clear;
+  availableEncryptionTypes := TList.Create;
+  try
+    TAccountComp.ValidsEC_OpenSSL_NID(availableEncryptionTypes);
+    for i := 0 to availableEncryptionTypes.Count - 1 do begin
+      rgKeyType.Items.AddObject(TAccountComp.GetECInfoTxt(PtrInt(availableEncryptionTypes[i])),availableEncryptionTypes[i]);
+    end;
+  finally
+    availableEncryptionTypes.free;
+  end;
+end;
+
+procedure TWIZAddKey_SelectEncryption.OnNext;
+begin
+  Self.Model.EncryptionTypeNID := PtrInt(rgKeyType.Items.Objects[rgKeyType.ItemIndex]);
+end;
+
+function TWIZAddKey_SelectEncryption.Validate(out message : AnsiString) : boolean;
+begin
+  Result := true;
+  if rgKeyType.ItemIndex < 0 then begin
+    message := 'A type of encryption must be selected';
+    Result := false;
+  end;
+end;
+
+end.
+

+ 65 - 0
Units/Forms/Wizards/UWIZAddKey_Start.lfm

@@ -0,0 +1,65 @@
+object WIZAddKey_Start: TWIZAddKey_Start
+  Left = 26
+  Height = 300
+  Top = 27
+  Width = 437
+  Caption = 'Add Key'
+  ClientHeight = 300
+  ClientWidth = 437
+  LCLVersion = '1.6.4.0'
+  object rbPrivateKey: TRadioButton
+    Left = 32
+    Height = 19
+    Top = 56
+    Width = 84
+    Caption = 'Private Key'
+    Checked = True
+    Font.Style = [fsBold]
+    ParentFont = False
+    TabOrder = 1
+    TabStop = True
+  end
+  object rbPublicKey: TRadioButton
+    Left = 32
+    Height = 19
+    Top = 168
+    Width = 144
+    Caption = 'Watch-only Public Key'
+    Font.Style = [fsBold]
+    ParentFont = False
+    TabOrder = 0
+  end
+  object Label1: TLabel
+    Left = 32
+    Height = 32
+    Top = 16
+    Width = 370
+    Anchors = [akTop, akLeft, akRight]
+    AutoSize = False
+    Caption = 'What type of key would you like to add into your wallet?'
+    ParentColor = False
+    WordWrap = True
+  end
+  object Label2: TLabel
+    Left = 52
+    Height = 64
+    Top = 80
+    Width = 352
+    Anchors = [akTop, akLeft, akRight]
+    AutoSize = False
+    Caption = 'Adding a private key allows you to send operations from accounts bound to this key. Please ensure your wallet is adequately protected if using this option since sensitive information is stored on your machine.'
+    ParentColor = False
+    WordWrap = True
+  end
+  object Label3: TLabel
+    Left = 48
+    Height = 66
+    Top = 192
+    Width = 350
+    Anchors = [akTop, akLeft, akRight]
+    AutoSize = False
+    Caption = 'A watch-only key allows you to track accounts that are bound to this key but without the ability to authorize new operations. There is no sensitive information kept on your machine when using this option.'
+    ParentColor = False
+    WordWrap = True
+  end
+end

+ 55 - 0
Units/Forms/Wizards/UWIZAddKey_Start.pas

@@ -0,0 +1,55 @@
+unit UWIZAddKey_Start;
+
+{$mode delphi}
+
+{ Copyright (c) 2018 by Herman Schoenfeld
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+}
+
+interface
+
+uses
+  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
+  UWizard, UWIZAddKey;
+
+type
+
+  { TWIZAddKey_Start }
+
+  TWIZAddKey_Start = class(TWizardForm<TWIZAddKeyModel>)
+    Label1: TLabel;
+    Label2: TLabel;
+    Label3: TLabel;
+    rbPrivateKey: TRadioButton;
+    rbPublicKey: TRadioButton;
+  private
+    { private declarations }
+  public
+    { public declarations }
+    procedure OnNext; override;
+  end;
+
+implementation
+
+{$R *.lfm}
+
+uses
+   UWIZAddKey_GenerateOrImport, UWIZAddKey_ImportPrivKey, UWIZAddKey_ImportPubKey, UWIZAddKey_EnterName;
+
+{ TWIZAddKey_Start }
+
+
+procedure TWIZAddKey_Start.OnNext;
+begin
+  if rbPublicKey.Checked = true then begin
+    Model.Action := akaImportPublicKey;
+    UpdatePath(ptReplaceAllNext, [TWIZAddKey_ImportPubKey, TWIZAddKey_EnterName]);
+  end else begin
+    UpdatePath(ptReplaceAllNext, [TWIZAddKey_GenerateOrImport, TWIZAddKey_ImportPrivKey]);//, TWIZAddKey_ImportPrivKey, TWIZAddKey_Finish]);
+  end;
+end;
+
+end.
+

+ 0 - 23
Units/PascalCoin/UConst.pas

@@ -141,29 +141,6 @@ Const
 
   CT_MAX_Operations_per_block_by_miner =  {$IFDEF PRODUCTION}10000{$ELSE}{$IFDEF TESTNET}50000{$ELSE}{$ENDIF}{$ENDIF};
 
-  // App Params
-  CT_PARAM_GridAccountsStream = 'GridAccountsStreamV2';
-  CT_PARAM_GridAccountsPos = 'GridAccountsPos';
-  CT_PARAM_DefaultFee = 'DefaultFee';
-  CT_PARAM_InternetServerPort = 'InternetServerPort';
-  {$IFDEF TESTNET}CT_PARAM_AutomaticMineWhenConnectedToNodes = 'AutomaticMineWhenConnectedToNodes';{$ENDIF}
-  CT_PARAM_MinerPrivateKeyType = 'MinerPrivateKeyType';
-  CT_PARAM_MinerPrivateKeySelectedPublicKey = 'MinerPrivateKeySelectedPublicKey';
-  CT_PARAM_SaveLogFiles = 'SaveLogFiles';
-  CT_PARAM_SaveDebugLogs = 'SaveDebugLogs';
-  CT_PARAM_ShowLogs = 'ShowLogs';
-  CT_PARAM_MinerName = 'MinerName';
-  CT_PARAM_FirstTime = 'FirstTime';
-  CT_PARAM_ShowModalMessages = 'ShowModalMessages';
-  {$IFDEF TESTNET}CT_PARAM_MaxCPUs = 'MaxCPUs'; {$ENDIF} //deprecated
-  CT_PARAM_PeerCache = 'PeerCache';
-  CT_PARAM_TryToConnectOnlyWithThisFixedServers = 'TryToConnectOnlyWithFixedServers';
-  CT_PARAM_JSONRPCMinerServerPort = 'JSONRPCMinerServerPort';
-  CT_PARAM_JSONRPCMinerServerActive = 'JSONRPCMinerServerActive';
-  CT_PARAM_JSONRPCEnabled = 'JSONRPCEnabled';
-  CT_PARAM_JSONRPCAllowedIPs = 'JSONRPCAllowedIPs';
-
-
 
 implementation
 

+ 43 - 17
Units/PascalCoin/UCrypto.pas

@@ -37,6 +37,7 @@ Type
      EC_OpenSSL_NID : Word;
      x: TRawBytes;
      y: TRawBytes;
+     class operator = (const a,b : TECDSA_Public) : boolean;
   end;
   PECDSA_Public = ^TECDSA_Public;
 
@@ -61,24 +62,25 @@ Type
     class Function ImportFromRaw(Const raw : TRawBytes) : TECPrivateKey; static;
   End;
 
-  TCrypto = Class
+  TCrypto = class
   private
   public
-    Class function ToHexaString(const raw : TRawBytes) : AnsiString;
-    Class function HexaToRaw(const HexaString : AnsiString) : TRawBytes;
-    Class function DoSha256(p : PAnsiChar; plength : Cardinal) : TRawBytes; overload;
-    Class function DoSha256(const TheMessage : AnsiString) : TRawBytes; overload;
-    Class procedure DoDoubleSha256(p : PAnsiChar; plength : Cardinal; Var ResultSha256 : TRawBytes); overload;
-    Class function DoRipeMD160_HEXASTRING(const TheMessage : AnsiString) : TRawBytes; overload;
-    Class function DoRipeMD160AsRaw(p : PAnsiChar; plength : Cardinal) : TRawBytes; overload;
-    Class function DoRipeMD160AsRaw(const TheMessage : AnsiString) : TRawBytes; overload;
-    Class function PrivateKey2Hexa(Key : PEC_KEY) : AnsiString;
-    Class function ECDSASign(Key : PEC_KEY; const digest : AnsiString) : TECDSA_SIG;
-    Class function ECDSAVerify(EC_OpenSSL_NID : Word; PubKey : EC_POINT; const digest : AnsiString; Signature : TECDSA_SIG) : Boolean; overload;
-    Class function ECDSAVerify(PubKey : TECDSA_Public; const digest : AnsiString; Signature : TECDSA_SIG) : Boolean; overload;
-    Class procedure InitCrypto;
-    Class function IsHumanReadable(Const ReadableText : TRawBytes) : Boolean;
-  End;
+    class function IsHexString(const AHexString: AnsiString) : boolean;
+    class function ToHexaString(const raw : TRawBytes) : AnsiString;
+    class function HexaToRaw(const HexaString : AnsiString) : TRawBytes;
+    class function DoSha256(p : PAnsiChar; plength : Cardinal) : TRawBytes; overload;
+    class function DoSha256(const TheMessage : AnsiString) : TRawBytes; overload;
+    class procedure DoDoubleSha256(p : PAnsiChar; plength : Cardinal; Var ResultSha256 : TRawBytes); overload;
+    class function DoRipeMD160_HEXASTRING(const TheMessage : AnsiString) : TRawBytes; overload;
+    class function DoRipeMD160AsRaw(p : PAnsiChar; plength : Cardinal) : TRawBytes; overload;
+    class function DoRipeMD160AsRaw(const TheMessage : AnsiString) : TRawBytes; overload;
+    class function PrivateKey2Hexa(Key : PEC_KEY) : AnsiString;
+    class function ECDSASign(Key : PEC_KEY; const digest : AnsiString) : TECDSA_SIG;
+    class function ECDSAVerify(EC_OpenSSL_NID : Word; PubKey : EC_POINT; const digest : AnsiString; Signature : TECDSA_SIG) : Boolean; overload;
+    class function ECDSAVerify(PubKey : TECDSA_Public; const digest : AnsiString; Signature : TECDSA_SIG) : Boolean; overload;
+    class procedure InitCrypto;
+    class function IsHumanReadable(const ReadableText : TRawBytes) : Boolean;
+  end;
 
   TBigNum = Class
   private
@@ -126,7 +128,7 @@ Const
 implementation
 
 uses
-  ULog, UConst, UAccounts;
+  UAES, ULog, UConst, UAccounts;
 
 Var _initialized : Boolean = false;
 
@@ -138,6 +140,16 @@ Begin
   end;
 End;
 
+{ TECDSA_Public }
+
+class operator TECDSA_Public.= (const a,b : TECDSA_Public) : boolean;
+begin
+  Result :=
+    (a.EC_OpenSSL_NID = b.EC_OpenSSL_NID) AND
+    (a.x = b.x) AND
+    (a.y = b.y);
+end;
+
 { TECPrivateKey }
 
 constructor TECPrivateKey.Create;
@@ -534,6 +546,20 @@ begin
   end;
 end;
 
+class function TCrypto.IsHexString(const AHexString: AnsiString) : boolean;
+var
+  i : Integer;
+begin
+  Result := true;
+  for i := Low(AHexString) to High(AHexString) do
+    if (NOT (AHexString[i] in ['0'..'9'])) AND
+       (NOT (AHexString[i] in ['a'..'f'])) AND
+       (NOT (AHexString[i] in ['A'..'F'])) then begin
+       Result := false;
+       exit;
+    end;
+end;
+
 { TBigNum }
 
 function TBigNum.Add(BN: TBigNum): TBigNum;

+ 1 - 1
Units/PascalCoin/URPC.pas

@@ -18,7 +18,7 @@ unit URPC;
 interface
 
 Uses UThread, ULog, UConst, UNode, UAccounts, UCrypto, UBlockChain,
-  UNetProtocol, UOpTransaction, UWalletKeys, UTime, UAES, UECIES,
+  UNetProtocol, UOpTransaction, UWallet, UTime, UAES, UECIES,
   UJSONFunctions, classes, blcksock, synsock, IniFiles, Variants, math;
 
 Const

+ 1 - 1
Units/PascalCoin/UServerApp.pas

@@ -17,7 +17,7 @@ uses
   Messages,
   {$ENDIF}
   SyncObjs,
-  UOpenSSL, UCrypto, UNode, UFileStorage, UFolderHelper, UWalletKeys, UConst, ULog, UNetProtocol,
+  UOpenSSL, UCrypto, UNode, UFileStorage, UFolderHelper, UWallet, UConst, ULog, UNetProtocol,
   URPC;
 
 type

+ 339 - 0
Units/PascalCoin/USettings.pas

@@ -0,0 +1,339 @@
+unit USettings;
+
+{$mode delphi}
+
+{ Copyright (c) 2018 by Herman Schoenfeld
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+}
+
+{$I ./../PascalCoin/config.inc}
+
+interface
+
+uses
+  UAppParams, UCommon;
+
+type
+
+  { TMinerPrivateKeyType }
+
+  TMinerPrivateKeyType = (mpk_NewEachTime, mpk_Random, mpk_Selected);
+
+  { TSettings }
+
+  TSettings = class
+    private
+      FOnChanged : TNotifyManyEvent; static;
+      FAppParams : TAppParams; static;
+      class function GetInternetServerPort : Integer; static;
+      class procedure SetInternetServerPort(AInt:Integer); static;
+      class function GetRpcPortEnabled : boolean; static;
+      class procedure SetRpcPortEnabled(ABool: boolean); static;
+      class function GetDefaultFee : Int64; static;
+      class procedure SetDefaultFee(AInt64: Int64); static;
+      class function GetMinerPrivateKeyType : TMinerPrivateKeyType; static;
+      class procedure SetMinerPrivateKeyType(AType: TMinerPrivateKeyType); static;
+      class function GetMinerSelectedPrivateKey : string; static;
+      class procedure SetMinerSelectedPrivateKey(AKey:string); static;
+      class function GetMinerServerRpcActive : boolean; static;
+      class procedure SetMinerServerRpcActive(ABool: Boolean); static;
+      class function GetMinerServerRpcPort : Integer; static;
+      class procedure SetMinerServerRpcPort(APort: Integer); static;
+      class function GetSaveLogFiles : boolean; static;
+      class procedure SetSaveLogFiles(ABool: boolean); static;
+      class function GetShowLogs : boolean; static;
+      class procedure SetShowLogs(ABool: boolean); static;
+      class function GetSaveDebugLogs : boolean; static;
+      class procedure SetSaveDebugLogs(ABool: boolean); static;
+      class function GetMinerName : string; static;
+      class procedure SetMinerName(AName: string); static;
+      class function GetRunCount : Integer; static;
+      class procedure SetRunCount(AInt: Integer); static;
+      class function GetShowModalMessages : boolean; static;
+      class procedure SetShowModalMessages(ABool: boolean); static;
+      class function GetRpcAllowedIPs : string; static;
+      class procedure SetRpcAllowedIPs(AString: string); static;
+      class function GetPeerCache : string; static;
+      class procedure SetPeerCache(AString: string); static;
+      class function GetTryConnectOnlyWithThisFixedServers : string; static;
+      class procedure SetTryConnectOnlyWithThisFixedServers(AString: string); static;
+      class procedure CheckLoaded;
+      class procedure NotifyOnChanged;
+    public
+      class procedure Load;
+      class procedure Save;
+      class property OnChanged : TNotifyManyEvent read FOnChanged write FOnChanged;
+      class property InternetServerPort : Integer read GetInternetServerPort write SetInternetServerPort;
+      class property RpcPortEnabled : boolean read GetRpcPortEnabled write SetRpcPortEnabled;
+      class property RpcAllowedIPs : string read GetRpcAllowedIPs write SetRpcAllowedIPs;
+      class property DefaultFee : Int64 read GetDefaultFee write SetDefaultFee;
+      class property MinerPrivateKeyType : TMinerPrivateKeyType read GetMinerPrivateKeyType write SetMinerPrivateKeyType;
+      class property MinerSelectedPrivateKey : string read GetMinerSelectedPrivateKey write SetMinerSelectedPrivateKey;
+      class property MinerServerRpcActive : boolean read GetMinerServerRpcActive write SetMinerServerRpcActive;
+      class property MinerServerRpcPort : Integer read GetMinerServerRpcPort write SetMinerServerRpcPort;
+      class property SaveLogFiles : boolean read GetSaveLogFiles write SetSaveLogFiles;
+      class property ShowLogs : boolean read GetShowLogs write SetShowLogs;
+      class property SaveDebugLogs : boolean read GetSaveDebugLogs write SetSaveDebugLogs;
+      class property MinerName : string read GetMinerName write SetMinerName;
+      class property RunCount : Integer read GetRunCount write SetRunCount;
+      class property ShowModalMessages : boolean read GetShowModalMessages write SetShowModalMessages;
+      class property PeerCache : string read GetPeerCache write SetPeerCache;
+      class property TryConnectOnlyWithThisFixedServers : string read GetTryConnectOnlyWithThisFixedServers write SetTryConnectOnlyWithThisFixedServers;
+      class property AppParams : TAppParams read FAppParams;
+  end;
+
+implementation
+
+uses
+  Classes, SysUtils, UConst, UFolderHelper;
+
+const
+  // App Params
+  CT_PARAM_DefaultFee = 'DefaultFee';
+  CT_PARAM_InternetServerPort = 'InternetServerPort';
+  {$IFDEF TESTNET}CT_PARAM_AutomaticMineWhenConnectedToNodes = 'AutomaticMineWhenConnectedToNodes';{$ENDIF}
+  CT_PARAM_MinerPrivateKeyType = 'MinerPrivateKeyType';
+  CT_PARAM_MinerPrivateKeySelectedPublicKey = 'MinerPrivateKeySelectedPublicKey';
+  CT_PARAM_SaveLogFiles = 'SaveLogFiles';
+  CT_PARAM_SaveDebugLogs = 'SaveDebugLogs';
+  CT_PARAM_ShowLogs = 'ShowLogs';
+  CT_PARAM_MinerName = 'MinerName';
+  CT_PARAM_RunCount = 'RunCount';
+  CT_PARAM_ShowModalMessages = 'ShowModalMessages';
+  {$IFDEF TESTNET}CT_PARAM_MaxCPUs = 'MaxCPUs'; {$ENDIF} //deprecated
+  CT_PARAM_PeerCache = 'PeerCache';
+  CT_PARAM_TryToConnectOnlyWithThisFixedServers = 'TryToConnectOnlyWithFixedServers';
+  CT_PARAM_JSONRPCMinerServerPort = 'JSONRPCMinerServerPort';
+  CT_PARAM_JSONRPCMinerServerActive = 'JSONRPCMinerServerActive';
+  CT_PARAM_JSONRPCEnabled = 'JSONRPCEnabled';
+  CT_PARAM_JSONRPCAllowedIPs = 'JSONRPCAllowedIPs';
+
+{ TSettings }
+
+class procedure TSettings.Load;
+begin
+  FAppParams := TAppParams.Create(nil);
+  FAppParams.FileName := TFolderHelper.GetPascalCoinDataFolder+PathDelim+'AppParams.prm';
+end;
+
+class procedure TSettings.Save;
+begin
+  //TODO Update FAppParams to optionally save on set value, and make FApp.Save public and verify all AppParams updates in client code
+end;
+
+class function TSettings.GetInternetServerPort : Integer;
+begin
+  CheckLoaded;
+  Result := FAppParams.ParamByName[CT_PARAM_InternetServerPort].GetAsInteger(CT_NetServer_Port);
+end;
+
+class procedure TSettings.SetInternetServerPort(AInt:Integer);
+begin
+  CheckLoaded;
+  FAppParams.ParamByName[CT_PARAM_InternetServerPort].SetAsInteger(AInt);
+end;
+
+class function TSettings.GetRpcPortEnabled : boolean;
+begin
+  CheckLoaded;
+  Result := FAppParams.ParamByName[CT_PARAM_JSONRPCEnabled].GetAsBoolean(false);
+end;
+
+class procedure TSettings.SetRpcPortEnabled(ABool: boolean);
+begin
+  CheckLoaded;
+  FAppParams.ParamByName[CT_PARAM_JSONRPCEnabled].SetAsBoolean(ABool);
+end;
+
+class function TSettings.GetRpcAllowedIPs : string;
+begin
+  CheckLoaded;
+  Result := FAppParams.ParamByName[CT_PARAM_JSONRPCAllowedIPs].GetAsString('127.0.0.1;');
+end;
+
+class procedure TSettings.SetRpcAllowedIPs(AString: string);
+begin
+  CheckLoaded;
+  FAppParams.ParamByName[CT_PARAM_JSONRPCAllowedIPs].SetAsString(AString);
+end;
+
+class function TSettings.GetDefaultFee : Int64;
+begin
+  CheckLoaded;
+  Result := FAppParams.ParamByName[CT_PARAM_DefaultFee].GetAsInt64(0);
+end;
+
+class procedure TSettings.SetDefaultFee(AInt64: Int64);
+begin
+  CheckLoaded;
+  FAppParams.ParamByName[CT_PARAM_DefaultFee].SetAsInt64(AInt64);
+end;
+
+class function TSettings.GetMinerServerRpcActive : boolean;
+begin
+  CheckLoaded;
+  Result := FAppParams.ParamByName[CT_PARAM_JSONRPCMinerServerActive].GetAsBoolean(true);
+end;
+
+class procedure TSettings.SetMinerServerRpcActive(ABool: Boolean);
+begin
+  CheckLoaded;
+  FAppParams.ParamByName[CT_PARAM_JSONRPCMinerServerActive].SetAsBoolean(ABool);
+end;
+
+class function TSettings.GetMinerServerRpcPort : Integer;
+begin
+  CheckLoaded;
+  Result := FAppParams.ParamByName[CT_PARAM_JSONRPCMinerServerPort].GetAsInteger(CT_JSONRPCMinerServer_Port);
+end;
+
+class procedure TSettings.SetMinerServerRpcPort(APort: Integer);
+begin
+  CheckLoaded;
+  FAppParams.ParamByName[CT_PARAM_JSONRPCMinerServerPort].SetAsInteger(APort)
+end;
+
+class function TSettings.GetMinerPrivateKeyType : TMinerPrivateKeyType;
+begin
+  CheckLoaded;
+  Result := TMinerPrivateKeyType(FAppParams.ParamByName[CT_PARAM_MinerPrivateKeyType].GetAsInteger(Integer(mpk_Random)))
+end;
+
+class procedure TSettings.SetMinerPrivateKeyType(AType: TMinerPrivateKeyType);
+begin
+  CheckLoaded;
+  FAppParams.ParamByName[CT_PARAM_MinerPrivateKeyType].SetAsInteger(Integer(AType));
+end;
+
+class function TSettings.GetMinerSelectedPrivateKey : string;
+begin
+  CheckLoaded;
+  Result := FAppParams.ParamByName[CT_PARAM_MinerPrivateKeySelectedPublicKey].GetAsString('');
+end;
+
+class procedure TSettings.SetMinerSelectedPrivateKey(AKey:string);
+begin
+  CheckLoaded;
+  FAppParams.ParamByName[CT_PARAM_MinerPrivateKeySelectedPublicKey].SetAsString(AKey);
+end;
+
+class function TSettings.GetSaveLogFiles : boolean;
+begin
+  CheckLoaded;
+  Result := FAppParams.ParamByName[CT_PARAM_SaveLogFiles].GetAsBoolean(false);
+end;
+
+class procedure TSettings.SetSaveLogFiles(ABool: boolean);
+begin
+  CheckLoaded;
+  FAppParams.ParamByName[CT_PARAM_SaveLogFiles].SetAsBoolean(ABool);
+end;
+
+class function TSettings.GetShowLogs : boolean;
+begin
+  CheckLoaded;
+  Result := FAppParams.ParamByName[CT_PARAM_ShowLogs].GetAsBoolean(false);
+end;
+
+class procedure TSettings.SetShowLogs(ABool: boolean);
+begin
+  CheckLoaded;
+  FAppParams.ParamByName[CT_PARAM_ShowLogs].SetAsBoolean(ABool);
+end;
+
+class function TSettings.GetSaveDebugLogs : boolean;
+begin
+  CheckLoaded;
+  Result := FAppParams.ParamByName[CT_PARAM_SaveDebugLogs].GetAsBoolean(false);
+end;
+
+class procedure TSettings.SetSaveDebugLogs(ABool: boolean);
+begin
+  CheckLoaded;
+  FAppParams.ParamByName[CT_PARAM_SaveDebugLogs].SetAsBoolean(ABool);
+end;
+
+class function TSettings.GetMinerName : string;
+begin
+  CheckLoaded;
+  Result := FAppParams.ParamByName[CT_PARAM_MinerName].GetAsString('Anonymous Miner')
+end;
+
+class procedure TSettings.SetMinerName(AName: string);
+begin
+  CheckLoaded;
+  FAppParams.ParamByName[CT_PARAM_MinerName].SetAsString(AName);
+end;
+
+class function TSettings.GetRunCount : Integer;
+begin
+  CheckLoaded;
+  Result := FAppParams.ParamByName[CT_PARAM_RunCount].GetAsInteger(0)
+end;
+
+class procedure TSettings.SetRunCount(AInt: Integer);
+begin
+  CheckLoaded;
+  FAppParams.ParamByName[CT_PARAM_RunCount].SetAsInteger(AInt)
+end;
+
+class function TSettings.GetShowModalMessages : boolean;
+begin
+  CheckLoaded;
+  Result := FAppParams.ParamByName[CT_PARAM_ShowModalMessages].GetAsBoolean(false);
+end;
+
+class procedure TSettings.SetShowModalMessages(ABool: boolean);
+begin
+  CheckLoaded;
+  FAppParams.ParamByName[CT_PARAM_ShowModalMessages].SetAsBoolean(ABool);
+end;
+
+class function TSettings.GetPeerCache : string;
+begin
+  CheckLoaded;
+  Result := FAppParams.ParamByName[CT_PARAM_PeerCache].GetAsString('');
+end;
+
+class procedure TSettings.SetPeerCache(AString: string);
+begin
+  CheckLoaded;
+  FAppParams.ParamByName[CT_PARAM_PeerCache].SetAsString(AString);
+end;
+
+class function TSettings.GetTryConnectOnlyWithThisFixedServers : string;
+begin
+  CheckLoaded;
+  Result := Trim(FAppParams.ParamByName[CT_PARAM_TryToConnectOnlyWithThisFixedServers].GetAsString(''));
+end;
+
+class procedure TSettings.SetTryConnectOnlyWithThisFixedServers(AString: string);
+begin
+  CheckLoaded;
+  FAppParams.ParamByName[CT_PARAM_TryToConnectOnlyWithThisFixedServers].SetAsString(Trim(AString));
+end;
+
+class procedure TSettings.CheckLoaded;
+begin
+  if not Assigned(FAppParams) then
+    raise Exception.Create('Application settings have not been loaded');
+end;
+
+class procedure TSettings.NotifyOnChanged;
+begin
+  FOnChanged.Invoke(nil);
+end;
+
+initialization
+  TSettings.FAppParams := nil;
+
+finalization
+  if Assigned(TSettings.FAppParams) then
+    FreeAndNil(TSettings.FAppParams);
+
+end.
+
+
+

+ 350 - 4
Units/PascalCoin/UWalletKeys.pas → Units/PascalCoin/UWallet.pas

@@ -1,4 +1,4 @@
-unit UWalletKeys;
+unit UWallet;
 
 {$mode delphi}
 
@@ -18,7 +18,7 @@ unit UWalletKeys;
 interface
 
 uses
-  Classes, UBlockChain, UAccounts, UCrypto, UCommon;
+  Classes, USettings, UBlockChain, UAccounts, UCrypto, UCommon;
 
 Type
   TWalletKey = Record
@@ -27,6 +27,7 @@ Type
     CryptedKey : TRawBytes;
     PrivateKey : TECPrivateKey;
     SearchableAccountKey : TRawBytes;
+    function HasPrivateKey : boolean;
   End;
 
   TWalletKeys = Class(TComponent)
@@ -78,23 +79,62 @@ Type
     Function AddPublicKey(Const Name : AnsiString; ECDSA_Public : TECDSA_Public) : Integer; override;
     Procedure Delete(index : Integer); override;
     Procedure Clear; override;
-    //
     Property AccountsKeyList : TOrderedAccountKeysList read FOrderedAccountKeysList;
     Property SafeBox : TPCSafeBox read GetSafeBox write SetSafeBox;
   End;
 
+  TRestoreWalletResult = record
+    TotalKeysFound : Integer;
+    ImportedPrivateKeys : Integer;
+    ImportedPublicKeys : Integer;
+    Duplicates : Integer;
+    Success : boolean;
+  end;
+
+  TWallet = class
+    private
+      FKeys : TWalletKeysExt; static;
+      class function GetKeys : TWalletKeysExt; static;
+      class function GetMiningKey : TAccountKey; static;
+      class procedure CheckLoaded;
+      class procedure CheckUnlocked;
+    public
+      class property Keys : TWalletKeysExt read GetKeys;
+      class property MiningKey : TAccountKey read GetMiningKey;
+      class procedure Load;
+      class function HasKey(const AKey: TWalletKey) : boolean;
+      class procedure DeleteKey(const AKey: TWalletKey);
+      class procedure GenerateNewKey(const AName: string; AEncryptionTypeNID : Word);
+      class function ExportPublicKey(const AKey: TWalletKey) : string;
+      class function ExportPrivateKey(const AKey: TWalletKey; const APassword: string) : string;
+      class procedure ImportPrivateKey(const AName, AKeyImportText, APassword: string);
+      class procedure ImportPublicKey(Const AName, AKeyImportText : string);
+      class function RestoreWallet(const AFileName, APassword: string) : TRestoreWalletResult;
+      class procedure BackupWallet(const AFileName: string);
+      class function TryDecryptPrivateKey(const AEncryptedKeyText, APassword:string; out APrivateKey : TECPrivateKey; out AMessage : string) : boolean;
+      class function TryParseEncryptedKey(const AKeyText, AKeyPassword : string; out AKey : TECPrivateKey) : boolean;
+      class function TryParseRawKey(const ARawBytes : TRawBytes; AEncryptionTypeNID : Word; out AKey : TECPrivateKey) : boolean;
+      class function TryParseHexKey(const AHexString : string; AEncryptionTypeNID : Word; out AKey : TECPrivateKey) : boolean;
+  end;
 
 Const CT_TWalletKey_NUL  : TWalletKey = (Name:'';AccountKey:(EC_OpenSSL_NID:0;x:'';y:'');CryptedKey:'';PrivateKey:Nil;SearchableAccountKey:'');
 
 implementation
 
 uses
-  SysUtils, UConst, ULog, UAES;
+  SysUtils, UConst, ULog, UAES, UFolderHelper;
 
 Const
   CT_PrivateKeyFile_Magic = 'TWalletKeys';
   CT_PrivateKeyFile_Version = 100;
 
+{ TWalletKey }
+
+function TWalletKey.HasPrivateKey : boolean;
+begin
+  Result := Length(Self.CryptedKey) > 0;
+end;
+
 { TWalletKeys }
 
 Type PWalletKey = ^TWalletKey;
@@ -122,6 +162,14 @@ begin
   end else begin
     P := FSearchableKeys[Result];
     P^.Name := Name;
+    if NOT P^.HasPrivateKey then begin
+      // overriding watch-only public key with full private/public key data, so double-check private key matches
+      if P^.AccountKey <> ECPrivateKey.PublicKey then
+        raise Exception.Create('[UWallet.pas] TWalletKeys.AddPrivateKey - consistency check failed when overriding watch-only key');
+      P^.CryptedKey := TAESComp.EVP_Encrypt_AES256(TCrypto.PrivateKey2Hexa(ECPrivateKey.PrivateKey), WalletPassword);
+      P^.PrivateKey := TECPrivateKey.Create;
+      P^.PrivateKey.SetPrivateKeyFromHexa(ECPrivateKey.EC_OpenSSL_NID, TCrypto.PrivateKey2Hexa(ECPrivateKey.PrivateKey));
+    end;
   end;
   if Not FIsReadingStream then SaveToStream(FWalletFileStream);
   FOnChanged.Invoke(Self);
@@ -136,6 +184,7 @@ begin
     P^ := CT_TWalletKey_NUL;
     P^.Name := Name;
     P^.AccountKey := ECDSA_Public;
+    P^.CryptedKey := '';
     P^.PrivateKey := Nil;
     P^.SearchableAccountKey := TAccountComp.AccountKey2RawString(ECDSA_Public);
     FSearchableKeys.Insert(Result,P);
@@ -458,4 +507,301 @@ begin
   end;
 end;
 
+{ TWallet }
+
+class function TWallet.GetMiningKey: TAccountKey;
+Var PK : TECPrivateKey;
+  i : Integer;
+  PublicK : TECDSA_Public;
+begin
+  CheckLoaded;
+  Result := CT_TECDSA_Public_Nul;
+  case TSettings.MinerPrivateKeyType of
+    mpk_NewEachTime: PublicK := CT_TECDSA_Public_Nul;
+    mpk_Selected: PublicK := TAccountComp.RawString2Accountkey(TSettings.MinerSelectedPrivateKey);
+    mpk_Random: begin
+      PublicK := CT_TECDSA_Public_Nul;
+      if FKeys.Count>0 then PublicK := FKeys.Key[Random(FKeys.Count)].AccountKey;
+    end;
+  end;
+  i := FKeys.IndexOfAccountKey(PublicK);
+  if i>=0 then begin
+    if (FKeys.Key[i].CryptedKey='') then i:=-1;
+  end else begin
+    // Generate a new key
+    PK := TECPrivateKey.Create;
+    try
+      PK.GenerateRandomPrivateKey(CT_Default_EC_OpenSSL_NID);
+      FKeys.AddPrivateKey('User Key '+FormatDateTime('YYYY-MM-DD hh:nn' ,Now), PK);
+      PublicK := PK.PublicKey;
+    finally
+      PK.Free;
+    end;
+  end;
+  Result := PublicK;
+end;
+
+class function TWallet.GetKeys : TWalletKeysExt; inline;
+begin
+  CheckLoaded;
+  Result := FKeys;
+end;
+
+class procedure TWallet.Load;
+begin
+  try
+    if not Assigned(FKeys) then
+      FKeys := TWalletKeysExt.Create(nil);
+    FKeys.WalletFileName := TFolderHelper.GetPascalCoinDataFolder+PathDelim+'WalletKeys.dat';
+  except
+    on E:Exception do begin
+      E.Message := 'Cannot open your wallet... Perhaps another instance of Pascal Coin is active!'+#10+#10+E.Message;
+      Raise;
+    end;
+  end;
+end;
+
+class function TWallet.HasKey(const AKey: TWalletKey) : boolean;
+begin
+  Result := FKeys.IndexOfAccountKey(AKey.AccountKey) >= 0;
+end;
+
+class procedure TWallet.DeleteKey(const AKey: TWalletKey);
+var
+  i : Integer;
+begin
+  CheckLoaded;
+  i := FKeys.IndexOfAccountKey(AKey.AccountKey);
+  if i >= 0 then
+    FKeys.Delete(i)
+  else
+    raise Exception.Create('Key not found');
+end;
+
+class procedure TWallet.GenerateNewKey(const AName: string; AEncryptionTypeNID : Word);
+var
+  privateKey : TECPrivateKey;
+begin
+  privateKey := TECPrivateKey.Create;
+  try
+    privateKey.GenerateRandomPrivateKey(AEncryptionTypeNID);
+    FKeys.AddPrivateKey(AName, privateKey);
+  finally
+    privateKey.Free;
+  end;
+end;
+
+class function TWallet.ExportPublicKey(const AKey: TWalletKey) : string;
+begin
+  Result := TAccountComp.AccountPublicKeyExport(AKey.AccountKey);
+end;
+
+class function TWallet.ExportPrivateKey(const AKey: TWalletKey; const APassword: string) : string;
+begin
+  Result := TCrypto.ToHexaString(TAESComp.EVP_Encrypt_AES256(AKey.PrivateKey.ExportToRaw, APassword));
+end;
+
+class procedure TWallet.ImportPrivateKey(const AName, AKeyImportText, APassword: string);
+var
+ message : String;
+ EC : TECPrivateKey;
+ i : Integer;
+begin
+  CheckLoaded;
+  CheckUnlocked;
+  try
+    if NOT TryDecryptPrivateKey(AKeyImportText, APassword, EC, message) then
+      raise Exception.Create(message);
+    i := FKeys.IndexOfAccountKey(EC.PublicKey);
+    if  i>=0  then
+      if FKeys.Key[i].HasPrivateKey then
+        raise Exception.Create('This key is already in your wallet!');
+    i := FKeys.AddPrivateKey(AName,EC);
+  finally
+    if Assigned(EC) then
+      EC.Free;
+  end;
+end;
+
+class procedure TWallet.ImportPublicKey(Const AName, AKeyImportText : string);
+var
+  raw, errors : AnsiString;
+  accountKey : TAccountKey;
+begin
+  CheckLoaded;
+  CheckUnlocked;
+  If not TAccountComp.AccountPublicKeyImport(AKeyImportText, accountKey, errors) then begin
+    raw := TCrypto.HexaToRaw(AKeyImportText);
+    if trim(raw)='' then
+      raise Exception.Create('Invalid public key value (Not hexa or not an imported format)'+#10+errors);
+    accountKey := TAccountComp.RawString2Accountkey(raw);
+  end;
+  If not TAccountComp.IsValidAccountKey(accountKey,errors) then
+    raise Exception.Create('This data is not a valid public key'+#10+errors);
+  if FKeys.IndexOfAccountKey(accountKey)>=0 then
+    raise exception.Create('This key exists on your wallet');
+  FKeys.AddPublicKey(AName, accountKey);
+end;
+
+class function TWallet.RestoreWallet(const AFileName, APassword: string) : TRestoreWalletResult;
+var
+  wki : TWalletKeys;
+  i, j : Integer;
+begin
+  CheckLoaded;
+  if NOT FileExists(AFileName) then
+    raise Exception.Create('File not found: ' + AFilename);
+
+  wki := TWalletKeys.Create(nil);
+  try
+    wki.WalletFileName := AFileName;
+    if wki.Count<=0 then
+      raise Exception.Create('Wallet file has no valid data');
+    Result.ImportedPrivateKeys := 0;
+    Result.ImportedPublicKeys := 0;
+    Result.Success := false;
+
+    // If password required, set it
+    if NOT wki.IsValidPassword then begin
+      wki.WalletPassword := APassword;
+      if NOT wki.IsValidPassword then
+        exit;
+    end;
+
+    // Import the keys
+    Result.TotalKeysFound:= wki.Count;
+    for i := 0 to wki.Count - 1 do begin
+      if NOT HasKey(wki.Key[i]) then begin
+        if wki.Key[i].HasPrivateKey then begin
+          TWallet.Keys.AddPrivateKey(wki.Key[i].Name, wki.Key[i].PrivateKey);
+          inc(Result.ImportedPrivateKeys);
+        end else begin
+          TWallet.Keys.AddPublicKey(wki.Key[i].Name, wki.Key[i].AccountKey);
+          inc(Result.ImportedPublicKeys);
+        end;
+      end else begin
+        j := FKeys.IndexOfAccountKey(wki[i].AccountKey);
+        // case: existing wallet has public key but import has private key
+        if (NOT FKeys[j].HasPrivateKey) AND (wki.Key[i].HasPrivateKey) then begin
+          TWallet.Keys.AddPrivateKey(wki.Key[i].Name, wki.Key[i].PrivateKey);
+          inc(Result.ImportedPrivateKeys);
+        end else Inc(Result.Duplicates);
+      end;
+    end;
+    result.Success := true;
+  finally
+    wki.Free;
+  end;
+end;
+
+class procedure TWallet.BackupWallet(const AFileName : string);
+var
+  fs : TFileStream;
+begin
+  CheckLoaded;
+  fs := TFileStream.Create(AFileName, fmCreate);
+  try
+    fs.Size := 0;
+    TWallet.Keys.SaveToStream(fs);
+  finally
+    fs.Free;
+  end;
+end;
+
+class function TWallet.TryDecryptPrivateKey(const AEncryptedKeyText, APassword:string; out APrivateKey : TECPrivateKey; out AMessage : string) : boolean;
+var
+ parseResult : Boolean;
+begin
+  APrivateKey := nil;
+  AMessage := '';
+  if NOT TCrypto.IsHexString(AEncryptedKeyText) then begin
+    Result := false;
+    AMessage := 'Invalid key text. You must enter a hexadecimal value ("0".."9" or "A".."F").';
+    exit;
+  end;
+  case Length(AEncryptedKeyText) div 2 of
+    32: parseResult := TryParseRawKey(AEncryptedKeyText, CT_NID_secp256k1, APrivateKey);
+    35,36: parseResult := TryParseRawKey(AEncryptedKeyText, CT_NID_sect283k1, APrivateKey);
+    48: parseResult := TryParseRawKey(AEncryptedKeyText, CT_NID_secp384r1, APrivateKey);
+    65,66: parseResult := TryParseRawKey(AEncryptedKeyText, CT_NID_secp521r1, APrivateKey);
+    64, 80, 96: parseResult := TryParseEncryptedKey(AEncryptedKeyText, APassword, APrivateKey);
+    else begin
+      result := false;
+      AMessage := 'Invalidly formatted private key string. Ensure it is an encrypted private key export or raw private key hexstring.';
+      exit;
+    end;
+  end;
+  if NOT parseResult then begin
+    Result := false;
+    if Length(AEncryptedKeyText) div 2 in [64, 80, 96] then
+      AMessage := 'Incorrect password'
+    else
+      AMessage := 'Unencrypted key data is invalid or corrupted';
+    if Assigned(APrivateKey) then FreeAndNil(APrivateKey);
+    exit;
+  end;
+  if Not Assigned(APrivateKey) then begin
+    Result := false;
+    AMessage := '[UWallet.pas] TWallet.ImportPrivateKey - expected non-null private key';
+    exit;
+  end;
+  Result := true;
+end;
+
+class function TWallet.TryParseEncryptedKey(const AKeyText, AKeyPassword : string; out AKey : TECPrivateKey) : boolean;
+var
+ decrypt : string;
+begin
+  AKey := nil;
+  if NOT TCrypto.IsHexString(AKeyText) then begin
+    Result := false;
+    exit;
+  end;
+  decrypt := '';
+  If (TAESComp.EVP_Decrypt_AES256(TCrypto.HexaToRaw(AKeyText),AKeyPassword,decrypt)) AND (decrypt<>'') then begin
+    AKey := TECPrivateKey.ImportFromRaw(decrypt);
+    Result := true;
+  end else begin
+    Result := false;
+  end;
+end;
+
+class function TWallet.TryParseRawKey(const ARawBytes : TRawBytes; AEncryptionTypeNID : Word; out AKey : TECPrivateKey) : boolean;
+begin
+  Result := TryParseHexKey(TCrypto.ToHexaString(ARawBytes), AEncryptionTypeNID, AKey);
+end;
+
+class function TWallet.TryParseHexKey(const AHexString : string; AEncryptionTypeNID : Word; out AKey : TECPrivateKey) : boolean;
+begin
+  AKey := TECPrivateKey.Create;
+  Try
+    AKey.SetPrivateKeyFromHexa(AEncryptionTypeNID, AHexString);
+    Result := True;
+  Except
+    On E:Exception do begin
+      FreeAndNil(AKey);
+      Result := false;
+    end;
+  end;
+end;
+
+class procedure TWallet.CheckLoaded;
+begin
+  if not Assigned(FKeys) then
+    raise Exception.Create('Wallet has not been loaded');
+end;
+
+class procedure TWallet.CheckUnlocked;
+begin
+  if NOT FKeys.IsValidPassword then
+    raise Exception.Create('Wallet is locked.');
+end;
+
+initialization
+  TWallet.FKeys := nil;
+
+finalization
+  if Assigned(TWallet.FKeys) then
+    FreeAndNil(TWallet.FKeys);
+
 end.

+ 1 - 1
Units/PascalCoin/upcdaemon.pas

@@ -19,7 +19,7 @@ interface
 
 uses
   Classes, SysUtils, daemonapp,
-  SyncObjs, UOpenSSL, UCrypto, UNode, UFileStorage, UFolderHelper, UWalletKeys, UConst, ULog, UNetProtocol,
+  SyncObjs, UOpenSSL, UCrypto, UNode, UFileStorage, UFolderHelper, UWallet, UConst, ULog, UNetProtocol,
   IniFiles,
   UThread, URPC, UPoolMining, UAccounts;
 

+ 6 - 6
Units/Utils/UAutoScope.pas

@@ -18,7 +18,7 @@
     Ver 1.0.0
     * Initial release.
  **********************************************************************}
-unit AutoScope;
+unit UAutoScope;
 {$IFDEF FPC}
   {$CODEPAGE UTF8}
   {$MODE DELPHI}{$H+}
@@ -36,10 +36,10 @@ interface
     {$IFDEF VER2_4}{$ERROR Too old compiller.}{$ENDIF}
   {$ENDIF}
   {$DEFINE USE_INTERFACE}
-  {$IFNDEF VER_3_0}
-    {$IFDEF USE_INTERFACE}{$UNDEF USE_INTERFACE}{$ENDIF}
-    {$DEFINE USE_OPERATORS}
-  {$ENDIF}
+  //{$IFNDEF VER_3_0}
+  //  {$IFDEF USE_INTERFACE}{$UNDEF USE_INTERFACE}{$ENDIF}
+  //  {$DEFINE USE_OPERATORS}
+  //{$ENDIF}
 {$ELSE}
   {$DEFINE USE_INTERFACE}
 {$ENDIF}
@@ -395,4 +395,4 @@ begin
   UnregisterPointer(P);
 end;
 
-end.
+end.

+ 1 - 1
Units/Utils/UGridUtils.pas

@@ -20,7 +20,7 @@ interface
 uses
   LCLIntf, LCLType, LMessages,
   Classes, Grids, UNode, UAccounts, UBlockChain, UAppParams,
-  UWalletKeys, UCrypto, UPoolMining, URPC;
+  UWallet, UCrypto, UPoolMining, URPC;
 
 Type
   // TAccountsGrid implements a visual integration of TDrawGrid

+ 2 - 2
Units/Utils/UWizard.lfm

@@ -1,7 +1,7 @@
 object WizardHostForm: TWizardHostForm
-  Left = 187
+  Left = 993
   Height = 120
-  Top = 35
+  Top = 640
   Width = 360
   BorderIcons = [biSystemMenu]
   Caption = 'Wizard'

+ 123 - 70
Units/Utils/UWizard.pas

@@ -5,9 +5,6 @@
 
   Distributed under the MIT software license, see the accompanying file LICENSE
   or visit http://www.opensource.org/licenses/mit-license.php.
-
-  Additional Credits:
-    <contributors add yourselves here>
 }
 
 unit UWizard;
@@ -27,11 +24,14 @@ const
   CT_WIZARD_DEFAULT_FINISH : AnsiString = '&Finish';
   CT_WIZARD_DEFAULT_TITLE : AnsiString = 'Wizard';
 
-
 type
   { Forward Declarations }
   TWizardForm<T> = class;
 
+  { Enums }
+
+  TPathUpdateType = (ptInject, ptReplaceAllNext, ptReplaceAll);
+
   { TWizardHostForm - the host form that contains the wizard screens. }
   TWizardHostForm = class(TForm)
     FHorizonalLine: TPanel;
@@ -73,11 +73,11 @@ type
   { TWizardForm is the base class for wizard screens }
   TWizardForm<T> = class(TForm)
     private
-      FBag : T;
+      FModel : T;
       //FWizard : TWizard<T>;  // FPG Bug: cyclic generic dependencies, via forward decls, don't work
     protected
-      InjectScreen : procedure (screen : TWizardForm<T>) of object;    // FPC Bug workaround: calling this is equivalent to FWizard.InjectScreen
-      property Bag : T read FBag write FBag;
+      UpdatePath : procedure (APathUpdateType: TPathUpdateType; const screens : array of TComponentClass) of object;    // FPC Bug workaround: calling this is equivalent to FWizard.InjectScreen
+      property Model : T read FModel write FModel;
 
     public
       procedure Initialize; virtual;
@@ -88,18 +88,19 @@ type
    end;
 
   { TWizard - Base class for wizards. Encapsulates the entire wizard flow. }
-  TWizard<T> = class
+  TWizard<T> = class(TComponent)
     type
       __TScreenType = TWizardForm<T>; // FPC Bug: doesn't support nested generics
-      TWizardFormList = TList<__TScreenType>;
-
+      __TList_TComponentClass = TList<TComponentClass>;
     private
         FHost : TWizardHostForm;
         FStarted : Boolean;
         FFinished : Boolean;
         FCurrentScreen : TWizardForm<T>;
-        FPropertyBag : T;
-        FScreens :  TWizardFormList;
+        FModel : T;
+        FScreenPath : TList<TComponentClass>;
+        FScreenPathBackup : TDictionary<SizeInt, __TList_TComponentClass>;
+        FScreenInstances : TDictionary<TComponentClass, __TScreenType>;
         FCurrentScreenIndex : Integer;
         FNextText : AnsiString;
         FPreviousText : AnsiString;
@@ -111,31 +112,32 @@ type
         procedure NextHandler(sender : TObject);
         procedure PreviousHandler(sender : TObject);
     protected
+        function CreateScreen(AType: TComponentClass) : TWizardForm<T>;
         function DetermineHasNext : boolean; virtual;
         function DetermineHasPrevious : boolean; virtual;
         procedure PresentScreen(screen : TWizardForm<T>); virtual;
         function FinishRequested(out message : AnsiString) : boolean; virtual; abstract;
         function CancelRequested(out message : AnsiString) : boolean; virtual; abstract;
     public
-        constructor Create(constref propertyBag : T; screens: array of TWizardForm<T>);
+        constructor Create(AOwner:TComponent; const screens: array of TComponentClass); overload;
         destructor Destroy; override;
-        property PropertyBag : T read FPropertyBag;
+        property CurrentScreen : TWizardForm<T> read FCurrentScreen;
+        property Model : T read FModel;
         property HasNext : boolean read DetermineHasNext;
         property HasPrevious : boolean read DetermineHasPrevious;
         property NextText : AnsiString read FNextText write FNextText;
         property PreviousText : AnsiString read FPreviousText write FPreviousText;
         property FinishText : AnsiString read FFinishText write FFinishText;
         property TitleText : AnsiString read FTitleText write FTitleText;
-        procedure Start(AOwner : TComponent); virtual;
+        procedure Start(constref model : T); virtual;
         procedure Next; virtual;
         procedure Previous; virtual;
-        procedure InjectScreen(screen : TWizardForm<T>); virtual;
-        procedure RemoveScreen(screen : TWizardForm<T>); virtual;
+        procedure UpdatePath(APathUpdateType: TPathUpdateType; const screens : array of TComponentClass); virtual;
   end;
 
   { TActioWizard Delegate Declarations }
-  TActionWizardCancelFunc<T> = function(screenIndex : Integer; constref propertyBag : T; out message : AnsiString) : boolean of object;
-  TActionWizardFinishFunc<T> = function(constref  propertyBag : T; out message : AnsiString) : boolean of object;
+  TActionWizardCancelFunc<T> = function(screenIndex : Integer; constref model : T; out message : AnsiString) : boolean of object;
+  TActionWizardFinishFunc<T> = function(constref  model : T; out message : AnsiString) : boolean of object;
 
   { TActionWizard - a generic Wizard that can be used without subclassing }
   TActionWizard<T> = class(specialize TWizard<T>)
@@ -146,8 +148,8 @@ type
       function CancelRequested(out message : AnsiString) : boolean; override;
       function FinishRequested(out message : AnsiString) : boolean; override;
     public
-      constructor Create(title, finish: AnsiString; constref bag : T; screens : array of TWizardForm<T>; cancelFunc: TActionWizardCancelFunc<T>; finishFunc : TActionWizardFinishFunc<T>);
-      class procedure Show(AOwner : TComponent; title, finish: AnsiString; constref bag : T; screens : array of TWizardForm<T>; cancelFunc: TActionWizardCancelFunc<T>; finishFunc : TActionWizardFinishFunc<T>);
+      constructor Create(AOwner:TComponent; title, finish: AnsiString; const screens : array of TComponentClass; cancelFunc: TActionWizardCancelFunc<T>; finishFunc : TActionWizardFinishFunc<T>);
+      class procedure Show(AParent: TForm; title, finish: AnsiString; constref bag : T; const screens : array of TComponentClass; cancelFunc: TActionWizardCancelFunc<T>; finishFunc : TActionWizardFinishFunc<T>);
       property FinishText : AnsiString read FTitleText;
       property TitleText : AnsiString read FFinishText;
   end;
@@ -294,11 +296,12 @@ end;
 
 {%region TWizard }
 
-constructor TWizard<T>.Create(constref propertyBag : T; screens: array of TWizardForm<T>);
+constructor TWizard<T>.Create(AOwner:TComponent; const screens: array of TComponentClass);
 var
    i : integer;
    screen : TWizardForm<T>;
 begin
+  inherited Create(AOwner);
   if Length(screens) = 0 then
     raise Exception.Create('Wizard needs at least 1 screen');
 
@@ -309,26 +312,47 @@ begin
   self.FTitleText := CT_WIZARD_DEFAULT_TITLE;
   self.FStarted := false;
   self.FFinished := false;
-  self.FPropertyBag := propertyBag;
-  self.FScreens := TWizardFormList.Create;
-  for i := Low(screens) to High(screens) do begin
-    screen := screens[i];
-    screen.InjectScreen := InjectScreen;
-    FScreens.Add(screen);
-  end;
+  self.FScreenPath := TList<TComponentClass>.Create;
+  self.FScreenInstances := TDictionary<TComponentClass, __TScreenType>.Create;
+
+  // Create the screen path
+  UpdatePath(ptReplaceAll, screens);
+  FScreenPathBackup := TDictionary<SizeInt, __TList_TComponentClass>.Create;
 end;
 
 destructor TWizard<T>.Destroy;
 var
   i : integer;
+  screen : TWizardForm<T>;
+  key : TComponentClass;
+  backup : TList<TComponentClass>;
 begin
-  for i:= 0 to FScreens.Count - 1 do begin
-    FScreens[i].Destroy;
+  // screens destroyed as sub-components
+  for screen in FScreenInstances.Values do begin
+    if screen.Owner = nil then
+      screen.Free; // only destroy if dangling screen component
   end;
-  FScreens.Destroy;
+  FScreenInstances.Free;
+  FScreenPath.Free;
+  for backup in FScreenPathBackup.Values do
+    backup.Free;
+  FScreenPathBackup.Free;
+  inherited Destroy;
   // note: Property bag not destroyed, left for user to destroy
 end;
 
+function TWizard<T>.CreateScreen(AType: TComponentClass) : TWizardForm<T>;
+begin
+  if NOT FScreenInstances.ContainsKey(AType) then begin
+    Result := TWizardForm<T>(AType.Create(self));
+    if Result = nil then
+      raise Exception.Create('Supplied type was not correct TWizardForm<T> type');
+    Result.UpdatePath := UpdatePath;
+    FScreenInstances.Add(AType, Result);
+    Result.Initialize;
+  end else Result := FScreenInstances[AType];
+end;
+
 function TWizard<T>.CalculateFitSize : TPoint;
 var
   maxWidth, maxHeight, i : Integer;
@@ -336,8 +360,7 @@ var
 begin
   maxWidth := 0;
   maxHeight := 0;
-  for i := 0 to self.FScreens.Count - 1 do begin
-    screen := self.FScreens[i];
+  for screen in FScreenInstances.Values do begin
     if screen.Width > maxWidth then maxWidth := screen.Width;
     if screen.Height > maxHeight then maxHeight := screen.Height;
   end;
@@ -347,7 +370,7 @@ end;
 function TWizard<T>.DetermineHasNext : boolean;
 begin
    CheckStarted;
-   DetermineHasNext := FCurrentScreenIndex < FScreens.Count - 1;
+   DetermineHasNext := FCurrentScreenIndex < FScreenPath.Count - 1;
 end;
 
 function TWizard<T>.DetermineHasPrevious : boolean;
@@ -356,12 +379,13 @@ begin
   DetermineHasPrevious := FCurrentScreenIndex > 0;
 end;
 
-procedure TWizard<T>.Start(AOwner : TComponent);
+procedure TWizard<T>.Start(constref model : T);
 var
   i : integer;
 begin
   CheckNotStarted;
-  self.FHost := TWizardHostForm.Create(AOwner);
+  self.FModel := model;
+  self.FHost := TWizardHostForm.Create(Self.GetParentComponent);
   self.FHost.NextEvent.Add(NextHandler);
   self.FHost.PreviousEvent.Add(PreviousHandler);
   self.FHost.CloseQueryEvent := CancelRequested;
@@ -371,14 +395,13 @@ begin
   self.FCurrentScreenIndex := 0;
   self.FStarted := true;
   self.FFinished := false;
-  for i := 0 to self.FScreens.Count - 1 do begin
-    FScreens[i].Bag := self.PropertyBag;
-    FScreens[i].Initialize;
-  end;
   self.FHost.SetContentSize ( CalculateFitSize );
-  self.PresentScreen(FScreens[FCurrentScreenIndex]);
+  self.FScreenPathBackup.Add(0, TList<TComponentClass>.Create(FScreenPath));
+  self.PresentScreen(FScreenInstances[FScreenPath[FCurrentScreenIndex]]);
+  //self.FHost.NextEvent.Remove(NextHandler);
+  //self.FHost.PreviousEvent.Remove(PreviousHandler);
   self.FHost.ShowModal;
-  self.FHost.Destroy;
+  self.FHost.Free;
   self.FHost := nil;
 end;
 
@@ -391,10 +414,16 @@ begin
     ShowMessage (message);
     exit;
   end;
-  FCurrentScreen.Next;
+  FCurrentScreen.OnNext;
+  FModel := FCurrentScreen.Model; // Restore model in case it's a record
   if HasNext then begin
     inc(FCurrentScreenIndex);
-    PresentScreen(FScreens[FCurrentScreenIndex]);
+    // Backup current path in case user goes back
+    if FScreenPathBackup.ContainsKey(FCurrentScreenIndex) then begin
+      FScreenPathBackup[FCurrentScreenIndex].Free;
+    end;
+    FScreenPathBackup.AddOrSetValue(FCurrentScreenIndex, TList<TComponentClass>.Create(FScreenPath));
+    PresentScreen(FScreenInstances[FScreenPath[FCurrentScreenIndex]]);
     exit;
   end;
 
@@ -409,30 +438,56 @@ procedure TWizard<T>.Previous;
 begin
   CheckStarted;
   if not HasPrevious then exit;
-  FCurrentScreen.Previous;
+  FCurrentScreen.OnPrevious;
+  FModel := FCurrentScreen.Model; // Restore model in case it's a record
   dec (FCurrentScreenIndex);
-  PresentScreen(FScreens[FCurrentScreenIndex]);
-end;
 
-procedure TWizard<T>.InjectScreen(screen : TWizardForm<T>);
-begin
-  CheckStarted;
-  screen.Initialize;
-  FScreens.Insert(FCurrentScreenIndex + 1, screen );
-  self.FHost.SetContentSize ( CalculateFitSize );
-  FHost.NextText := IIF(NOT HasNext, FinishText, NextText);
+  // Restore backup path when this screen was first displayed
+  FScreenPath.Free;
+  FScreenPath := TList<TComponentClass>.Create(FScreenPathBackup[FCurrentScreenIndex]);
+  PresentScreen(FScreenInstances[FScreenPath[FCurrentScreenIndex]]);
 end;
 
-procedure TWizard<T>.RemoveScreen(screen : TWizardForm<T>);
-begin
-  CheckStarted;
-  FScreens.Remove(screen);
-  screen.Destroy;
+procedure TWizard<T>.UpdatePath(APathUpdateType: TPathUpdateType; const screens : array of TComponentClass);
+var
+  i, n : SizeInt;
+begin
+  case APathUpdateType of
+    ptInject: begin
+      for i := Low(screens) to High(screens) do begin
+        n := FCurrentScreenIndex + 1 + i - Low(screens);
+        if FScreenPath[n] <> screens[i] then begin
+          // only insert screen if not already there
+          FScreenPath.Insert(n, screens[i]);
+          CreateScreen(screens[i]);
+        end;
+      end;
+    end;
+    ptReplaceAllNext: begin
+      FScreenPath.DeleteRange(FCurrentScreenIndex + 1, FScreenPath.Count - FCurrentScreenIndex - 1);
+      for i := Low(screens) to High(screens) do begin
+        FScreenPath.Add(screens[i]);
+        CreateScreen(screens[i]);
+      end;
+    end;
+    ptReplaceAll: begin
+      FScreenPath.Clear;
+      for i := Low(screens)to High(screens) do begin
+        FScreenPath.Add(screens[i]);
+        CreateScreen(screens[i]);
+      end;
+    end;
+  end;
+  if Assigned(FHost) then begin
+    FHost.SetContentSize ( CalculateFitSize );
+    FHost.NextText := IIF(NOT HasNext, FinishText, NextText);
+  end;
 end;
 
 procedure TWizard<T>.PresentScreen(screen : TWizardForm<T>);
 begin
   FCurrentScreen := screen;
+  FCurrentScreen.Model := Model;
   FHost.HidePrevious := NOT HasPrevious;
   FHost.NextText := IIF( NOT HasNext, FinishText, NextText);
   FHost.SetContent(screen);
@@ -459,45 +514,44 @@ begin
   Previous;
 end;
 
-
 {%endregion}
 
 {%region TActionWizard }
 
-constructor TActionWizard<T>.Create(title, finish: AnsiString; constref bag : T; screens : array of TWizardForm<T>; cancelFunc: TActionWizardCancelFunc<T>; finishFunc : TActionWizardFinishFunc<T>);
+constructor TActionWizard<T>.Create(AOwner: TComponent; title, finish: AnsiString; const screens : array of TComponentClass; cancelFunc: TActionWizardCancelFunc<T>; finishFunc : TActionWizardFinishFunc<T>);
 begin
-  inherited Create(bag, screens);
+  inherited Create(AOwner, screens);
   self.FTitleText := title;
   self.FFinishText := finishText;
   self.FCancelEvent := cancelFunc;
   self.FFinishEvent := finishFunc;
 end;
 
-class procedure TActionWizard<T>.Show(AOwner : TComponent; title, finish: AnsiString; constref bag : T; screens : array of TWizardForm<T>; cancelFunc: TActionWizardCancelFunc<T>; finishFunc : TActionWizardFinishFunc<T>);
+class procedure TActionWizard<T>.Show(AParent: TForm; title, finish: AnsiString; constref bag : T; const screens : array of TComponentClass; cancelFunc: TActionWizardCancelFunc<T>; finishFunc : TActionWizardFinishFunc<T>);
 type
   MyWizard = TActionWizard<T>;
 var
   wizard : MyWizard;
 begin
-  wizard := MyWizard.Create(title, finish, bag, screens, cancelFunc, finishFunc);
+  wizard := MyWizard.Create(nil, title, finish, screens, cancelFunc, finishFunc);
   try
-    wizard.Start(AOwner);
+    wizard.Start(bag);
   finally
-    wizard.Destroy;
+    wizard.Free;
   end;
 end;
 
 function TActionWizard<T>.CancelRequested(out message : AnsiString) : boolean;
 begin
   if Assigned(FCancelEvent) and NOT FFinished then
-    Result := FCancelEvent(Self.FCurrentScreenIndex, self.PropertyBag, message)
+    Result := FCancelEvent(Self.FCurrentScreenIndex, self.Model, message)
   else Result := true;
 end;
 
 function TActionWizard<T>.FinishRequested(out message : AnsiString) : boolean;
 begin
   if Assigned(FFinishEvent) then
-    Result := FFinishEvent(self.PropertyBag, message)
+    Result := FFinishEvent(self.Model, message)
   else Result := true;
   FFinished := true;
 end;
@@ -505,4 +559,3 @@ end;
 {%endregion}
 
 end.
-