OSDN Git Service

Various improvements to Delphi bindings.
authorLoRd_MuldeR <mulder2@gmx.de>
Sun, 7 Jan 2018 15:27:52 +0000 (16:27 +0100)
committerLoRd_MuldeR <mulder2@gmx.de>
Sun, 7 Jan 2018 15:27:52 +0000 (16:27 +0100)
bindings/Delphi/example/src/Main.pas
bindings/Delphi/library/MHash384.pas

index 017189f..a9d83ca 100644 (file)
@@ -28,7 +28,7 @@ interface
 
 uses
   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
-  Dialogs, StdCtrls, ComCtrls, MHash384;
+  Dialogs, StdCtrls, ComCtrls, SyncObjs, MHash384;
 
 type
   TMainForm = class(TForm)
@@ -44,13 +44,13 @@ type
     procedure Button_BrowseClick(Sender: TObject);
     procedure Button_ComputeClick(Sender: TObject);
     procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
-    procedure FormKeyDown(Sender: TObject; var Key: Word;
-      Shift: TShiftState);
+    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
   protected
     procedure ThreadTerminated(Sender: TObject);
     procedure ProgressChanged(progress: Integer);
+    procedure UpdateProgress(total: Integer; current: Integer; progress: Integer);
   private
-    { Private-Deklarationen }
+    AbortFlag: TSimpleEvent;
   public
     { Public-Deklarationen }
   end;
@@ -65,8 +65,9 @@ type
     inputFile, hashString: String;
     progressValue: Integer;
     progressEvent: TProgressEvent;
+    abortFlag: TSimpleEvent;
   public
-    constructor Create(const hwnd: HWND; const inputFile: String);
+    constructor Create(const hwnd: HWND; const inputFile: String; const abortFlag: TSimpleEvent);
     function GetResult: String;
     property OnProgress: TProgressEvent read progressEvent write progressEvent;
   protected
@@ -100,11 +101,13 @@ begin
   Constraints.MinWidth := Width;
   TMHash384.GetVersion(VersionMajor, VersionMinor, VersionPatch);
   Caption := 'MHashDelphi384 - Example App v' + Format('%d.%d.%d', [VersionMajor, VersionMinor, VersionPatch]);
+  AbortFlag := TSimpleEvent.Create();
 end;
 
 procedure TMainForm.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
 const
   F12: Word = $7B;
+  ESC: Word = $1B;
 begin
   if Key = F12 then
   begin
@@ -114,8 +117,16 @@ begin
     Edit_FileDigest.Text := 'Self-test is running, please be patient...';
     Application.ProcessMessages();
     try
