Apt-Get: Viewing Release Notes on Packages Updated and/or Installed

Subjectively speaking, you might want to see release notes for packages, whether you’re installing them or updating them. (If this isn’t down your avenue of caring or you’re looking for a more exciting post, then, you can probably just skip this rest of this, altogether. True story.)

apt_get

Anyways, if you use terminal to update your machine, there’s a Debian package (sorry, other flavours, I haven’t dug into it but maybe you have the equivalent?) that – when installed – will configure apt-get to automatically prompt you with the release notes for any update or package that you install.

Of course, the caveat is that if you’re updating (e.g.: upgrade), the release notes are shown just before install.

The package, in question, is called apt-listchanges. You can see screenshots of it in action, here.

Install it as you would any other package and that’s it. ūüôā

linux_your_grandma_could_do_it

Azure: Enabling Function Apps to Access Microsoft Graph

With Azure Functions, it’s even easier to code to Azure; however, with such portability comes a little bit of pain to the growing processes. It used to be (and still is, frankly) that you had to register a full-blown application in Azure Active Directory to grant your application read access to other resources, such as Microsoft Graph. However, with these new features, we can bypass a lot of the old-school red-tape to get what we need to do up and running.

The first thing that you’ll want to do in your Azure Function App is to enable it’s Managed Identity. Keep in mind that all of the functions within your Azure Function App resource will have this shared managed identity, so this could present security implications, as you roll-out more functions in a shared space.

In the Azure Portal, go your Azure Function App, pick the specific Function App in question, go to Platform Features, select Identity, and then – under System assigned – toggle the Status to On. Save it. Wait for the execution to complete and then Refresh the page. Save the ObjectId, as we’ll be using that to grant our Functions within the Function App access to the Microsoft Graph.

AzureFunctionAppManagedIdentity

Now that we have a service principal (via managed identity), we need to grant it permissions to the Graph Application, itself, at the tenant level.

Unfortunately, we can’t – at present – do this via the Azure Portal, so to do so, we’ll need to use the Azure Active Directory PowerShell Snap-In and we need to decide which permissions that we want to grant to our Azure Function App.

Connect as you normally would in your tenant and then run the following commands, replacing the redacted object id value with the one that you copied from the portal in the steps above and changing the target role value to be whichever roles in Graph that you want to assign (remember: this is at the Function App level and not individualised for specific functions within the Function App). In this case, I’m after reading the Security Alerts from Microsoft Graph, so this is the only role that I’ll be targeting. YMMV.

$objectId = [REDACTED]
$graph = Get-AzureADServicePrincipal -Filter “AppId eq ‘00000003-0000-0000-c000-000000000000′”
$targetRole = $graph.AppRoles | Where{$_.Value -like “*SecurityEvents.Read.All*”}
$msp = Get-AzureADServicePrincipal -ObjectId $objectId
New-AzureADServiceAppRoleAssignment -Id $targetRole.Id -PrincipalId $msp.ObjectId -ObjectId $msp.ObjectId -ResourceId $graph.ObjectId

If all goes according to plan, then you should see output similar to the below.

ObjectId ResourceDisplayName PrincipalDisplayName
——– ——————- ——————–
ibpZvR05qk2N7TMPftyjXxh14LgZiq1Fo41w-kdjaYA Microsoft Graph [REDACTED]

Now, you can leverage Microsoft Graph in the Functions contained within your Azure Function App for whichever permission[s] that you just granted the Azure Functions App.

Happy dev’ing! ūüôā

 

 

DLNA: Network Shares Cause Blocking Threads in Windows Explorer During Copying Events

TL;DR – DLNA shares have a bug which can cause Explorer to stop copying data across the share, nigh indefinitely. The easiest work-around is to restart Windows Explorer, delete the target file in the previous copy operation, and start anew.

I’ve discovered a bug that I can’t seem to get addressed because the assembly isn’t publicly documented, anywhere, but I figured that I would write about what happens to explain it to those of you who run into it.

First, we need to cover what DLNA (Digital Living Network Alliance) is. (Wiki article is here.) DLNA is a standard by which multiple libraries can be accessed for sharing/streaming, without having had a proprietary library to communicate between them.

Plex Media Server is one such media streaming service built using the DLNA libraries for sharing resources. One of the DLNA features, in Windows, is that it appears as a Network Share/Location in Windows Explorer.

