The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 1,839 other subscribers

Archive for the ‘Development’ Category

6502 emulation: the ICE, or in-circuit-emulator…

Posted by jpluimers on 2019/02/05

On my list of hardware things to try:

[WayBack] a different take on 6502 emulation: the ICE, or in-circuit-emulator… – mos6502 – Google+

Basically it consists of three parts:

 

–jeroen

 

Posted in 6502, Development, Hardware Development, History, Z80 | Leave a Comment »

keyman/DevDelphiStarterCompileWrapper.pas at master · keymanapp/keyman

Posted by jpluimers on 2019/02/05

Cool: bds.exe -ns -b projectname.dproj will build a project from the command-line.

Should work in Starter Edition (and the now defunct AppMethod).

[WayBackkeyman/DevDelphiStarterCompileWrapper.pas at master · keymanapp/keyman.

Via: [WayBack] Question: is there any chance Embarcadero would reconsider and stop blocking the use of the command line compilers for Starter Edition?I run an open s… – Marc Durdin – Google+

–jeroen

Posted in Delphi, Development, Software Development | Leave a Comment »

RawGit is going away: redirect your content before October 2019 (it does disappear after that)

Posted by jpluimers on 2019/02/04

[WayBack] RawGit: RawGit served raw files directly from GitHub with proper Content-Type headers.

This means you have to redirect your existing RawGit links before October 2019, and you cannot add new links on RawGit.

You might want to try alternatives, for instance this one I mentioned in 2017: raw.githack.com – like rawgit.com but supports bitbucket as well and runs on plain nginx.

[WayBack] raw.githack.com:

raw.githack.com serves raw files directly from GitHub, Bitbucket or GitLab with proper Content-Type headers.

There are some other options that RawGit itself mentions:

What you should use instead

The following free services offer fantastic alternatives to some or all of RawGit’s functionality. You may like them even more than RawGit.

RawGit source is still at [WayBack] GitHub – rgrove/rawgit: Served files from raw.githubusercontent.com, but with the correct content types., so if you want to host your own alternative you can.

It means I need to change these pages:

–jeroen

 

Posted in Development, DVCS - Distributed Version Control, gist, GitHub, Power User, rawgit, Source Code Management | Leave a Comment »

‪Dear #lazyweb, can anyone point me to a modern email server setup (just emai…

Posted by jpluimers on 2019/02/01

Summary from [WayBack]‪ Dear #lazyweb, can anyone point me to a modern email server setup (just email) with letsencrypt, some spam filter, multi domain preferably on RHEL/Cent… – Jan Wildeboer – Google+

  • many SMTP servers on the interwebs do not have proper TLS setups, so do not require remote SMTP servers to deliver email with a proper certificate
  • delivering mail via SMTP using STARTTLS with a proper certificate yourself is a good step forward
  • postfix
  • dovecot
  • greylisting (although in practice it does not make much of a difference any more)
  • fail2ban
  • dnsbl (often called rbl)
  • spamassasin
  • rspamd (supports SPF, DKIM and many others)
  • letsencrypt automation can be tough, so here is a small wrapper: [WayBack] GitHub – DrGlitchMX/update-letsencrypt: Tiny script for updating “Let’s Encrypt!” certificates from cron
  • it helps having letsencrypt and the mail server to be on one machine:
    • multidomain let’s encrypt cert that has my webserver name and the mailserver in the Subject Alternative Names field. As both are on the same machine certbot can automatically update it and I just point Postfix and Dovecot to the LE files.
  • Hans-Martin Mosner SMTP as-is is just not suitable for the kind of decentralized mail that you would prefer. You need some mechanism to determine which mail senders to trust and which not. Cryptography is suitable at the MUA level and should be used much more, but at the MTA level, TLS for privacy and SPF(bleh) or DKIM(meh) for sender domain authentication are basically your only weapons -much too weak. The PGP web of trust must be considered a failed experiment – who of your mail contacts uses PGP properly or at all? Ironically the only secure messaging solutions for the masses are centralized.

Things to do:

  • find a proper multi-MX fallback setup guide for postfix

–jeroen

Read the rest of this entry »

Posted in *nix, *nix-tools, Communications Development, Development, Internet protocol suite, postfix, Power User, SMTP | Leave a Comment »

Passing the `–symbol-report` to the Delphi compiler gives you a nice XML overview with all symbols used

Posted by jpluimers on 2019/01/31

Cool undocumented parameter --symbol-report at the [WayBack/Archive] Hatena Diary mid 2017:

Read the rest of this entry »

Posted in Conference Topics, Conferences, Delphi, Development, Event, Software Development, Undocumented Delphi | 7 Comments »

Scaling, automatically and manually – The Isoblog.

Posted by jpluimers on 2019/01/31

You don’t want to reach the saturation line (Sättigung) on the right: if you do, things go down very fast.

TL;DR of TL;DR:

Reactive autoscaling sucks. Get out of it. Model your shit.

TL;DR:

A reactive scheme where you try automatically detect where the hockey sticks curve mens you are always too late as user experience is already down the drain: no matter the environment, the curve is always too steep to go unnoticed.

If you use loadav in your reactive scheme, you’re lost even more.

So you need a proactive scheme with models. Those models of course are based on prior monitoring of situations where things went bad combined with knowledge on how the system is likely to scale. Each time the system goes bad, refine your models.

Monitoring

I was really glad that Kristian followed up with [WayBack] Monitoring – the data you have and the data you want – The Isoblog.

According to Kristian, the first monitoring tier should be something like [WayBackPrometheus – Monitoring system & time series database: An open-source monitoring system with a dimensional data model, flexible query language, efficient time series database and modern alerting approach.

I’m glad he mentioned that, as I’m a bit fed up with sites having Nagios and Zabbix. Way too cumbersome to setup, and either not far enough features, or the dashboards aren’t insightful enough.

–jeroen

Sources:

Percentile video:

Read the rest of this entry »

Posted in Developing scalable systems, Development, Software Development | Leave a Comment »

The G+ GExperts community does no longer accept new members and new posts: use the English DelphiPraxis GExperts sub-forum (which has RSS)

Posted by jpluimers on 2019/01/31

For GExperts: go to http://en.delphipraxis.net/forum/31-gexperts/ with these RSS feed https://en.delphipraxis.net/forum/31-gexperts.xml/

Via [WayBack] NOTE: This community does no longer accept new members and new posts. Since Google will shut down Google+ in April 2019, I have moved to the GExperts su… – Jeroen Wiert Pluimers – Google+ and[WayBack] NOTE: This community does no longer accept new members and new posts. Since Google will shut down Google+ in April 2019, I have moved to the GExperts su… – Thomas Mueller (dummzeuch) – Google+

–jeroen

 

Posted in Delphi, Development, Software Development | Leave a Comment »

delphi – in Delphi7, How can I retrieve hard disk unique serial number? – Stack Overflow

Posted by jpluimers on 2019/01/30

From long time ago, but since I needed it in Delphi 2007 again: [WayBack] delphi – in Delphi7, How can I retrieve hard disk unique serial number? – Stack Overflow:

Following the links in the question comments Sertac posted, I came across this interesting C++ question, where Fredou answered with a nice link to a codeproject example showing how to do this in .NET, which in turn was based on a link to Borland C++ code and article.

The cool thing is that this C++ code works as a non-administrator user too!

Now you need someone to help you translate this C++ code to Delphi.

EditFound a Delphi unit that does this for you.

I wrote some sample use for it:

program DiskDriveSerialConsoleProject;

{$APPTYPE CONSOLE}

uses
  Windows,
  SysUtils,
  hddinfo in 'hddinfo.pas';

const
  // Max number of drives assuming primary/secondary, master/slave topology
  MAX_IDE_DRIVES = 16;

procedure ReadPhysicalDriveInNTWithZeroRights ();
var
  DriveNumber: Byte;
  HDDInfo: THDDInfo;
begin
  HDDInfo := THDDInfo.Create();
  try
    for DriveNumber := 0 to MAX_IDE_DRIVES - 1 do
    try
      HDDInfo.DriveNumber := DriveNumber;
      if HDDInfo.IsInfoAvailable then
      begin
        Writeln('VendorId: ', HDDInfo.VendorId);
        Writeln('ProductId: ', HDDInfo.ProductId);
        Writeln('ProductRevision: ', HDDInfo.ProductRevision);
        Writeln('SerialNumber: ', HDDInfo.SerialNumber);
        Writeln('SerialNumberInt: ', HDDInfo.SerialNumberInt);
        Writeln('SerialNumberText: ', HDDInfo.SerialNumberText);
      end;
    except
      on E: Exception do
        Writeln(Format('DriveNumber %d, %s: %s', [DriveNumber, E.ClassName, E.Message]));
    end;
  finally
    HDDInfo.Free;
  end;
end;

begin
  ReadPhysicalDriveInNTWithZeroRights;
  Write('Press <Enter>');
  Readln;
end.

Unit from http://www.delphipraxis.net/564756-post28.html

// http://www.delphipraxis.net/564756-post28.html

unit hddinfo;

interface

uses Windows, SysUtils, Classes;

const
  IOCTL_STORAGE_QUERY_PROPERTY = $2D1400;

type
  THDDInfo = class (TObject)
  private
    FDriveNumber: Byte;
    FFileHandle: Cardinal;
    FInfoAvailable: Boolean;
    FProductRevision: string;
    FProductId: string;
    FSerialNumber: string;
    FVendorId: string;
    procedure ReadInfo;
    procedure SetDriveNumber(const Value: Byte);
  public
    constructor Create;
    property DriveNumber: Byte read FDriveNumber write SetDriveNumber;
    property VendorId: string read FVendorId;
    property ProductId: string read FProductId;
    property ProductRevision: string read FProductRevision;
    property SerialNumber: string read FSerialNumber;
    function SerialNumberInt: Cardinal;
    function SerialNumberText: string;
    function IsInfoAvailable: Boolean;
  end;

implementation

type
  STORAGE_PROPERTY_QUERY = packed record
    PropertyId: DWORD;
    QueryType: DWORD;
    AdditionalParameters: array[0..3] of Byte;
  end;

  STORAGE_DEVICE_DESCRIPTOR = packed record
    Version: ULONG;
    Size: ULONG;
    DeviceType: Byte;
    DeviceTypeModifier: Byte;
    RemovableMedia: Boolean;
    CommandQueueing: Boolean;
    VendorIdOffset: ULONG;
    ProductIdOffset: ULONG;
    ProductRevisionOffset: ULONG;
    SerialNumberOffset: ULONG;
    STORAGE_BUS_TYPE: DWORD;
    RawPropertiesLength: ULONG;
    RawDeviceProperties: array[0..511] of Byte;
  end;

function ByteToChar(const B: Byte): Char;
begin
  Result := Chr(B + $30)
end;

function SerialNumberToCardinal (SerNum: String): Cardinal;
begin
  HexToBin(PChar(SerNum), PChar(@Result), SizeOf(Cardinal));
end;

function SerialNumberToString(SerNum: String): String;
var
  I, StrLen: Integer;
  Pair: string;
  B: Byte;
  Ch: Char absolute B;

begin
  Result := '';
  StrLen := Length(SerNum);

  if Odd(StrLen) then Exit;

  I := 1;

  while I < StrLen do
  begin
    Pair := Copy (SerNum, I, 2);
    HexToBin(PChar(Pair), PChar(@B), 1);
    Result := Result + Chr(B);
    Inc(I, 2);
  end;

  I := 1;

  while I < Length(Result) do
  begin
    Ch := Result[I];
    Result[I] := Result[I + 1];
    Result[I + 1] := Ch;
    Inc(I, 2);
  end;
end;

constructor THddInfo.Create;
begin
  inherited;

  SetDriveNumber(0);
end;

function THDDInfo.IsInfoAvailable: Boolean;
begin
  Result := FInfoAvailable
end;

procedure THDDInfo.ReadInfo;
type
  PCharArray = ^TCharArray;
  TCharArray = array[0..32767] of Char;

var
  Returned: Cardinal;
  Status: LongBool;
  PropQuery: STORAGE_PROPERTY_QUERY;
  DeviceDescriptor: STORAGE_DEVICE_DESCRIPTOR;
  PCh: PChar;

begin
  FInfoAvailable := False;
  FProductRevision := '';
  FProductId := '';
  FSerialNumber := '';
  FVendorId := '';

  try
    FFileHandle := CreateFile(
                     PChar('\\.\PhysicalDrive' + ByteToChar(FDriveNumber)),
                     0,
                     FILE_SHARE_READ or FILE_SHARE_WRITE,
                     nil,
                     OPEN_EXISTING,
                     0,
                     0
                   );

    if FFileHandle = INVALID_HANDLE_VALUE then
      RaiseLastOSError;

    ZeroMemory(@PropQuery, SizeOf(PropQuery));
    ZeroMemory(@DeviceDescriptor, SizeOf(DeviceDescriptor));

    DeviceDescriptor.Size := SizeOf(DeviceDescriptor);

    Status := DeviceIoControl(
                FFileHandle,
                IOCTL_STORAGE_QUERY_PROPERTY,
                @PropQuery,
                SizeOf(PropQuery),
                @DeviceDescriptor,
                DeviceDescriptor.Size,
                Returned,
                nil
              );

    if not Status then
      RaiseLastOSError;

    if DeviceDescriptor.VendorIdOffset <> 0 then
    begin
      PCh := @PCharArray(@DeviceDescriptor)^[DeviceDescriptor.VendorIdOffset];
      FVendorId := PCh;
    end;

    if DeviceDescriptor.ProductIdOffset <> 0 then
    begin
      PCh := @PCharArray(@DeviceDescriptor)^[DeviceDescriptor.ProductIdOffset];
      FProductId := PCh;
    end;

    if DeviceDescriptor.ProductRevisionOffset <> 0 then
    begin
      PCh := @PCharArray(@DeviceDescriptor)^[DeviceDescriptor.ProductRevisionOffset];
      FProductRevision := PCh;
    end;

    if DeviceDescriptor.SerialNumberOffset <> 0 then
    begin
      PCh := @PCharArray(@DeviceDescriptor)^[DeviceDescriptor.SerialNumberOffset];
      FSerialNumber := PCh;
    end;

    FInfoAvailable := True;
  finally
    if FFileHandle <> INVALID_HANDLE_VALUE then
      CloseHandle(FFileHandle);
  end;
end;

function THDDInfo.SerialNumberInt: Cardinal;
begin
  Result := 0;
  if ((IsInfoAvailable = True) and (FSerialNumber <> '')) then Result := SerialNumberToCardinal(FSerialNumber)
end;

function THDDInfo.SerialNumberText: string;
begin
  Result := '';
  if ((IsInfoAvailable = True) and (FSerialNumber <> '')) then Result := SerialNumberToString(FSerialNumber)
end;

procedure THDDInfo.SetDriveNumber(const Value: Byte);
begin
  FDriveNumber := Value;
  ReadInfo;
end;

end.

EditRAID configurations require special provisions.

For instance, I got a RAID system with multiple RAID 5 array; only the first one displays, and it does not show the drive serial numbers, but the serial number of the RAID array:

VendorId: AMCC
ProductId: 9550SXU-16ML
ProductRevision: 3.08
SerialNumber: 006508296D6A2A00DE82
SerialNumberInt: 688416000

–jeroen

–jeroen

Posted in Delphi, Development, Software Development | Leave a Comment »

Tips and Tricks in the Visual Studio Debugger | Microsoft Docs

Posted by jpluimers on 2019/01/30

A few things in there that I didn’t know yet (like pinning data tips, tracking out-of-scope variables with object-ID and debugger attachment): [WayBackTips and Tricks in the Visual Studio Debugger | Microsoft Docs.

Via: [WayBackUsing the debugger in #VisualStudio? Learn how to pin #data tips, change the execution flow, & more w/ these tips & tricks: http://msft.social/wbmUes – Lars Fosdal – Google+

–jeroen

 

–jeroen

Posted in .NET, C#, Development, Software Development | Leave a Comment »

Quick Intro Into Actions on Google | Grokking Android

Posted by jpluimers on 2019/01/30

Hopefully by now the Google Assistant and Google Home have made their way into the Dutch language. If so, then it’s time for me

[WayBackQuick Intro Into Actions on Google | Grokking Android: Find out which options exist to develop apps for the Google Assistant with Actions on Google and to bring the Assistant to devices with the Assistant SDK.

–jeroen

 

Posted in Android, Android Devices, Development, Google, Google AI, Google Assistant, GoogleHome, Mobile Development, Software Development | Leave a Comment »