-      TMHash384.SelfTest();
-      ShowMessage('Self-test completed successfully.');
+      try
+        TMHash384.SelfTest(UpdateProgress, AbortFlag);
+        ShowMessage('Self-test completed successfully.');
+      except
+        on E: Exception do
+        begin
+          MessageBox(Self.WindowHandle, PAnsiChar('Self-test has faild with an error!'#10#10'Details:'#10 + E.Message), PAnsiChar(String(E.ClassName)), MB_ICONERROR or MB_SYSTEMMODAL);
+          Exit;
+         end;
+      end;
     finally
       Button_Browse.Enabled := True;
       Button_Compute.Enabled := True;
@@ -123,6 +134,17 @@ begin
       Edit_FileDigest.Text := 'Self-test completed.';
     end;
   end;
+  if Key = ESC then
+  begin
+    AbortFlag.SetEvent();
+  end;
+end;
+
+procedure TMainForm.UpdateProgress(total: Integer; current: Integer; progress: Integer);
+begin
+  Edit_FileDigest.Text := 'Self-test is running (step ' + IntToStr(current) +' of ' + IntToStr(total) + '), please be patient...';
+  ProgressChanged(progress);
+  Application.ProcessMessages();
 end;
 
 procedure TMainForm.Button_BrowseClick(Sender: TObject);
@@ -145,9 +167,11 @@ begin
   ProgressBar.Position := 0;
   Edit_FileDigest.Text := 'Working, please wait...';
 
-  thread := TComputeThread.Create(Self.WindowHandle, Edit_InputFile.Text);
+  thread := TComputeThread.Create(Self.WindowHandle, Edit_InputFile.Text, AbortFlag);
   thread.OnProgress := ProgressChanged;
   thread.OnTerminate := ThreadTerminated;
+
+  AbortFlag.ResetEvent();
   thread.Resume;
 end;
 
@@ -175,11 +199,12 @@ end;
 { Compute Thread                               }
 {----------------------------------------------}
 
-constructor TComputeThread.Create(const hwnd: HWND; const inputFile: String);
+constructor TComputeThread.Create(const hwnd: HWND; const inputFile: String; const abortFlag: TSimpleEvent);
 begin
   inherited Create(True);
   Self.hwnd := hwnd;
   Self.inputFile := inputFile;
+  Self.abortFlag := abortFlag;
   ReturnValue := 0;
   progressEvent := nil;
 end;
@@ -227,6 +252,10 @@ begin
               spinner := 0;
             end;
           end;
+          if (abortFlag.WaitFor(0) = wrSignaled) then
+          begin
+            raise Exception.Create('Operation was aborted by the user!');
+          end;
         end;
         digest.Result(result);
         HashString := ByteToHex(result);
@@ -241,7 +270,7 @@ begin
   except
      on E: Exception do
      begin
-       MessageBox(self.hwnd, PAnsiChar('Failed to open input file!'#10#10'Details:'#10 + E.Message), PAnsiChar(String(E.ClassName)), MB_ICONERROR or MB_SYSTEMMODAL);
+       MessageBox(self.hwnd, PAnsiChar('Failed to compute hash, because an error occurred!'#10#10'Details:'#10 + E.Message), PAnsiChar(String(E.ClassName)), MB_ICONERROR or MB_SYSTEMMODAL);
        Exit;
      end;
   end;
@@ -270,7 +299,6 @@ begin
   end;
 end;
 
-
 procedure TComputeThread.SetProgress(const processed: UInt64; const totalSize: UInt64);
 var
   nextProgress: Integer;
index 3b6273e..d279137 100644 (file)
@@ -27,7 +27,7 @@ unit MHash384;
 interface
 
 uses
-  Classes;
+  Classes, SyncObjs;
 
 const
   MHASH384_LEN = 48;
@@ -35,6 +35,7 @@ const
 type
   TByteArray = array of byte;
   TDigestBuf = array[0..MHASH384_LEN-1] of Byte;
+  TProgress = procedure(total: Integer; current: Integer; progress: Integer) of object;
 
 type
   TMHash384 = Class
@@ -49,7 +50,7 @@ type
     procedure Result(var output: TByteArray);
     procedure Reset();
     class procedure GetVersion(var major: Word; var minor: Word; var patch: Word);
-    class procedure SelfTest();
+    class procedure SelfTest(const callback: TProgress; const abortFlag: TSimpleEvent);
   private
     m_digest: array[0..1] of TDigestBuf;
     m_rnd: Cardinal;
@@ -1265,7 +1266,15 @@ end;
 { Debugging Functions                            }
 { ---------------------------------------------- }
 
-class procedure TMHash384.SelfTest();
+function GetProgress(const total: Integer; const current: Integer): Integer;
+var
+  fTotal, fCurrent: Double;
+begin
+  fTotal := total; fCurrent := current;
+  Result := Round((fCurrent / fTotal) * 100.0);
+end;
+
+class procedure TMHash384.SelfTest(const callback: TProgress; const abortFlag: TSimpleEvent);
 type
   TTestVector = record
     iterations: Cardinal;
@@ -1329,53 +1338,79 @@ const
     (
       iterations: $0000001;
       input:
-            #$92#$AD#$AC#$49#$7F#$FA#$B3#$0B#$40#$AC#$67#$4F#$9D#$53#$A9#$A6#$24#$B2#$47#$FA#$23#$72#$94#$FA#$75#$88#$41#$A8#$5F#$4D#$DE#$FD#$DB#$FD#$23#$71#$C1#$E2#$CA#$F8#$5B#$0E#$06#$4B#$BC#$4F#$3A#$C0#$A9#$C6#$FD#$6C#$18#$5D#$C4#$B1#$2C#$8A#$AC#$C3#$E6#$25#$BD#$E8#$7A#$DF#$CB#$FF#$60#$1B#$F0#$66#$DF#$08#$7C#$0A#$63#$CE#$2C#$11#$D6#$64#$8D#$1E#$D0 +
-            #$57#$CE#$1B#$5D#$93#$C6#$CB#$6F#$33#$19#$81#$B9#$FC#$B5#$BC#$F4#$FB#$6F#$77#$50#$54#$06#$D7#$1A#$87#$EC#$7E#$C1#$99#$55#$97#$FB#$B7#$96#$9D#$EC#$0D#$AD#$01#$93#$9E#$88#$89#$F5#$30#$96#$3F#$E9#$2E#$23#$A8#$F5#$DA#$E5#$47#$3E#$2C#$1E#$22#$38#$2A#$D4#$F7#$0E#$A2#$E4#$5E#$BB#$CB#$AD#$11#$C8#$7A#$74#$8F#$78#$CB#$56#$77#$8E#$F4#$1C#$0A#$EC#$A5 +
-            #$63#$2E#$75#$E3#$52#$B2#$EA#$B5#$53#$3C#$06#$F7#$C6#$80#$8E#$77#$D0#$0B#$2D#$B5#$F9#$64#$F5#$9F#$89#$83#$D9#$25#$79#$22#$26#$E2#$F3#$E6#$D4#$B0#$FD#$E7#$BA#$74#$6C#$59#$BA#$9A#$20#$21#$2C#$25#$DA#$02#$D2#$3A#$EE#$5F#$88#$5A#$75#$F1#$1A#$C5#$BD#$D5#$CC#$6F#$9C#$4B#$72#$BC#$47#$D8#$40#$89#$72#$00#$F1#$B7#$EF#$97#$7F#$23#$52#$2C#$83#$38#$A3 +
-            #$FC#$FD#$D7#$72#$C6#$15#$D3#$4A#$93#$46#$BC#$B1#$CE#$37#$14#$FC#$0E#$2B#$CB#$99#$C7#$34#$4D#$AC#$D8#$48#$A1#$EE#$58#$43#$6D#$B4#$78#$D0#$30#$E4#$09#$F1#$7B#$3A#$E9#$60#$68#$D9#$06#$F8#$59#$22#$6A#$66#$47#$D6#$09#$8A#$95#$18#$3B#$01#$46#$0D#$29#$36#$7B#$A5#$22#$B4#$05#$7E#$30#$AC#$8B#$C2#$D5#$4C#$BB#$63#$50#$0B#$76#$A1#$36#$EB#$36#$A0#$77 +
-            #$D8#$F7#$98#$14#$57#$91#$0E#$8D#$9C#$42#$95#$E9#$39#$42#$01#$C9#$B8#$DF#$82#$87#$FF#$E5#$E6#$66#$80#$0B#$19#$B4#$13#$AC#$EC#$71#$2A#$5D#$35#$C5#$CA#$0F#$56#$E6#$A3#$51#$70#$58#$21#$B2#$20#$8D#$C9#$DE#$CC#$25#$19#$D5#$CF#$A1#$B9#$2B#$68#$BE#$D2#$64#$32#$94#$9B#$02#$7C#$F2#$00#$FE#$3D#$8B#$40#$A2#$19#$50#$0F#$EE#$41#$61#$23#$A8#$C5#$A3#$F5 +
-            #$FC#$37#$35#$1E#$6A#$51#$42#$AA#$33#$8D#$34#$11#$F8#$B3#$BD#$2B#$74#$99#$16#$FF#$AD#$26#$8F#$00#$C5#$F5#$1C#$59#$22#$02#$3E#$B1#$71#$08#$43#$BF#$A7#$6B#$CD#$03#$33#$0E#$53#$9D#$BA#$E5#$28#$CA#$09#$E6#$1B#$AE#$11#$76#$A9#$7A#$89#$DF#$48#$DC#$85#$F1#$9A#$ED#$9F#$E1#$9F#$2D#$B7#$DA#$21#$BA#$D1#$0C#$CA#$67#$05#$5B#$CC#$24#$5B#$EA#$F0#$B8#$6C +
-            #$C4#$B8;
+            #$92#$AD#$AC#$49#$7F#$FA#$B3#$0B#$40#$AC#$67#$4F#$9D#$53#$A9#$A6#$24#$B2#$47#$FA#$23#$72#$94#$FA#$75#$88#$41#$A8#$5F#$4D#$DE#$FD#$DB#$FD#$23#$71#$C1#$E2#$CA#$F8#$5B#$0E#$06#$4B#$BC#$4F#$3A#$C0 +
+            #$A9#$C6#$FD#$6C#$18#$5D#$C4#$B1#$2C#$8A#$AC#$C3#$E6#$25#$BD#$E8#$7A#$DF#$CB#$FF#$60#$1B#$F0#$66#$DF#$08#$7C#$0A#$63#$CE#$2C#$11#$D6#$64#$8D#$1E#$D0#$57#$CE#$1B#$5D#$93#$C6#$CB#$6F#$33#$19#$81 +
+            #$B9#$FC#$B5#$BC#$F4#$FB#$6F#$77#$50#$54#$06#$D7#$1A#$87#$EC#$7E#$C1#$99#$55#$97#$FB#$B7#$96#$9D#$EC#$0D#$AD#$01#$93#$9E#$88#$89#$F5#$30#$96#$3F#$E9#$2E#$23#$A8#$F5#$DA#$E5#$47#$3E#$2C#$1E#$22 +
+            #$38#$2A#$D4#$F7#$0E#$A2#$E4#$5E#$BB#$CB#$AD#$11#$C8#$7A#$74#$8F#$78#$CB#$56#$77#$8E#$F4#$1C#$0A#$EC#$A5#$63#$2E#$75#$E3#$52#$B2#$EA#$B5#$53#$3C#$06#$F7#$C6#$80#$8E#$77#$D0#$0B#$2D#$B5#$F9#$64 +
+            #$F5#$9F#$89#$83#$D9#$25#$79#$22#$26#$E2#$F3#$E6#$D4#$B0#$FD#$E7#$BA#$74#$6C#$59#$BA#$9A#$20#$21#$2C#$25#$DA#$02#$D2#$3A#$EE#$5F#$88#$5A#$75#$F1#$1A#$C5#$BD#$D5#$CC#$6F#$9C#$4B#$72#$BC#$47#$D8 +
+            #$40#$89#$72#$00#$F1#$B7#$EF#$97#$7F#$23#$52#$2C#$83#$38#$A3#$FC#$FD#$D7#$72#$C6#$15#$D3#$4A#$93#$46#$BC#$B1#$CE#$37#$14#$FC#$0E#$2B#$CB#$99#$C7#$34#$4D#$AC#$D8#$48#$A1#$EE#$58#$43#$6D#$B4#$78 +
+            #$D0#$30#$E4#$09#$F1#$7B#$3A#$E9#$60#$68#$D9#$06#$F8#$59#$22#$6A#$66#$47#$D6#$09#$8A#$95#$18#$3B#$01#$46#$0D#$29#$36#$7B#$A5#$22#$B4#$05#$7E#$30#$AC#$8B#$C2#$D5#$4C#$BB#$63#$50#$0B#$76#$A1#$36 +
+            #$EB#$36#$A0#$77#$D8#$F7#$98#$14#$57#$91#$0E#$8D#$9C#$42#$95#$E9#$39#$42#$01#$C9#$B8#$DF#$82#$87#$FF#$E5#$E6#$66#$80#$0B#$19#$B4#$13#$AC#$EC#$71#$2A#$5D#$35#$C5#$CA#$0F#$56#$E6#$A3#$51#$70#$58 +
+            #$21#$B2#$20#$8D#$C9#$DE#$CC#$25#$19#$D5#$CF#$A1#$B9#$2B#$68#$BE#$D2#$64#$32#$94#$9B#$02#$7C#$F2#$00#$FE#$3D#$8B#$40#$A2#$19#$50#$0F#$EE#$41#$61#$23#$A8#$C5#$A3#$F5#$FC#$37#$35#$1E#$6A#$51#$42 +
+            #$AA#$33#$8D#$34#$11#$F8#$B3#$BD#$2B#$74#$99#$16#$FF#$AD#$26#$8F#$00#$C5#$F5#$1C#$59#$22#$02#$3E#$B1#$71#$08#$43#$BF#$A7#$6B#$CD#$03#$33#$0E#$53#$9D#$BA#$E5#$28#$CA#$09#$E6#$1B#$AE#$11#$76#$A9 +
+            #$7A#$89#$DF#$48#$DC#$85#$F1#$9A#$ED#$9F#$E1#$9F#$2D#$B7#$DA#$21#$BA#$D1#$0C#$CA#$67#$05#$5B#$CC#$24#$5B#$EA#$F0#$B8#$6C#$C4#$B8;
     ),
     (
       iterations: $0000001;
       input:
-            #$05#$85#$7B#$AA#$C0#$C9#$E8#$62#$60#$62#$B0#$A0#$22#$03#$88#$A6#$84#$43#$AA#$8C#$77#$0C#$82#$94#$5D#$35#$82#$98#$04#$1C#$DD#$A8#$D4#$4E#$90#$6F#$6D#$B9#$81#$E2#$7B#$3F#$95#$74#$24#$3E#$9F#$53#$7B#$EF#$0A#$25#$47#$79#$89#$5C#$B6#$B2#$37#$FC#$4F#$74#$6F#$7F#$CD#$E3#$73#$8B#$F5#$D1#$A2#$3C#$BC#$70#$F1#$41#$84#$F2#$EB#$37#$9B#$CB#$C3#$D7#$46 +
-            #$2E#$52#$C3#$97#$3A#$B6#$74#$F3#$D5#$BB#$5A#$89#$36#$F3#$1D#$D5#$A1#$0E#$F1#$8E#$F4#$17#$26#$CE#$66#$00#$28#$DE#$17#$3D#$5B#$3B#$83#$7B#$D3#$AB#$C4#$A1#$EF#$8A#$59#$A2#$E2#$BA#$6E#$13#$EE#$EA#$83#$6B#$C1#$B1#$17#$9C#$65#$1A#$BE#$45#$A7#$B2#$40#$91#$99#$07#$9F#$4B#$5F#$BE#$F8#$C6#$7E#$4E#$0A#$FF#$5B#$B5#$5A#$7C#$2F#$9E#$77#$EE#$3B#$E0#$B5 +
-            #$62#$80#$22#$9D#$2D#$13#$CB#$BC#$33#$80#$DD#$AB#$15#$AA#$AD#$04#$3A#$AD#$8C#$D5#$32#$4D#$30#$32#$F0#$71#$47#$27#$5E#$4B#$12#$FB#$EF#$7B#$AB#$83#$AC#$9D#$CD#$ED#$EE#$2C#$25#$69#$19#$6D#$60#$EF#$18#$B5#$A0#$80#$9D#$A2#$83#$31#$87#$07#$53#$52#$E1#$5B#$4C#$1E#$FF#$41#$61#$34#$1C#$3E#$1F#$5F#$A2#$58#$D7#$67#$56#$23#$B6#$EC#$F5#$BC#$27#$CE#$CD +
-            #$B4#$B2#$57#$B1#$3B#$EB#$A6#$58#$95#$E0#$B5#$E8#$B1#$9E#$18#$3F#$4B#$60#$96#$4E#$FB#$59#$25#$06#$F4#$95#$83#$80#$98#$5D#$9F#$59#$9B#$83#$26#$97#$89#$CE#$AC#$BB#$D0#$5C#$95#$37#$DC#$E4#$DD#$2F#$5C#$22#$9C#$65#$10#$FB#$61#$A1#$73#$A1#$6A#$89#$61#$93#$7C#$C8#$6E#$80#$B8#$48#$57#$48#$4F#$88#$7E#$6A#$CE#$90#$F3#$EB#$B3#$9F#$50#$F0#$0F#$B6#$29 +
-            #$60#$28#$E5#$8B#$DF#$EA#$CA#$FB#$3C#$DD#$AA#$60#$60#$73#$B3#$AE#$45#$4F#$C9#$1D#$B2#$63#$31#$30#$3B#$85#$BA#$8A#$37#$41#$D6#$5A#$52#$11#$A2#$2A#$11#$39#$D2#$1E#$2D#$BF#$1A#$53#$8A#$13#$24#$C7#$A3#$DE#$BE#$0B#$23#$72#$CC#$92#$29#$B8#$2B#$92#$8F#$08#$0A#$B4#$A6#$47#$76#$29#$39#$BF#$40#$BC#$59#$9F#$CD#$9D#$CF#$35#$51#$16#$F5#$44#$40#$A4#$C3 +
-            #$1D#$A8#$8C#$73#$C0#$A1#$12#$84#$15#$4D#$B1#$7B#$4A#$44#$F4#$12#$8E#$0F#$E4#$4C#$7E#$5C#$B2#$92#$5F#$A9#$B3#$71#$DA#$40#$50#$78#$C7#$02#$1F#$20#$79#$84#$F3#$91#$1F#$47#$47#$40#$67#$2B#$52#$A1#$67#$91#$05#$CA#$B4#$AB#$A8#$69#$40#$FD#$7F#$28#$F6#$17#$B0#$DD#$1A#$82#$0F#$20#$5D#$D2#$39#$A8#$9A#$73#$F1#$AC#$10#$18#$3C#$69#$99#$49#$B8#$B2#$90 +
-            #$24#$B5#$2E#$0C#$57#$93#$6A#$1B#$0B#$9C#$B9#$F5#$45#$71#$DD#$AF#$94#$6F#$A5#$F5#$CF#$B1#$BC#$1C#$0E#$5E#$5A#$0E#$F6#$9D#$9E#$71#$11#$99#$9F#$A4#$57#$E6#$6D#$D5#$83#$00#$D7#$85#$0C#$54#$01#$D4#$49#$1C#$F6#$8C#$8E#$00#$8B#$F8#$48#$50#$4D#$6F#$F1#$EA#$EF#$2D#$64#$D4#$F5#$00#$A9#$03#$E6#$CB#$5F#$CF#$6C#$D6#$26#$C1#$F4#$97#$CF#$B5#$16#$A1#$62 +
-            #$DE#$FF#$C2#$00#$D0#$9A#$5E#$BB#$B4#$76#$86#$FD#$4B#$F2#$29#$4F#$0F#$69#$15#$7D#$AC#$AA#$2B#$D1#$BA#$6E#$A2#$1A#$C1#$6B#$9A#$14#$90#$63#$BD#$C4#$31#$36#$BB#$26#$A7#$69#$7D#$11#$76#$E5#$3F#$05#$C5#$4F#$6D#$B0#$12#$2E#$BC#$72#$18#$8A#$0F#$07#$A1#$2A#$D0#$C0#$DE#$2B#$63#$19#$6E#$A8#$7F#$C7#$9D#$47#$2F#$A6#$62#$A3#$57#$F0#$37#$58#$9F#$80#$4D +
-            #$9D#$A9#$2F#$2A#$39#$79#$16#$6A#$CA#$DF#$22#$8F#$2F#$AA#$A2#$72#$75#$96#$63#$19#$E2#$DF#$7E#$37#$1D#$68#$F8#$D9#$5D#$8D#$40#$23#$7F#$F5#$1B#$40#$33#$CB#$38#$81#$4F#$4A#$5E#$25#$3C#$F0#$19#$D7#$01#$D1#$21#$F6#$C5#$6F#$DA#$17#$83#$60#$39#$25#$66#$F2#$25#$31#$58#$A6#$A4#$AD#$46#$78#$E7#$76#$57#$19#$CB#$7C#$9C#$6D#$E0#$6D#$F8#$FD#$28#$14#$14 +
-            #$0D#$F0#$0C#$8F#$D4#$68#$59#$D2#$96#$15#$BF#$EC#$8A#$34#$F7#$1A#$3B#$2C#$8C#$4A#$98#$16#$37#$7D#$95#$15#$BD#$45#$CB#$F8#$C1#$A1#$9E#$64#$3A#$17#$4C#$C4#$D2#$D1#$A0#$A4#$BD#$5A#$79#$CB#$53#$BC#$37#$84#$C8#$4F#$9B#$D7#$10#$42#$3D#$26#$40#$D6#$F2#$50#$20#$17#$8C#$2A#$81#$3A#$B5#$D2#$8B#$66#$E5#$9F#$CB#$EB#$29#$C8#$41#$D1#$B1#$9F#$BA#$77#$2A +
-            #$18#$D7#$7F#$8D#$46#$60#$FE#$DB#$E4#$C1#$A5#$73#$DD#$88#$7B#$17#$AA#$3D#$58#$30#$9B#$F6#$B2#$66#$4E#$AC#$C3#$E3#$A4#$7A#$AE#$DF#$33#$BE#$52#$89#$B7#$F9#$B0#$18#$FB#$70#$63#$9A#$C2#$B5#$FD#$EF#$3C#$8E#$91#$69#$5F#$A8#$E0#$F6#$83#$25#$EF#$16#$AA#$AF#$27#$B5#$D5#$2C#$58#$57#$35#$67#$5D#$11#$31#$A3#$25#$39#$0D#$5C#$F1#$AC#$D4#$FB#$03#$4C#$8A +
-            #$C0#$FB#$B2#$E5#$0E#$AD#$7F#$C9#$B1#$33#$AE#$D9#$EE#$3D#$71#$CB#$23#$54#$F9#$7F#$BF#$02#$4D#$E1#$D2#$BC#$66#$A9#$5C#$9D#$36#$47#$5A#$62#$76#$EF#$C5#$C8#$30#$BC#$78#$79#$92#$62#$A8#$E9#$0B#$83#$E5#$91#$42#$8F#$FC#$E9#$A8#$6C#$AB#$A9#$75#$A1#$9B#$6B#$A2#$E5#$87#$96#$BE#$16#$84#$0A#$04#$29#$9F#$2E#$2D#$C9#$C8#$DA#$EA#$F6#$9A#$25#$0F#$F8#$C0 +
-            #$FD#$B5#$D7#$82;
+            #$05#$85#$7B#$AA#$C0#$C9#$E8#$62#$60#$62#$B0#$A0#$22#$03#$88#$A6#$84#$43#$AA#$8C#$77#$0C#$82#$94#$5D#$35#$82#$98#$04#$1C#$DD#$A8#$D4#$4E#$90#$6F#$6D#$B9#$81#$E2#$7B#$3F#$95#$74#$24#$3E#$9F#$53 +
+            #$7B#$EF#$0A#$25#$47#$79#$89#$5C#$B6#$B2#$37#$FC#$4F#$74#$6F#$7F#$CD#$E3#$73#$8B#$F5#$D1#$A2#$3C#$BC#$70#$F1#$41#$84#$F2#$EB#$37#$9B#$CB#$C3#$D7#$46#$2E#$52#$C3#$97#$3A#$B6#$74#$F3#$D5#$BB#$5A +
+            #$89#$36#$F3#$1D#$D5#$A1#$0E#$F1#$8E#$F4#$17#$26#$CE#$66#$00#$28#$DE#$17#$3D#$5B#$3B#$83#$7B#$D3#$AB#$C4#$A1#$EF#$8A#$59#$A2#$E2#$BA#$6E#$13#$EE#$EA#$83#$6B#$C1#$B1#$17#$9C#$65#$1A#$BE#$45#$A7 +
+            #$B2#$40#$91#$99#$07#$9F#$4B#$5F#$BE#$F8#$C6#$7E#$4E#$0A#$FF#$5B#$B5#$5A#$7C#$2F#$9E#$77#$EE#$3B#$E0#$B5#$62#$80#$22#$9D#$2D#$13#$CB#$BC#$33#$80#$DD#$AB#$15#$AA#$AD#$04#$3A#$AD#$8C#$D5#$32#$4D +
+            #$30#$32#$F0#$71#$47#$27#$5E#$4B#$12#$FB#$EF#$7B#$AB#$83#$AC#$9D#$CD#$ED#$EE#$2C#$25#$69#$19#$6D#$60#$EF#$18#$B5#$A0#$80#$9D#$A2#$83#$31#$87#$07#$53#$52#$E1#$5B#$4C#$1E#$FF#$41#$61#$34#$1C#$3E +
+            #$1F#$5F#$A2#$58#$D7#$67#$56#$23#$B6#$EC#$F5#$BC#$27#$CE#$CD#$B4#$B2#$57#$B1#$3B#$EB#$A6#$58#$95#$E0#$B5#$E8#$B1#$9E#$18#$3F#$4B#$60#$96#$4E#$FB#$59#$25#$06#$F4#$95#$83#$80#$98#$5D#$9F#$59#$9B +
+            #$83#$26#$97#$89#$CE#$AC#$BB#$D0#$5C#$95#$37#$DC#$E4#$DD#$2F#$5C#$22#$9C#$65#$10#$FB#$61#$A1#$73#$A1#$6A#$89#$61#$93#$7C#$C8#$6E#$80#$B8#$48#$57#$48#$4F#$88#$7E#$6A#$CE#$90#$F3#$EB#$B3#$9F#$50 +
+            #$F0#$0F#$B6#$29#$60#$28#$E5#$8B#$DF#$EA#$CA#$FB#$3C#$DD#$AA#$60#$60#$73#$B3#$AE#$45#$4F#$C9#$1D#$B2#$63#$31#$30#$3B#$85#$BA#$8A#$37#$41#$D6#$5A#$52#$11#$A2#$2A#$11#$39#$D2#$1E#$2D#$BF#$1A#$53 +
+            #$8A#$13#$24#$C7#$A3#$DE#$BE#$0B#$23#$72#$CC#$92#$29#$B8#$2B#$92#$8F#$08#$0A#$B4#$A6#$47#$76#$29#$39#$BF#$40#$BC#$59#$9F#$CD#$9D#$CF#$35#$51#$16#$F5#$44#$40#$A4#$C3#$1D#$A8#$8C#$73#$C0#$A1#$12 +
+            #$84#$15#$4D#$B1#$7B#$4A#$44#$F4#$12#$8E#$0F#$E4#$4C#$7E#$5C#$B2#$92#$5F#$A9#$B3#$71#$DA#$40#$50#$78#$C7#$02#$1F#$20#$79#$84#$F3#$91#$1F#$47#$47#$40#$67#$2B#$52#$A1#$67#$91#$05#$CA#$B4#$AB#$A8 +
+            #$69#$40#$FD#$7F#$28#$F6#$17#$B0#$DD#$1A#$82#$0F#$20#$5D#$D2#$39#$A8#$9A#$73#$F1#$AC#$10#$18#$3C#$69#$99#$49#$B8#$B2#$90#$24#$B5#$2E#$0C#$57#$93#$6A#$1B#$0B#$9C#$B9#$F5#$45#$71#$DD#$AF#$94#$6F +
+            #$A5#$F5#$CF#$B1#$BC#$1C#$0E#$5E#$5A#$0E#$F6#$9D#$9E#$71#$11#$99#$9F#$A4#$57#$E6#$6D#$D5#$83#$00#$D7#$85#$0C#$54#$01#$D4#$49#$1C#$F6#$8C#$8E#$00#$8B#$F8#$48#$50#$4D#$6F#$F1#$EA#$EF#$2D#$64#$D4 +
+            #$F5#$00#$A9#$03#$E6#$CB#$5F#$CF#$6C#$D6#$26#$C1#$F4#$97#$CF#$B5#$16#$A1#$62#$DE#$FF#$C2#$00#$D0#$9A#$5E#$BB#$B4#$76#$86#$FD#$4B#$F2#$29#$4F#$0F#$69#$15#$7D#$AC#$AA#$2B#$D1#$BA#$6E#$A2#$1A#$C1 +
+            #$6B#$9A#$14#$90#$63#$BD#$C4#$31#$36#$BB#$26#$A7#$69#$7D#$11#$76#$E5#$3F#$05#$C5#$4F#$6D#$B0#$12#$2E#$BC#$72#$18#$8A#$0F#$07#$A1#$2A#$D0#$C0#$DE#$2B#$63#$19#$6E#$A8#$7F#$C7#$9D#$47#$2F#$A6#$62 +
+            #$A3#$57#$F0#$37#$58#$9F#$80#$4D#$9D#$A9#$2F#$2A#$39#$79#$16#$6A#$CA#$DF#$22#$8F#$2F#$AA#$A2#$72#$75#$96#$63#$19#$E2#$DF#$7E#$37#$1D#$68#$F8#$D9#$5D#$8D#$40#$23#$7F#$F5#$1B#$40#$33#$CB#$38#$81 +
+            #$4F#$4A#$5E#$25#$3C#$F0#$19#$D7#$01#$D1#$21#$F6#$C5#$6F#$DA#$17#$83#$60#$39#$25#$66#$F2#$25#$31#$58#$A6#$A4#$AD#$46#$78#$E7#$76#$57#$19#$CB#$7C#$9C#$6D#$E0#$6D#$F8#$FD#$28#$14#$14#$0D#$F0#$0C +
+            #$8F#$D4#$68#$59#$D2#$96#$15#$BF#$EC#$8A#$34#$F7#$1A#$3B#$2C#$8C#$4A#$98#$16#$37#$7D#$95#$15#$BD#$45#$CB#$F8#$C1#$A1#$9E#$64#$3A#$17#$4C#$C4#$D2#$D1#$A0#$A4#$BD#$5A#$79#$CB#$53#$BC#$37#$84#$C8 +
+            #$4F#$9B#$D7#$10#$42#$3D#$26#$40#$D6#$F2#$50#$20#$17#$8C#$2A#$81#$3A#$B5#$D2#$8B#$66#$E5#$9F#$CB#$EB#$29#$C8#$41#$D1#$B1#$9F#$BA#$77#$2A#$18#$D7#$7F#$8D#$46#$60#$FE#$DB#$E4#$C1#$A5#$73#$DD#$88 +
+            #$7B#$17#$AA#$3D#$58#$30#$9B#$F6#$B2#$66#$4E#$AC#$C3#$E3#$A4#$7A#$AE#$DF#$33#$BE#$52#$89#$B7#$F9#$B0#$18#$FB#$70#$63#$9A#$C2#$B5#$FD#$EF#$3C#$8E#$91#$69#$5F#$A8#$E0#$F6#$83#$25#$EF#$16#$AA#$AF +
+            #$27#$B5#$D5#$2C#$58#$57#$35#$67#$5D#$11#$31#$A3#$25#$39#$0D#$5C#$F1#$AC#$D4#$FB#$03#$4C#$8A#$C0#$FB#$B2#$E5#$0E#$AD#$7F#$C9#$B1#$33#$AE#$D9#$EE#$3D#$71#$CB#$23#$54#$F9#$7F#$BF#$02#$4D#$E1#$D2 +
+            #$BC#$66#$A9#$5C#$9D#$36#$47#$5A#$62#$76#$EF#$C5#$C8#$30#$BC#$78#$79#$92#$62#$A8#$E9#$0B#$83#$E5#$91#$42#$8F#$FC#$E9#$A8#$6C#$AB#$A9#$75#$A1#$9B#$6B#$A2#$E5#$87#$96#$BE#$16#$84#$0A#$04#$29#$9F +
+            #$2E#$2D#$C9#$C8#$DA#$EA#$F6#$9A#$25#$0F#$F8#$C0#$FD#$B5#$D7#$82;
     ),
     (
       iterations: $0000001;
       input:
-            #$FF#$D3#$B0#$A7#$2D#$6F#$68#$3A#$0B#$80#$75#$AA#$E0#$E7#$1E#$77#$32#$81#$7D#$74#$65#$EE#$85#$B5#$7A#$D8#$D6#$53#$CE#$9F#$4F#$B7#$BD#$D4#$B0#$B6#$7B#$44#$A5#$2C#$2E#$69#$C9#$60#$E3#$AE#$C7#$AD#$66#$04#$DC#$1D#$B1#$AE#$B2#$AE#$5E#$F0#$78#$CB#$08#$FF#$40#$1C#$36#$34#$0C#$10#$E3#$41#$9B#$80#$8F#$62#$BF#$D6#$25#$B7#$2D#$74#$83#$4F#$24#$7E#$BA +
-            #$B7#$0D#$87#$9A#$5C#$72#$E6#$F0#$09#$79#$51#$2B#$1F#$E6#$4A#$C0#$22#$17#$58#$66#$E9#$8B#$B2#$92#$E3#$62#$FC#$73#$6E#$BC#$72#$D5#$CF#$08#$05#$4B#$B6#$14#$3C#$91#$33#$3E#$60#$BA#$81#$C3#$FD#$32#$A9#$B7#$64#$D8#$1F#$9B#$44#$63#$2D#$1A#$70#$E1#$F5#$4E#$A0#$8D#$3C#$20#$8C#$46#$59#$F5#$F4#$E2#$E6#$A2#$A7#$E8#$18#$CB#$4D#$DB#$5A#$C6#$90#$93#$AC +
-            #$DF#$6A#$FF#$D1#$00#$96#$4F#$FC#$EF#$B7#$6A#$EB#$BB#$87#$30#$4F#$FC#$19#$CE#$12#$33#$C1#$13#$DE#$DF#$A3#$7B#$89#$C2#$A3#$DC#$A4#$A9#$BD#$04#$10#$96#$EE#$B8#$77#$FA#$98#$5C#$42#$01#$F3#$F5#$D4#$EF#$18#$0E#$B4#$0F#$2E#$2C#$FC#$9A#$D0#$CF#$4C#$99#$E1#$20#$F0#$65#$5B#$FE#$AF#$F0#$9B#$B5#$DF#$D5#$2B#$C2#$3D#$B0#$FD#$E8#$31#$3C#$7F#$A6#$65#$6F +
-            #$BA#$0E#$D9#$C9#$8D#$5B#$D1#$EA#$7C#$7F#$4B#$52#$ED#$80#$4F#$26#$17#$95#$91#$6B#$B8#$08#$2C#$1E#$62#$4F#$D2#$D0#$7A#$00#$75#$A6#$13#$29#$93#$CB#$C4#$C5#$A7#$9E#$90#$B1#$7C#$8C#$1C#$7A#$59#$6C#$1D#$5D#$FC#$46#$AF#$0C#$96#$BA#$31#$95#$44#$7B#$CB#$5E#$AB#$64#$42#$F7#$35#$7A#$1F#$87#$F2#$B3#$3E#$42#$33#$28#$CF#$52#$47#$47#$13#$9A#$A3#$63#$D1 +
-            #$BD#$7A#$F0#$0C#$90#$68#$1D#$0C#$03#$83#$A9#$8E#$9D#$7A#$5C#$6A#$1E#$66#$A9#$F1#$2B#$B8#$CE#$A2#$D2#$2B#$17#$21#$B1#$83#$87#$FC#$F1#$F3#$46#$78#$DC#$D3#$96#$66#$C2#$B4#$D3#$83#$02#$A8#$D7#$A5#$95#$DF#$30#$04#$F2#$D1#$52#$8C#$5A#$44#$62#$68#$BC#$CD#$A7#$69#$CB#$4E#$B4#$5B#$10#$83#$59#$AC#$28#$29#$13#$04#$C3#$B2#$7A#$C5#$35#$A7#$B0#$0A#$D4 +
-            #$F0#$F0#$EC#$B4#$C0#$F2#$D2#$C2#$2B#$88#$03#$D5#$E6#$4E#$6F#$EF#$AD#$7D#$D8#$0F#$F0#$6C#$B0#$B1#$09#$D8#$9D#$99#$14#$E3#$00#$05#$23#$C7#$15#$B9#$B1#$B7#$F1#$EE#$9F#$CE#$04#$39#$B7#$E2#$4D#$0C#$5A#$13#$7A#$72#$08#$21#$11#$28#$B2#$35#$EC#$7A#$E5#$23#$D5#$66#$D6#$4C#$7A#$82#$FD#$6E#$1F#$3A#$01#$DC#$38#$3A#$21#$7B#$23#$B5#$FA#$CC#$05#$65#$8D +
-            #$DC#$DA#$5C#$A7#$0A#$1A#$A0#$02#$F4#$B6#$A0#$32#$34#$77#$C5#$E2#$BB#$10#$46#$CE#$57#$E3#$A9#$0B#$65#$73#$8F#$D5#$A5#$17#$83#$00#$BD#$40#$B1#$EE#$44#$F4#$EB#$28#$5B#$96#$A6#$C1#$94#$D3#$B6#$4B#$AE#$F4#$72#$F6#$EC#$AC#$D4#$52#$9E#$C7#$7A#$A8#$4B#$3D#$1D#$BC#$C0#$57#$7B#$91#$62#$EE#$4D#$67#$F3#$BA#$8D#$BB#$6D#$E7#$48#$5E#$BE#$16#$48#$85#$6C +
-            #$52#$48#$00#$FF#$06#$95#$E1#$7E#$D9#$13#$98#$E0#$6D#$96#$13#$B7#$4B#$28#$3B#$AC#$C5#$0A#$37#$85#$BB#$6E#$E5#$E9#$2F#$2C#$0E#$9E#$B7#$44#$E7#$85#$F2#$5B#$FD#$EE#$8B#$C2#$B8#$30#$E0#$81#$29#$94#$DB#$33#$FF#$88#$32#$91#$F9#$CB#$14#$BC#$2D#$91#$26#$13#$4A#$A2#$E2#$D7#$D0#$CA#$9F#$1F#$36#$7A#$12#$7D#$0C#$9A#$0B#$E6#$5C#$E2#$B7#$4D#$E5#$0B#$A4 +
-            #$3E#$25#$F8#$D9#$8D#$9D#$F4#$E3#$2C#$8A#$9B#$98#$AD#$6B#$F5#$0F#$FB#$7D#$DA#$2A#$FE#$21#$18#$76#$9A#$1A#$55#$FC#$25#$CA#$3E#$F9#$FD#$E4#$B6#$2D#$10#$3E#$58#$79#$D8#$30#$ED#$DD#$4B#$B6#$0F#$D5#$D6#$F6#$B4#$B1#$37#$7C#$4E#$29#$E6#$F7#$79#$23#$74#$01#$66#$5F#$02#$EB#$F2#$9F#$51#$02#$39#$31#$AA#$8B#$BC#$DE#$6E#$5A#$6D#$AF#$3A#$84#$23#$34#$F4 +
-            #$13#$9C#$04#$FD#$7E#$6C#$E7#$22#$CC#$B9#$32#$6B#$D9#$C2#$77#$C2#$7B#$DF#$E9#$B6#$17#$53#$AF#$7B#$A6#$94#$AE#$39#$39#$00#$EF#$75#$E2#$4D#$15#$F6#$45#$1A#$B2#$9F#$D6#$82#$24#$45#$B2#$07#$A7#$00#$3D#$14#$01#$62#$40#$DD#$D2#$B8#$F0#$96#$9B#$07#$0C#$49#$F8#$74#$B2#$BF#$E9#$31#$B3#$2E#$9D#$2F#$30#$C2#$F6#$ED#$4C#$56#$42#$D4#$47#$55#$6A#$F4#$39 +
-            #$C2#$23#$5F#$58#$BD#$2C#$7B#$C5#$4A#$DC#$8A#$AD#$40#$E5#$84#$A0#$65#$B3#$65#$73#$74#$9F#$AB#$BD#$E6#$09#$A2#$24#$65#$8D#$F6#$5B#$5B#$14#$4B#$C0#$6A#$78#$F2#$D6#$F3#$76#$45#$A0#$77#$DD#$AA#$DB#$13#$F9#$9F#$0F#$5A#$A5#$A0#$B9#$28#$48#$95#$24#$03#$2D#$94#$6E#$E1#$05#$F7#$5C#$23#$82#$29#$95#$A1#$7C#$F2#$E3#$B9#$2F#$AC#$29#$11#$EC#$60#$D1#$4C +
-            #$5F#$B8#$D2#$1E#$9D#$EC#$76#$1D#$FC#$5F#$C0#$FE#$D1#$50#$33#$0A#$42#$D7#$83#$C9#$F9#$49#$54#$BB#$50#$17#$6C#$6B#$38#$C1#$31#$19#$DB#$FC#$DE#$CE#$17#$AD#$B2#$D1#$DA#$0A#$13#$EE#$2B#$ED#$3A#$EA#$EA#$20#$8E#$17#$14#$0B#$88#$EE#$B9#$A5#$02#$1B#$E8#$6C#$F7#$FB#$E4#$18#$72#$E7#$35#$88#$DE#$8E#$B8#$56#$FB#$D9#$8C#$B8#$81#$A7#$39#$AC#$F2#$D2#$39 +
-            #$0B#$AF#$7F#$B6#$D2#$0E#$A5#$C7#$A0#$B3#$EF#$6F#$4B#$F4#$08#$78#$B2#$A8#$89#$CD#$0E#$0E#$8A#$B1#$8F#$8C#$AC#$E3#$23#$23#$B6#$D1#$6C#$80#$FD#$F5#$4D#$65#$3B#$75#$17#$FC#$81#$A3#$88#$15#$2A#$EE#$19#$E0#$FD#$F5#$F1#$C2#$C3#$DD#$EE#$7A#$08#$12#$25#$72#$75#$42#$77#$8D#$51#$5B#$D6#$31#$61#$88#$21#$73#$86#$2E#$E5#$8E#$0B#$3E#$BE#$61#$B8#$E4#$FD +
-            #$FA#$67#$C6#$44#$78#$B2#$31#$D9#$8B#$BF#$A8#$07#$8F#$7E#$BE#$46#$54#$53#$24#$9A#$25#$E5#$D3#$5F#$C0#$22#$20#$EA#$C0#$86#$CD#$6C#$F8#$7A#$4A#$6C#$18#$BD#$0F#$CC#$F3#$5F#$7F#$E0#$BE#$B0#$53#$94#$5F#$E0#$89#$11#$86#$92#$F2#$3F#$1A#$BD#$E8#$68#$B8#$35#$3B#$91#$8F#$85#$73#$98#$B9#$7E#$D1#$C0#$AD#$F8#$4D#$72#$04#$4F#$1D#$AD#$82#$5F#$86#$DD#$89 +
-            #$17#$73#$38#$F8#$25#$34#$BA#$57#$24#$F8#$F3#$E3#$50#$AE#$41#$D9#$91#$F8#$AC#$8E#$C4#$87#$F6#$58#$D2#$1C#$31#$9B#$C9#$0E#$28#$56#$C9#$5F#$09#$43#$73#$A0#$79#$13#$58#$F2#$5E#$25#$89#$8F#$17#$58#$9E#$B3#$5E#$30#$6C#$8A#$AB#$81#$43#$27#$6C#$53#$82#$08#$19#$B9#$C0#$FB#$DA#$F4#$DD#$BD#$55#$66#$8D#$71#$FF#$67#$40#$4E#$53#$B3#$70#$22#$7B#$80#$20 +
-            #$8C#$92#$3F#$0F#$73#$AB#$F1#$E4#$5A#$A2#$57#$3D#$DF#$DE#$39#$D0#$E5#$47#$1C#$41#$DA#$7A#$95#$0C#$5E#$E4#$A3#$84#$34#$6E#$3E#$A4#$9A#$FD#$22#$46#$A9#$79#$65#$69#$19#$6A#$CE#$8A#$E9#$58#$94#$4A#$E1#$D9#$71#$02#$D9#$8F#$46#$A6#$5C#$59#$48#$1F#$63#$97#$1F#$AF#$FC#$11#$F0#$08#$02#$11#$02#$FF#$70#$A4#$E7#$3A#$B9#$5C#$F1#$70#$CA#$58#$F3#$1A#$00 +
-            #$14#$FA#$7C#$BF#$7E#$1B#$DE#$7E#$D6#$4F#$58#$40#$FB#$8F#$EA#$DC#$8B#$EC#$E2#$2A#$DD#$39#$97#$04#$BE#$3D#$8E#$0C#$AD#$9B#$48#$EF#$92#$5F#$76#$E3#$0C#$0D#$40#$20#$08#$4A#$46#$E7#$65#$38#$F1#$B4#$43#$E6#$99#$06#$5D#$D5#$4D#$7B#$DF#$D6#$46#$7A#$92#$55#$56#$08#$E4#$5F#$08#$D8#$C5#$94#$A6#$5E#$FE#$3B#$EC#$A3#$E8#$54#$90#$2B#$F7#$F3#$37#$25#$90 +
-            #$26#$0A#$1C#$78#$E6#$E5#$8D#$FF#$53#$96#$4B#$BB#$E4#$DE#$46#$05#$68#$7C#$BF#$05#$19#$D4#$D2#$C6#$8E#$AE#$E9#$45#$31#$60#$F8#$4C#$D1#$9A#$F1#$CA#$6E#$6E#$61#$33#$D0#$57#$15#$0E#$15#$6A#$14#$06#$1D#$CE#$65#$CA#$45#$71#$A7#$BB#$7A#$DE#$CE#$F6#$EA#$62#$A6#$FA#$54#$C1#$AE#$B4#$77#$26#$07#$C0#$10#$30#$B1#$CC#$24#$BF#$E8#$45#$C2#$A9#$D3#$4B#$66 +
-            #$A1#$E3#$F0#$57#$B0#$FE;
+            #$FF#$D3#$B0#$A7#$2D#$6F#$68#$3A#$0B#$80#$75#$AA#$E0#$E7#$1E#$77#$32#$81#$7D#$74#$65#$EE#$85#$B5#$7A#$D8#$D6#$53#$CE#$9F#$4F#$B7#$BD#$D4#$B0#$B6#$7B#$44#$A5#$2C#$2E#$69#$C9#$60#$E3#$AE#$C7#$AD +
+            #$66#$04#$DC#$1D#$B1#$AE#$B2#$AE#$5E#$F0#$78#$CB#$08#$FF#$40#$1C#$36#$34#$0C#$10#$E3#$41#$9B#$80#$8F#$62#$BF#$D6#$25#$B7#$2D#$74#$83#$4F#$24#$7E#$BA#$B7#$0D#$87#$9A#$5C#$72#$E6#$F0#$09#$79#$51 +
+            #$2B#$1F#$E6#$4A#$C0#$22#$17#$58#$66#$E9#$8B#$B2#$92#$E3#$62#$FC#$73#$6E#$BC#$72#$D5#$CF#$08#$05#$4B#$B6#$14#$3C#$91#$33#$3E#$60#$BA#$81#$C3#$FD#$32#$A9#$B7#$64#$D8#$1F#$9B#$44#$63#$2D#$1A#$70 +
+            #$E1#$F5#$4E#$A0#$8D#$3C#$20#$8C#$46#$59#$F5#$F4#$E2#$E6#$A2#$A7#$E8#$18#$CB#$4D#$DB#$5A#$C6#$90#$93#$AC#$DF#$6A#$FF#$D1#$00#$96#$4F#$FC#$EF#$B7#$6A#$EB#$BB#$87#$30#$4F#$FC#$19#$CE#$12#$33#$C1 +
+            #$13#$DE#$DF#$A3#$7B#$89#$C2#$A3#$DC#$A4#$A9#$BD#$04#$10#$96#$EE#$B8#$77#$FA#$98#$5C#$42#$01#$F3#$F5#$D4#$EF#$18#$0E#$B4#$0F#$2E#$2C#$FC#$9A#$D0#$CF#$4C#$99#$E1#$20#$F0#$65#$5B#$FE#$AF#$F0#$9B +
+            #$B5#$DF#$D5#$2B#$C2#$3D#$B0#$FD#$E8#$31#$3C#$7F#$A6#$65#$6F#$BA#$0E#$D9#$C9#$8D#$5B#$D1#$EA#$7C#$7F#$4B#$52#$ED#$80#$4F#$26#$17#$95#$91#$6B#$B8#$08#$2C#$1E#$62#$4F#$D2#$D0#$7A#$00#$75#$A6#$13 +
+            #$29#$93#$CB#$C4#$C5#$A7#$9E#$90#$B1#$7C#$8C#$1C#$7A#$59#$6C#$1D#$5D#$FC#$46#$AF#$0C#$96#$BA#$31#$95#$44#$7B#$CB#$5E#$AB#$64#$42#$F7#$35#$7A#$1F#$87#$F2#$B3#$3E#$42#$33#$28#$CF#$52#$47#$47#$13 +
+            #$9A#$A3#$63#$D1#$BD#$7A#$F0#$0C#$90#$68#$1D#$0C#$03#$83#$A9#$8E#$9D#$7A#$5C#$6A#$1E#$66#$A9#$F1#$2B#$B8#$CE#$A2#$D2#$2B#$17#$21#$B1#$83#$87#$FC#$F1#$F3#$46#$78#$DC#$D3#$96#$66#$C2#$B4#$D3#$83 +
+            #$02#$A8#$D7#$A5#$95#$DF#$30#$04#$F2#$D1#$52#$8C#$5A#$44#$62#$68#$BC#$CD#$A7#$69#$CB#$4E#$B4#$5B#$10#$83#$59#$AC#$28#$29#$13#$04#$C3#$B2#$7A#$C5#$35#$A7#$B0#$0A#$D4#$F0#$F0#$EC#$B4#$C0#$F2#$D2 +
+            #$C2#$2B#$88#$03#$D5#$E6#$4E#$6F#$EF#$AD#$7D#$D8#$0F#$F0#$6C#$B0#$B1#$09#$D8#$9D#$99#$14#$E3#$00#$05#$23#$C7#$15#$B9#$B1#$B7#$F1#$EE#$9F#$CE#$04#$39#$B7#$E2#$4D#$0C#$5A#$13#$7A#$72#$08#$21#$11 +
+            #$28#$B2#$35#$EC#$7A#$E5#$23#$D5#$66#$D6#$4C#$7A#$82#$FD#$6E#$1F#$3A#$01#$DC#$38#$3A#$21#$7B#$23#$B5#$FA#$CC#$05#$65#$8D#$DC#$DA#$5C#$A7#$0A#$1A#$A0#$02#$F4#$B6#$A0#$32#$34#$77#$C5#$E2#$BB#$10 +
+            #$46#$CE#$57#$E3#$A9#$0B#$65#$73#$8F#$D5#$A5#$17#$83#$00#$BD#$40#$B1#$EE#$44#$F4#$EB#$28#$5B#$96#$A6#$C1#$94#$D3#$B6#$4B#$AE#$F4#$72#$F6#$EC#$AC#$D4#$52#$9E#$C7#$7A#$A8#$4B#$3D#$1D#$BC#$C0#$57 +
+            #$7B#$91#$62#$EE#$4D#$67#$F3#$BA#$8D#$BB#$6D#$E7#$48#$5E#$BE#$16#$48#$85#$6C#$52#$48#$00#$FF#$06#$95#$E1#$7E#$D9#$13#$98#$E0#$6D#$96#$13#$B7#$4B#$28#$3B#$AC#$C5#$0A#$37#$85#$BB#$6E#$E5#$E9#$2F +
+            #$2C#$0E#$9E#$B7#$44#$E7#$85#$F2#$5B#$FD#$EE#$8B#$C2#$B8#$30#$E0#$81#$29#$94#$DB#$33#$FF#$88#$32#$91#$F9#$CB#$14#$BC#$2D#$91#$26#$13#$4A#$A2#$E2#$D7#$D0#$CA#$9F#$1F#$36#$7A#$12#$7D#$0C#$9A#$0B +
+            #$E6#$5C#$E2#$B7#$4D#$E5#$0B#$A4#$3E#$25#$F8#$D9#$8D#$9D#$F4#$E3#$2C#$8A#$9B#$98#$AD#$6B#$F5#$0F#$FB#$7D#$DA#$2A#$FE#$21#$18#$76#$9A#$1A#$55#$FC#$25#$CA#$3E#$F9#$FD#$E4#$B6#$2D#$10#$3E#$58#$79 +
+            #$D8#$30#$ED#$DD#$4B#$B6#$0F#$D5#$D6#$F6#$B4#$B1#$37#$7C#$4E#$29#$E6#$F7#$79#$23#$74#$01#$66#$5F#$02#$EB#$F2#$9F#$51#$02#$39#$31#$AA#$8B#$BC#$DE#$6E#$5A#$6D#$AF#$3A#$84#$23#$34#$F4#$13#$9C#$04 +
+            #$FD#$7E#$6C#$E7#$22#$CC#$B9#$32#$6B#$D9#$C2#$77#$C2#$7B#$DF#$E9#$B6#$17#$53#$AF#$7B#$A6#$94#$AE#$39#$39#$00#$EF#$75#$E2#$4D#$15#$F6#$45#$1A#$B2#$9F#$D6#$82#$24#$45#$B2#$07#$A7#$00#$3D#$14#$01 +
+            #$62#$40#$DD#$D2#$B8#$F0#$96#$9B#$07#$0C#$49#$F8#$74#$B2#$BF#$E9#$31#$B3#$2E#$9D#$2F#$30#$C2#$F6#$ED#$4C#$56#$42#$D4#$47#$55#$6A#$F4#$39#$C2#$23#$5F#$58#$BD#$2C#$7B#$C5#$4A#$DC#$8A#$AD#$40#$E5 +
+            #$84#$A0#$65#$B3#$65#$73#$74#$9F#$AB#$BD#$E6#$09#$A2#$24#$65#$8D#$F6#$5B#$5B#$14#$4B#$C0#$6A#$78#$F2#$D6#$F3#$76#$45#$A0#$77#$DD#$AA#$DB#$13#$F9#$9F#$0F#$5A#$A5#$A0#$B9#$28#$48#$95#$24#$03#$2D +
+            #$94#$6E#$E1#$05#$F7#$5C#$23#$82#$29#$95#$A1#$7C#$F2#$E3#$B9#$2F#$AC#$29#$11#$EC#$60#$D1#$4C#$5F#$B8#$D2#$1E#$9D#$EC#$76#$1D#$FC#$5F#$C0#$FE#$D1#$50#$33#$0A#$42#$D7#$83#$C9#$F9#$49#$54#$BB#$50 +
+            #$17#$6C#$6B#$38#$C1#$31#$19#$DB#$FC#$DE#$CE#$17#$AD#$B2#$D1#$DA#$0A#$13#$EE#$2B#$ED#$3A#$EA#$EA#$20#$8E#$17#$14#$0B#$88#$EE#$B9#$A5#$02#$1B#$E8#$6C#$F7#$FB#$E4#$18#$72#$E7#$35#$88#$DE#$8E#$B8 +
+            #$56#$FB#$D9#$8C#$B8#$81#$A7#$39#$AC#$F2#$D2#$39#$0B#$AF#$7F#$B6#$D2#$0E#$A5#$C7#$A0#$B3#$EF#$6F#$4B#$F4#$08#$78#$B2#$A8#$89#$CD#$0E#$0E#$8A#$B1#$8F#$8C#$AC#$E3#$23#$23#$B6#$D1#$6C#$80#$FD#$F5 +
+            #$4D#$65#$3B#$75#$17#$FC#$81#$A3#$88#$15#$2A#$EE#$19#$E0#$FD#$F5#$F1#$C2#$C3#$DD#$EE#$7A#$08#$12#$25#$72#$75#$42#$77#$8D#$51#$5B#$D6#$31#$61#$88#$21#$73#$86#$2E#$E5#$8E#$0B#$3E#$BE#$61#$B8#$E4 +
+            #$FD#$FA#$67#$C6#$44#$78#$B2#$31#$D9#$8B#$BF#$A8#$07#$8F#$7E#$BE#$46#$54#$53#$24#$9A#$25#$E5#$D3#$5F#$C0#$22#$20#$EA#$C0#$86#$CD#$6C#$F8#$7A#$4A#$6C#$18#$BD#$0F#$CC#$F3#$5F#$7F#$E0#$BE#$B0#$53 +
+            #$94#$5F#$E0#$89#$11#$86#$92#$F2#$3F#$1A#$BD#$E8#$68#$B8#$35#$3B#$91#$8F#$85#$73#$98#$B9#$7E#$D1#$C0#$AD#$F8#$4D#$72#$04#$4F#$1D#$AD#$82#$5F#$86#$DD#$89#$17#$73#$38#$F8#$25#$34#$BA#$57#$24#$F8 +
+            #$F3#$E3#$50#$AE#$41#$D9#$91#$F8#$AC#$8E#$C4#$87#$F6#$58#$D2#$1C#$31#$9B#$C9#$0E#$28#$56#$C9#$5F#$09#$43#$73#$A0#$79#$13#$58#$F2#$5E#$25#$89#$8F#$17#$58#$9E#$B3#$5E#$30#$6C#$8A#$AB#$81#$43#$27 +
+            #$6C#$53#$82#$08#$19#$B9#$C0#$FB#$DA#$F4#$DD#$BD#$55#$66#$8D#$71#$FF#$67#$40#$4E#$53#$B3#$70#$22#$7B#$80#$20#$8C#$92#$3F#$0F#$73#$AB#$F1#$E4#$5A#$A2#$57#$3D#$DF#$DE#$39#$D0#$E5#$47#$1C#$41#$DA +
+            #$7A#$95#$0C#$5E#$E4#$A3#$84#$34#$6E#$3E#$A4#$9A#$FD#$22#$46#$A9#$79#$65#$69#$19#$6A#$CE#$8A#$E9#$58#$94#$4A#$E1#$D9#$71#$02#$D9#$8F#$46#$A6#$5C#$59#$48#$1F#$63#$97#$1F#$AF#$FC#$11#$F0#$08#$02 +
+            #$11#$02#$FF#$70#$A4#$E7#$3A#$B9#$5C#$F1#$70#$CA#$58#$F3#$1A#$00#$14#$FA#$7C#$BF#$7E#$1B#$DE#$7E#$D6#$4F#$58#$40#$FB#$8F#$EA#$DC#$8B#$EC#$E2#$2A#$DD#$39#$97#$04#$BE#$3D#$8E#$0C#$AD#$9B#$48#$EF +
+            #$92#$5F#$76#$E3#$0C#$0D#$40#$20#$08#$4A#$46#$E7#$65#$38#$F1#$B4#$43#$E6#$99#$06#$5D#$D5#$4D#$7B#$DF#$D6#$46#$7A#$92#$55#$56#$08#$E4#$5F#$08#$D8#$C5#$94#$A6#$5E#$FE#$3B#$EC#$A3#$E8#$54#$90#$2B +
+            #$F7#$F3#$37#$25#$90#$26#$0A#$1C#$78#$E6#$E5#$8D#$FF#$53#$96#$4B#$BB#$E4#$DE#$46#$05#$68#$7C#$BF#$05#$19#$D4#$D2#$C6#$8E#$AE#$E9#$45#$31#$60#$F8#$4C#$D1#$9A#$F1#$CA#$6E#$6E#$61#$33#$D0#$57#$15 +
+            #$0E#$15#$6A#$14#$06#$1D#$CE#$65#$CA#$45#$71#$A7#$BB#$7A#$DE#$CE#$F6#$EA#$62#$A6#$FA#$54#$C1#$AE#$B4#$77#$26#$07#$C0#$10#$30#$B1#$CC#$24#$BF#$E8#$45#$C2#$A9#$D3#$4B#$66#$A1#$E3#$F0#$57#$B0#$FE;
     ),
     (
       iterations: $0000001;
@@ -1398,11 +1433,14 @@ const
     (
       iterations: $0000001;
       input:
-            '3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456' +
-            '485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733' +
-            '624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499' +
-            '999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858' +
-            '6328';
+            '3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844' +
+            '60955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564' +
+            '85669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213' +
+            '84146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362' +
+            '44065664308602139494639522473719070217986094370277053921717629317675238467481846766940513200056812714526356082778577134275778960' +
+            '91736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999' +
+            '98372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669' +
+            '14730359825349042875546873115956286388235378759375195778185778053217122680661300192787661119590921642019893809525720106548586328';
     ),
     (
       iterations: $1000000;
@@ -1438,8 +1476,23 @@ begin
     Digest := TMHash384.Create();
     for j := 0 to TEST_VECTOR[i].iterations-1 do
     begin
+      if (@callback <> nil) then
+      begin
+        callback(Length(TEST_VECTOR), i + 1, GetProgress(TEST_VECTOR[i].iterations, j));
+      end;
+      if (abortFlag <> nil) then
+      begin
+        if (abortFlag.WaitFor(0) = wrSignaled) then
+        begin
+          raise Exception.Create('Operation was aborted by the user!');
+        end;
+      end;
       Digest.Update(TEST_VECTOR[i].input);
     end;
+    if (@callback <> nil) then
+    begin
+      callback(Length(TEST_VECTOR), i + 1, 100);
+    end;
     Digest.Result(Hash);
     if not CompareMem(@Hash[0], @TEST_RESULT[i][0], MHASH384_LEN) then
     begin