So, we have a Plex Media Server and it’s serving DLNA. The media on the server is browsable, as it if were a dedicated network share. If we treat it as such and copy from one location to another, this is when this particular bug surfaces.

Microsoft has implement DLNA in x86 and x64 processes via assemblies included in Windows. In particular, for this bug, we care about the mfnetcore.dll assembly, which can be found in either the System32 or the SysWow64 folders.

Here’s a dump of the stack during repro:

81 TID:0e60 kb kbn kbnL kn knL kpn kPn
# Child-SP RetAddr Call Site
00 00000000`2fc8eb18 00007ffb`272683d3 ntdll!NtWaitForSingleObject+0x14
01 00000000`2fc8eb20 00007ffa`e0845d59 KERNELBASE!WaitForSingleObjectEx+0x93
02 00000000`2fc8ebc0 00007ffa`f135812f mfnetcore!MFGetSupportedDLNAProfileInfo+0xaa69
03 00000000`2fc8ec60 00007ffb`27ba03ed mfplat!CStreamOnMFByteStream::Read+0xef
04 00000000`2fc8ecb0 00007ffb`27ad01c5 windows_storage!SHCopyStreamWithProgress2+0x1ad
05 00000000`2fc8ed90 00007ffb`27ad03ce windows_storage!CCopyOperation::_CopyResourceStreams+0x89
06 00000000`2fc8ee00 00007ffb`278e50df windows_storage!CCopyOperation::_CopyResources+0x17e
07 00000000`2fc8eea0 00007ffb`276f784f windows_storage!CCopyOperation::Do+0x1b5cbf
08 00000000`2fc8efa0 00007ffb`276f5d4f windows_storage!CCopyWorkItem::_DoOperation+0x9b
09 00000000`2fc8f080 00007ffb`276f657a windows_storage!CCopyWorkItem::_SetupAndPerformOp+0x2a3
0a 00000000`2fc8f370 00007ffb`276f2f1e windows_storage!CCopyWorkItem::ProcessWorkItem+0x152
0b 00000000`2fc8f620 00007ffb`276f3907 windows_storage!CRecursiveFolderOperation::Do+0x1be
0c 00000000`2fc8f6c0 00007ffb`276f33d6 windows_storage!CFileOperation::_EnumRootDo+0x277
0d 00000000`2fc8f760 00007ffb`276fd25c windows_storage!CFileOperation::PrepareAndDoOperations+0x1c6
0e 00000000`2fc8f830 00007ffb`2874c525 windows_storage!CFileOperation::PerformOperations+0x10c
0f 00000000`2fc8f890 00007ffb`2874acf0 shell32!CFSDropTargetHelper::_MoveCopyHIDA+0x269
10 00000000`2fc8f940 00007ffb`2874d517 shell32!CFSDropTargetHelper::_Drop+0x220
11 00000000`2fc8fe20 00007ffb`29b6c315 shell32!CFSDropTargetHelper::s_DoDropThreadProc+0x37
12 00000000`2fc8fe50 00007ffb`2ab17974 SHCore!_WrapperThreadProc+0xf5
13 00000000`2fc8ff30 00007ffb`2aeba271 kernel32!BaseThreadInitThunk+0x14
14 00000000`2fc8ff60 00000000`00000000 ntdll!RtlUserThreadStart+0x21

Note that frames that we, generally, care about are in orange and red at the top of the stack and those are the last instructions executed in the thread. In this case, we’re waiting on a response from the request to get the supported DLNA profile information and this is demonstrated by the fact that we’re waiting on an object at the top of the stack. Essentially, we have an open/blocking request that has never completed and the thread will have to die to unblock the request.

We can see the block happen on other native threads. Specifically, in the dump that I created, there were three threads with the same stacks, shown as below.

97 TID:3cdc kb kbn kbnL kn knL kpn kPn
# Child-SP RetAddr Call Site
00 00000000`3448f9e8 00007ffb`299bf5cd win32u!NtUserMsgWaitForMultipleObjectsEx+0x14
01 00000000`3448f9f0 00007ffa`f88e2cfd user32!RealMsgWaitForMultipleObjectsEx+0x1d
02 00000000`3448fa30 00007ffa`f88e2c24 duser!CoreSC::Wait+0x75
03 00000000`3448fa80 00007ffb`299d05d1 duser!MphWaitMessageEx+0x104
04 00000000`3448fae0 00007ffb`2aef33c4 user32!_ClientWaitMessageExMPH+0x21
05 00000000`3448fb30 00007ffb`26f51224 ntdll!KiUserCallbackDispatcherContinue
06 00000000`3448fb98 00007ffa`fad54913 win32u!NtUserWaitMessage+0x14
07 00000000`3448fba0 00007ffa`fad547a9 explorerframe!CExplorerFrame::FrameMessagePump+0x153
08 00000000`3448fc20 00007ffa`fad546f6 explorerframe!BrowserThreadProc+0x85
09 00000000`3448fca0 00007ffa`fad55a12 explorerframe!BrowserNewThreadProc+0x3a
0a 00000000`3448fcd0 00007ffa`fad670c2 explorerframe!CExplorerTask::InternalResumeRT+0x12
0b 00000000`3448fd00 00007ffb`2785b58c explorerframe!CRunnableTask::Run+0xb2
0c 00000000`3448fd40 00007ffb`2785b245 windows_storage!CShellTask::TT_Run+0x3c
0d 00000000`3448fd70 00007ffb`2785b125 windows_storage!CShellTaskThread::ThreadProc+0xdd
0e 00000000`3448fe20 00007ffb`29b6c315 windows_storage!CShellTaskThread::s_ThreadProc+0x35
0f 00000000`3448fe50 00007ffb`2ab17974 SHCore!_WrapperThreadProc+0xf5
10 00000000`3448ff30 00007ffb`2aeba271 kernel32!BaseThreadInitThunk+0x14
11 00000000`3448ff60 00000000`00000000 ntdll!RtlUserThreadStart+0x21

Work-arounds: This bug is pretty ugly and there aren’t a whole lot of work-arounds for it. One could wait for the lifetime of the thread to cause an abort, which could be a considerable amount of time. The work-around that I typically opt for is to restart Windows Explorer process, via Task Manager, delete the file and try to copy it again. Sure, it takes a lot of time but it’s considerably a far lower cost, time-wise, than waiting for a thread to become unblocked due to a timeout.

Announcing ‘Tomte’: The Customisable Remote Administration Tool for Windows Systems

TL;DR – I’ve released source code for remote systems administration via PowerShell + WCF + WindowsService, here, under the Mozilla Public License 2.0.¬†

Windows has a huge, glaring gap where Linux really shines: Remote configuration via tools. Sure, there’s DSC (Desired State Configuration) but it doesn’t help much for run-time automation and administration.

Tomte¬†(o, as in phone, and ‘e’, as in meh) is a framework (though lacking in some features) that was written to primarily address that and give SRE/DevOps teams a tool to quickly add an activity to be used (just add a PowerShell command and then the corresponding activity).

First things, first: We have to set the SQL Server up. Install your flavour of SQL server (I’ve port this code twice, now, so I just kept the instance name, as that made life easier) and run the following commands from the command line, replacing the instance name with your SQL Server instance and the database name with the database that you created.

osql -E -S .\SQL2008Express -d WorkflowInstanceStore -i C:\Windows\Microsoft.NET\Framework64\v4.0.30319\SQL\en\SqlWorkflowInstanceStoreSchema.sql

osql -E -S .\SQL2008Express -d WorkflowInstanceStore -i C:\Windows\Microsoft.NET\Framework64\v4.0.30319\SQL\en\SqlWorkflowInstanceStoreLogic.sql

IMPORTANT: If you want to configure the service to use a user-account, please change that in the source code and add permissions for the account to the SQL database; otherwise, the SQL database will require Anonymous Logon permissions, as the Local System account used for the Windows Service is obfuscated as an anonymous logon on SQL Server.

Now that the database is set-up, you’ll need to punch a hole in your firewall to listen on port 65534. You can change the listen port in the application configuration file of the Windows Service (Fels√∂kning.Tomte.AdminService) via the baseAddress setting.

        <host>

<baseAddresses>

<!– NOTE: The ‘*’ allows the service to install on any given machine –>

<add baseAddress=”http://*:65534/WorkflowService/service”/>

</baseAddresses>

</host>

Now that we have the SQL database ready and we’ve punched a hole in the firewall, we should install the Windows Service, first. Ensure that the build configuration of all of the projects is set to ‘x64’ and clean/build the solution.

To install the windows service, we’ll leverage the standard tools that ship with .NET, to prevent any cursory problems with “specialised” versions of these tools. In an elevated command (or PowerShell) window, run the following to install the service, replacing the path with your build’s output path.

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe C:\Code\git\felsokning\Tomte\Felsökning.Tomte\Felsökning.Tomte.AdminService\bin\x64\Debug\Felsökning.Tomte.AdminService.exe

Installationsverktyg för Microsoft (R) .NET Framework, version 4.7.3190.0

Copyright (C) Microsoft Corporation. Med ensamrätt.

 

 

Kör en överförd installation.

 

Startar installationsfasen av installationen.

Se loggfilen om du vill ha information om installationsförloppet för sammansättningen C:\Code\git\felsokning\Tomte\Felsökning.Tomte\Felsökning.Tomte.AdminService\bin\x64\Debug\Felsökning.Tomte.AdminService.exe.

Filen finns på C:\Code\git\felsokning\Tomte\Felsökning.Tomte\Felsökning.Tomte.AdminService\bin\x64\Debug\Felsökning.Tomte.AdminService.InstallLog.

Installerar sammansättningen C:\Code\git\felsokning\Tomte\Felsökning.Tomte\Felsökning.Tomte.AdminService\bin\x64\Debug\Felsökning.Tomte.AdminService.exe.

Berörda parametrar är:

logtoconsole =

assemblypath = C:\Code\git\felsokning\Tomte\Felsökning.Tomte\Felsökning.Tomte.AdminService\bin\x64\Debug\Felsökning.Tomte.AdminService.exe

logfile = C:\Code\git\felsokning\Tomte\Felsökning.Tomte\Felsökning.Tomte.AdminService\bin\x64\Debug\Felsökning.Tomte.AdminService.InstallLog

Installerar tj√§nsten Fels√∂kning.Tomte.AdminService…

Tjänsten Felsökning.Tomte.AdminService har installerats.

Skapar EventLog-k√§llan Fels√∂kning.Tomte.AdminService i loggen Application…

 

Installationsfasen slutfördes och allokeringsfasen inleds.

Se loggfilen om du vill ha information om installationsförloppet för sammansättningen C:\Code\git\felsokning\Tomte\Felsökning.Tomte\Felsökning.Tomte.AdminService\bin\x64\Debug\Felsökning.Tomte.AdminService.exe.

Filen finns på C:\Code\git\felsokning\Tomte\Felsökning.Tomte\Felsökning.Tomte.AdminService\bin\x64\Debug\Felsökning.Tomte.AdminService.InstallLog.

Utför sammansättningen C:\Code\git\felsokning\Tomte\Felsökning.Tomte\Felsökning.Tomte.AdminService\bin\x64\Debug\Felsökning.Tomte.AdminService.exe.

Berörda parametrar är:

logtoconsole =

assemblypath = C:\Code\git\felsokning\Tomte\Felsökning.Tomte\Felsökning.Tomte.AdminService\bin\x64\Debug\Felsökning.Tomte.AdminService.exe

logfile = C:\Code\git\felsokning\Tomte\Felsökning.Tomte\Felsökning.Tomte.AdminService\bin\x64\Debug\Felsökning.Tomte.AdminService.InstallLog

 

Allokeringsfasen slutfördes.

 

Den överförda installationen slutfördes.

Now that the Windows Service is installed, we need to start it. You can do this via any number of means. Start>Run>services.msc is an easy way to do that.

With the service running, we can now import the PowerShell module.

Import-Module “C:\Code\git\felsokning\Tomte\Fels√∂kning.Tomte\Fels√∂kning.Tomte.PowerShell\bin\x64\Debug\Fels√∂kning.Tomte.PowerShell.dll” -Verbose

VERBOSE: Loading module from path ‘C:\Code\git\felsokning\Tomte\Fels√∂kning.Tomte\Fels√∂kning.Tomte.PowerShell\bin\x64\Debug\Fels√∂kning.Tomte.PowerShell.dll’.

VERBOSE: Importing cmdlet ‘Update-RemoteWindowsSystem’.

VERBOSE: Importing cmdlet ‘Test-RemotePortConnectivity’.

VERBOSE: Importing cmdlet ‘Test-RemoteFileExists’.

VERBOSE: Importing cmdlet ‘Start-RemoteSecureDelete’.

VERBOSE: Importing cmdlet ‘Set-RemoteComputerName’.

VERBOSE: Importing cmdlet ‘Set-RemoteSymbolServerEnvironmentVariable’.

VERBOSE: Importing cmdlet ‘Restart-RemoteService’.

VERBOSE: Importing cmdlet ‘Restart-RemoteSystem’.

VERBOSE: Importing cmdlet ‘Request-DevOpsElevation’.

VERBOSE: Importing cmdlet ‘Install-RemoteSysInternals’.

VERBOSE: Importing cmdlet ‘Get-RemoteDateTime’.

VERBOSE: Importing cmdlet ‘Get-RemoteFileText’.

VERBOSE: Importing cmdlet ‘Get-RemoteFreeDiskSpace’.

VERBOSE: Importing cmdlet ‘Get-RemoteLoggedOnUsers’.

VERBOSE: Importing cmdlet ‘Get-RemoteOSVersion’.

VERBOSE: Importing cmdlet ‘Get-RemotePingResponse’.

VERBOSE: Importing cmdlet ‘Get-RemoteProcessIds’.

VERBOSE: Importing cmdlet ‘Get-RemoteProcessThreads’.

VERBOSE: Importing cmdlet ‘Get-RemoteServerTimeSkew’.

VERBOSE: Importing cmdlet ‘Get-RemoteSystemUptime’.

VERBOSE: Importing cmdlet ‘Get-RemoteWebResponseString’.

VERBOSE: Importing cmdlet ‘Get-RemoteWindowsEvents’.

VERBOSE: Importing cmdlet ‘Edit-RemoteConfigurationFile’.

VERBOSE: Importing cmdlet ‘Copy-RemoteFiles’.

VERBOSE: Importing cmdlet ‘Copy-RemoteImagesAndLibrariesForProcess’.

Now that the module is loaded, you can run commands against the remote (or local) endpoint running the Windows Service. (As you can see, I’ve found a localisation bug that I need to sort-out with the return from the DateTimeActivity – 05-01-2019 can easily be May 1st or the 5th of January, depending on how you datetime.)

Get-RemoteDateTime -Server 192.168.0.252

den 5 januari 2019 15:00:02

 

Get-RemoteFreeDiskSpace -Server 192.168.0.252

Drive C:\ has 87.52% free

Drive D:\ has 90.22% free

 

Get-RemoteOSVersion -Server 192.168.0.252 -Kernel32

Major  Minor  Build  Revision

—–¬† —–¬† —–¬† ——–

10     0      17763  1

 

Test-RemotePortConnectivity -Server 192.168.0.252 -TargetHost 8.8.8.8 -Port 53

True

Now that we’ve run a few workflows, let’s check the SQL database and verify that the data we expect to find is there.

SQLQuery

SQL Query showing the executions of the Workflows on the machine.

…and that’s just about it.

Hope that this helps someone at some point in the some future. ūüôā

C++: Using the Luhn Algorithm to Validate the CheckSum in the Personnummer Supplied in User Input

The Swedish Personnummer uses a variant of the Luhn Algorithm to generate a checksum (technically, a check digit) value that is is appended to the end of the personnummer. So, forexample, the nine-digit number YYMMDD-SSS would become YYMMDD-SSSC with the tenth digit being the checksum.

The model for generating the checksum is created by multiplying the alternating digits by a 2 or a 1 and, then, adding the sum of the products. In the nine-digit series, this means 212121212. So, for example, the number 010214-010 would become (0x2) + (1×1) + (0x2) + (2×1) + (1×2) + (4×1) + (0x2) + (1×1) + (0x2). When the product is greater than nine, the sum of those numbers is added. So, for example, 2×7 = 14 –> 1 + 4 = 5 and, thus, our result would be five for that single instance of digit.

The last number in the sum is then subtracted from 10 to create the checksum number. So, for example, 46 –> 6 and 10-6 = 4, and 4 becomes our checksum value.

Below is an C++ program to validate the checksum for the provided personnumer, given in the user-input. PersonnummerSet is merely a struct of ints that I’ve created in a header file, so that it can be referenced by other libraries (either by direct assignment to type or pointer). StringMagic is another header file that uses std::string.erase/std::remove to remove the ‘-‘ character from the input (Swedish Personnummers are¬†always written as YYMMDD-SSSC.)

#include <cstring> // Replacing the old and busted with the new hotness.
#include <iomanip>
#include <iostream>
#include <cstdio> // Replacing the old and busted with the new hotness.
#include "Personnummerset.h"
#include "StringMagic.h"

class Personnummer
{
public:
    /**
     *  The PersonNumber is a property of type PersonnnummerSet, which is used to process the digits
     *  from the personnummer provided.
     */
    PersonnummerSet PersonNumber {};

    /**
     *  Initializes a new instance of the <see cref="Personnummer" /> class.
     * @param number - The converted long from the user's input.
     */
    explicit Personnummer(long number)
    {
        // We separate the three digit serial to future-proof for deriving sex of the individual in future checks.
        this->PersonNumber.Year = static_cast<int>(number / 100000000 % 100);   // First 2 integers     (0&1)
        this->PersonNumber.Month = static_cast<int>(number / 1000000 % 100);    // Second 2 integers    (2&3)
        this->PersonNumber.Day = static_cast<int>(number / 10000 % 100);        // Third 2 integers     (4&5)
        this->PersonNumber.SerialNumber = static_cast<int>(number / 100 % 100); // Fourth 2 integers    (6&7)
        this->PersonNumber.Sex = static_cast<int>(number / 10 % 10);            // First 1 integer      (8)
        this->PersonNumber.CheckSum = static_cast<int>(number % 10);            // Second 1 integer     (9)
    }

public:
    /**
     *  Generates the Luhn Algorithm checksum and compares that from the checksum given from the user's input.
     * @return A boolean indicating of the calculated checksum matches the provided checksum.
     */
    bool ValidateCheckSum()
    {
        return this->PersonNumber.CheckSum == this->GenerateChecksum();
    }

private:
    /**
     * This is a variation of the Luhn Algorithm, which is used to generate the checksum from the
     * first nine digits of the personnummer. Each value in the first nine digits is multiplied by
     * either a 2 or a 1. See: https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2773709/figure/Fig1/
    */
    int GenerateChecksum()
    {
        int firstCheck;
        int fifthCheck;
        int seventhCheck;
        int ninthCheck;
        int firstYear = PersonNumber.Year > 9 ? PersonNumber.Year / 10 % 10 : 0;
        int secondYear = PersonNumber.Year%10;
        int firstMonth = PersonNumber.Month > 9 ? PersonNumber.Month / 10 % 10 : 0;
        int secondMonth = PersonNumber.Month%10;
        int firstDay = PersonNumber.Day > 9 ? PersonNumber.Day / 10 % 10 : 0;
        int secondDay = PersonNumber.Day%10;
        int firstSerial = PersonNumber.SerialNumber/10%10;
        int secondSerial = PersonNumber.SerialNumber%10;

        int firstYearDigit = firstYear * 2;
        if (firstYearDigit > 9)
        {
            int firstSum = firstYearDigit/10%10;
            int secondSum = firstYearDigit%10;
            firstCheck = firstSum + secondSum;
        }
        else
        {
            firstCheck = firstYearDigit;
        }

        int secondCheck = secondYear * 1;
        int thirdCheck = firstMonth * 2;
        int fourthCheck = secondMonth * 1;
        int firstDayCheck = firstDay * 2;
        if(firstDayCheck > 9)
        {
            int firstSum = firstDayCheck/10%10;
            int secondSum = firstDayCheck%10;
            fifthCheck = firstSum + secondSum;
        }
        else
        {
            fifthCheck = firstDayCheck;
        }

        int sixthCheck = secondDay * 1;
        int firstDigitRandom = firstSerial * 2;
        if (firstDigitRandom > 9)
        {
            int firstSum = firstDigitRandom/10%10;
            int secondSum = firstDigitRandom%10;
            seventhCheck = firstSum + secondSum;
        }
        else
        {
            seventhCheck = firstDigitRandom;
        }

        int eighthCheck = secondSerial * 1;
        int sexCheck = PersonNumber.Sex * 2;
        if(sexCheck > 9)
        {
            int firstSum = sexCheck/10%10;
            int secondSum = sexCheck%10;
            ninthCheck = firstSum + secondSum;
        }
        else
        {
            ninthCheck = sexCheck;
        }

        int sum = firstCheck + secondCheck + thirdCheck + fourthCheck + fifthCheck + sixthCheck + seventhCheck + eighthCheck + ninthCheck;
        int lastOfSum = sum%10;
        int checkSum = 10 - lastOfSum;
        return checkSum;

    }
};

int main()
{
    std::string user_input;
    std::cout << "Enter Personnummer (YYMMDD-SSSC): " << std::endl;
    std::cin >> user_input;

    // Necessary or the long conversion treats '-' or '+' as a delimiter.
    // NOTE: People aged over 99 will always have '+' in their personnummer.
    if(user_input.find('-') != std::string::npos)
    {
        StringMagic::RemoveDashFromString(user_input);
    }
    else if (user_input.find('+') != std::string::npos)
    {
        StringMagic::RemovePlusFromString(user_input);
    }

    // Smart-pointers are the future...
    std::unique_ptr<Personnummer> personNumber (new Personnummer(std::stol(user_input)));
    std::cout << std::boolalpha;
    std::cout << "CheckSum Passes: " << personNumber->ValidateCheckSum() << std::endl;

    personNumber.reset();
}

The above code can be used to validate almost any personnummer – save for those individuals whom are over 99 years of age, as the separator changes from ‘-‘ to ‘+’.

…and that’s about the extent of fun with Swedish Personnummers in C++ that this post will cover.

Thanks for coming to this NERDTalk‚ĄĘ and happy programming!

Ubuntu: Changing the Crypt (Plymouth) Login Screen

So, with all of this customisation of my Ubuntu machine going on, there had to be¬†something else that I could configure, right? Well, there’s a lot, actually, but from the purely aesthetical point of view, the crypt screen was the next logical choice.

For those of you who may not be aware, and haven’t implemented encryption via Yubikey and LUKS, you can encrypt your volume and are forced to enter it on boot to get into the system. Think of it like BitLocker‚ĄĘ for Windows‚ĄĘ¬ģ, only better.

celtic-come-at-me-bro

Oh, yeah, that’s right: I said it…

Anyways, the first thing that you’ll want to do is find a Plymoth theme. There’s actually a site full of them, here, and there’s – arguably – hundreds (if not thousands) more that you could find across the internet.

So, first things first, we download the theme. In my case it was the Paw Ubuntu/Mint Floral theme, just for the sake of proof-of-concept and the aesthetic appeals to me. YYMV. However, this is the them being used in this haphazard “how-to”.

Once the file is downloaded, extract it. (NOTE: Make sure that the script’s name matches the folder name; otherwise, the later regex will fail.) Move the contents of the inner parent to the shared directory on Ubuntu:

$ sudo mv Paw-Ubuntu-Floral /usr/share/plymouth/themes/

Now that it’s copied, we need to tell Ubuntu to build a new boot screen with the one we just copied over. This is fairly easy to do (kind of) in all of three commands:

$ sudo update-alternatives --install /usr/share/plymouth/themes/default.plymouth default.plymouth /usr/share/plymouth/themes/Paw-Ubuntu-Floral/paw-ubuntu-floral.plymouth 100 $ sudo update-alternatives --config default.plymouth
Det finns 2 val för alternativet default.plymouth (som tillhandahåller /usr/share/plymouth/themes/default.plymouth).

  Val          Sökväg                                                                 Prioritet  Status
------------------------------------------------------------
* 0            /usr/share/plymouth/themes/ubuntu-logo/ubuntu-logo.plymouth               100       automatiskt läge
  1            /usr/share/plymouth/themes/Paw-Ubuntu-Floral/paw-ubuntu-floral.plymouth   100       manuellt läge
  2            /usr/share/plymouth/themes/ubuntu-logo/ubuntu-logo.plymouth               100       manuellt läge

Tryck  för att behålla nuvarande val[*], eller ange urvalsnummer: 1       
update-alternatives: använder /usr/share/plymouth/themes/Paw-Ubuntu-Floral/paw-ubuntu-floral.plymouth för att tillhandahålla /usr/share/plymouth/themes/default.plymouth (default.plymouth) i manuellt läge

$ sudo update-initramfs -u
update-initramfs: Generating /boot/initrd.img-4.15.0-46-generic

If you receive the following error, you probably didn’t verify the file name of the script, like I suggested in the section above:

W: plymouth module (/usr/lib/x86_64-linux-gnu/plymouth//.so) missing, skipping that theme.

If so, go back and change the name of the script and restart this entire process over from the beginning. (Yes, I know, which is why I cautioned you about it, before…)

Alright, assuming all went well, all you need to do, now, is to reboot and you’ll see your newfound plymouth theme when you’re prompted to input your credentials for the disk’s encryption.

Thanks for coming to this NERDTalk‚ĄĘ and happy Ubuntuing!

C++: Learning About Virtual Classes

Over the weekend, I was given something to learn for a potential job (in Sverige) and that was Virtual Classes in C++. If you’re familiar with Partial Classes the idea kind of related, only¬†it’s better. I’m sure how much of a pain it will be to debug but that’s the next thing that I want to test.

Anyways, Virtual Classes work off of inheritence and just like inheritence, you’re “wrapping” one object around another¬†but with virtual classes, the exposure is seemless.

Take these two classes for a principle example:

#include iostream
#include cstring // Replacing the old and busted with the new hotness.

class LabEquipment
{
    public:
        explicit LabEquipment(int number)
        {
            std::cout << "Lab Equipment: " << number << "\n";
        }

        virtual void LabWrite(std::string message)
        {
            std::cout << "Writing " << message << " from LabEquipment.\n";
        }
};

class Tubes : virtual public LabEquipment
{
    public:
        Tubes(int tubes, int number)
                : LabEquipment(number)
        {
            std::cout << "Tubes: " << tubes << "\n";
        }

        virtual void TubesWrite(std::string tubesMessage)
        {
            std::cout << "Writing " << tubesMessage.c_str() << " from Tubes.\n";
        }
};

I can then write the following to leverage both Tubes and LabEquipments classes:

// Object
Tubes tubes(2, 3);
tubes.TubesWrite("hello");
tubes.LabWrite("hello, again, ");

// Pointer
Tubes * pTubes = new Tubes(3,4);
pTubes->TubesWrite("hello");
pTubes->LabWrite("hello, again,");

If I debug this in CLion (on Ubuntu 18.04LTS), then I get what I would expect:

Lab Equipment: 3
Tubes: 2
Writing hello from Tubes.
Writing hello, again,  from LabEquipment.
Lab Equipment: 4
Tubes: 3
Writing hello from Tubes.
Writing hello, again, from LabEquipment.

Note that I didn’t¬†have to do anything else but declare the class’ inheritence for the methods to be exposed. None of that¬†this stuff is necessary for it for it to be exposed, as it’s purely abstracted from the child to the parent.

In this way, C++ affords more versatility that .NET, in that, if I¬†truly need to change any part of a class, there needn’t be any further changes – save on the caller.

Now, suppose that I declare the same method twice:

class ShowMessage
{
    public:
        explicit ShowMessage{};
    
        void virtual OutMessage(std::string message)
        {
            std::cout << "Writing " << message << " from WriteMessage.";
        }
};

class DisplayMessage : virtual public ShowMessage
{
    public:
        DisplayMessage()
                : ShowMessage()
        {};
        
        void OutMessage(std::string message)
        {
            std::cout << "Writing " << message << " from DisplayMessage";
        }
};

Our compiler, if it’s anything worwhile, should immediately alert us that we hiding the method; which, in this case, happens.

Markering_027

The IDE telling us that we’ve errored and suggesting ways to fix it.

If we override the method we can just drive on, as if nothing ever happened. We can also delete the method in DisplayMessage (which is what we should really do, as it’s redundant code already accomplished from within the ShowMessage class).

Now, let’s suppose we look at properties. Here’s a basic set of classes with int properties:

class FirstCount
{
    public:
        int Forsta;

    public:
        explicit FirstCount(int count)
        {
            Forsta = count;
        };
};

class SecondCount : virtual public FirstCount
{
    public:
        int Andra;

    public:
        SecondCount(int secondCount, int firstCount)
                : FirstCount(firstCount)
        {
            Andra = secondCount + Forsta;
        };
};

We can then construct an object that references them.

SecondCount secondCount(240, 547);
int first = secondCount.Forsta;
int second = secondCount.Andra;

When we debug, we can see that the value is what we’d expect (without having to have had used¬†this).

Markering_028

You can see that the vlaue for second/Andra is the sum of 240 and 547, the 547 having been passed through from the FirstCount class.

…And that’s about as far as I’ve gotten, really… There’s a whole diamond thing that we could get into but I can’t be arsed to get¬†that complicated with it, yet.

Anyways, thanks for coming to this NERDTalk‚ĄĘ and happy programming!