Saturday, 15 September 2018

Web Tutorial: Nike Meme Generator

In 2016, quarterback Colin Kaepernick made waves when he opted to take a knee while the United States national anthem was being played before the start of NFL games. There were some who felt this was disrespectful, though, coming from a country where you can literally wear the flag next to your crotch, I'm really not seeing the problem.

Others saw it as a brave protest against racial injustice. I may be overly cynical here, but all I saw was an aging athlete trying his darnedest to stay relevant. Still... good-looking guy. Great shoulders. Build to die for. And the dramatic shots of him bravely enduring the jeers and abuse to "stand up for his beliefs" sure didn't hurt the narrative.

Fast forward to 2018, and Kaepernick has been made the new face of Nike, ostensibly because they were interested in his message. Methinks they were a wee bit more interested in milking the controversy surrounding Kaepernick and turning it into cash, but anyways. The first ad to be displayed was this.


Conservatives started losing their shit, but I'm not gonna go into that black hole of inanity. Suffice to say, a whole new wave of spoofed memes have been made off this. Brilliant, I say. Brilliant!



Therefore, today, I'll walk you through how to make your very own Nike Meme Generator!

What you'll need

This will be done in PHP (cue the groans from purist snobs. Bite me, dipshits.) and you'll need an Apache server to run your code. First, create a folder called uploads and put this picture of Kaepernick in there. It'll be called, quite appropriately, colinkaepernick.jpg.



Then create index.php in the main folder. And place this tiny white Nike swoosh in the main folder as well, and call it... nikelogo.png? It has a transparent background, and we're going to need that transparency.


You may want to refer to a previous web tutorial, The Asynchronous File Upload, also done in PHP. We'll be copying a fair bit of code from the repository.

Let's Begin!

This is the HTML we start with.
<!DOCTYPE html>
<html>
    <head>
        <title>Nike Meme Generator</title>

        <style>

        </style>
    </head>

    <body>

    </body>
</html>


In the body, we have three divs, ids pnlMessage, formContainer and memeContainer. pnlMessage is meant to provide user feedback (sucess or failure) while formContainer will contain the controls. memeContainer will contain the resulting meme!
<!DOCTYPE html>
<html>
    <head>
        <title>Nike Meme Generator</title>

        <style>

        </style>
    </head>

    <body>
                <div id="pnlMessage"></div>

                <div id="formContainer">

                </div>

                <div id="memeContainer">

                </div>
    </body>
</html>


Got all that? Good. Now here's some styling.

pnlMessage will take up the top. Its text will be red, it will take up the entire screen's width, and have a height of 50 pixels.

formContainer will have its width, but not height, specified. I've given it and memeContainer widths, paddings and margins, and the float property of left.

Not to mention a grey outline for all three divs so you can visualize what we're doing here.

memeContainer's width and height will be equal to each other, because it's square.
<!DOCTYPE html>
<html>
    <head>
        <title>Nike Meme Generator</title>

        <style>
            #pnlMessage
            {
                width: 100%;
                height: 50px;
                color: #FF0000;
                outline: 1px solid #DDDDDD;
            }

            #formContainer
            {
                width: 400px;
                padding: 5px;
                margin: 5px;
                float: left;
                outline: 1px solid #DDDDDD;
            }

            #memeContainer
            {
                width: 500px;
                height: 500px;
                padding: 5px;
                margin: 5px;
                float: left;   
                outline: 1px solid #DDDDDD;
            }
        </style>
    </head>

    <body>
                <div id="pnlMessage"></div>

                <div id="formContainer">

                </div>

                <div id="memeContainer">

                </div>
    </body>
</html>


Looking right? Now you have a good idea where everything is going to be.


Now do this so that only the outline remains for memeContainer. The other divs don't need it.
            #pnlMessage
            {
                width: 100%;
                height: 50px;
                color: #FF0000;
                outline: 0px solid #DDDDDD;
            }

            #formContainer
            {
                width: 400px;
                padding: 5px;
                margin: 5px;
                float: left;
                outline: 0px solid #DDDDDD;
            }

            #memeContainer
            {
                width: 500px;
                height: 500px;
                padding: 5px;
                margin: 5px;
                float: left;   
                outline: 1px solid #DDDDDD;
            }


Now, within formContainer, we'll have a form tag. It points to this page itself, and the enctype attribute needs to be set to "multipart/form-data" because we're using the form to upload an image file. We have three text boxes (for the first and second line of the meme, and the Nike slogan), a file input object, and a submit button. And of course, their respective labels.

As per The Asynchronous File Upload web tutorial, there's also a hidden field, id hidUploadSize, that will be used to restrict the size of the file being uploaded. Not absolutely necessary, but I'm paranoid like that.
        <div id="formContainer">          
            <form id="frmUpload" name="frmUpload" action="" method="POST" enctype="multipart/form-data">
                <label for="flUpload">File</label>
                <input type="file" name="flUpload" id="flUpload">
                <input type="hidden" name="hidUploadSize" id="hidUploadSize" value="50000000">
                <br /><br />
                   <label for="txtLine1">Line 1</label>
                <input name="txtLine1" id="txtLine1" maxlength="50" value="" />
                <br /><br />
                   <label for="txtLine2">Line 2</label>
                <input name="txtLine2" id="txtLine2" maxlength="50" value="" />
                <br /><br />
                <label for="txtSlogan">Slogan</label>
               <input name="txtSlogan" id="txtSlogan" maxlength="20" value="" />
               <br /><br />
               <input type="submit" name="btSubmit" id="btSubmit" value="Create your Meme!">
           </form>
        </div>


This is not a very pretty form, but it's functional and that's all we really need.


Now for some PHP!

At the top of the file, before the doctype declaration, declare a PHP block, then the following variables as defaults. So the  default meme will use colinkaepernick.jpg and the default text will be "Believe in something. Even if it means sacrificing everything.", followed by the slogan "Just Do It.". By default, strmessage will be an empty string.
<?php
$filecode = "colinkaepernick";
$filetype = "jpg";
$line1 = "Believe in something.";
$line2 = "Even if it means sacrificing everything.";
$slogan = "Just Do It.";

$strmessage="";
?>

<!DOCTYPE html>


Next, we use an If block to check if a form has been submitted. If so, replace the current values of line1, line2 and slogan with the values POSTed from the form.
$filecode = "colinkaepernick";
$filetype = "jpg";
$line1 = "Believe in something.";
$line2 = "Even if it means sacrificing everything.";
$slogan = "Just Do It.";

$strmessage="";

if (isset($_POST["btSubmit"]))
{
    $line1 = $_POST["txtLine1"];
    $line2 = $_POST["txtLine2"];
    $slogan = $_POST["txtSlogan"];   
}


Then check if there's been a file upload. If not, set an error message to strmessage. line1, line2 and slogan are optional.
if (isset($_POST["btSubmit"]))
{
    $line1 = $_POST["txtLine1"];
    $line2 = $_POST["txtLine2"];
    $slogan = $_POST["txtSlogan"];

    if (basename($_FILES["flUpload"]["name"]) != "")
    {

    }
    else
    {
        $strmessage="No file selected.";
    }   
}


If there has been an upload, verify that the size of the upload doesn't exceed the size you specified in hidUploadSize. I don't want to repeat myself; all these steps can be found in the earlier web tutorial.
if (isset($_POST["btSubmit"]))
{
    $line1 = $_POST["txtLine1"];
    $line2 = $_POST["txtLine2"];
    $slogan = $_POST["txtSlogan"];

    if (basename($_FILES["flUpload"]["name"]) != "")
    {
        $uploadsize = intval($_POST["hidUploadSize"]);
        $filetype = pathinfo($_FILES["flUpload"]["name"],PATHINFO_EXTENSION);
        $filetype = strtolower($filetype);

        if ($_FILES["flUpload"]["size"] > $uploadsize)
        {
                $strmessage = "Error was encountered while uploading file. File cannot exceed " . ($uploadsize/1000) . "kb";
        }
        else
        {

        }
    }
    else
    {
        $strmessage="No file selected.";
    }   
}


The next step, however, is not in the previous web tutorial. Here, we check if the file uploaded is a valid image file. If not, we set the value of strmessage to an error message.

How, exactly, do we check if it's a valid image file? We certainly can't simply go by the extension. That's one of the easiest things to fake. So what we do, is use the getimagesize() function in PHP. Pass in the temporary filepath from the $_FILES["flUpload"] array. If the file is an image, the function should return you an array. Thus, if we use the is_array() function on the result and it comes back false, the uploaded file is not an image file.
if (isset($_POST["btSubmit"]))
{
    $line1 = $_POST["txtLine1"];
    $line2 = $_POST["txtLine2"];
    $slogan = $_POST["txtSlogan"];

    if (basename($_FILES["flUpload"]["name"]) != "")
    {
        $uploadsize = intval($_POST["hidUploadSize"]);
        $filetype = pathinfo($_FILES["flUpload"]["name"],PATHINFO_EXTENSION);
        $filetype = strtolower($filetype);

        if ($_FILES["flUpload"]["size"] > $uploadsize)
        {
                $strmessage = "Error was encountered while uploading file. File cannot exceed " . ($uploadsize/1000) . "kb";
        }
        else
        {
            if (!is_array(getimagesize($_FILES["flUpload"]["tmp_name"])))
            {
                $strmessage = "File type invalid";
            }
            else
            {
   
            }
        }
    }
    else
    {
        $strmessage="No file selected.";
    }   
}


And at this point, you upload the file.
if (isset($_POST["btSubmit"]))
{
    $line1 = $_POST["txtLine1"];
    $line2 = $_POST["txtLine2"];
    $slogan = $_POST["txtSlogan"];

    if (basename($_FILES["flUpload"]["name"]) != "")
    {
        $uploadsize = intval($_POST["hidUploadSize"]);
        $filetype = pathinfo($_FILES["flUpload"]["name"],PATHINFO_EXTENSION);
        $filetype = strtolower($filetype);

        if ($_FILES["flUpload"]["size"] > $uploadsize)
        {
                $strmessage = "Error was encountered while uploading file. File cannot exceed " . ($uploadsize/1000) . "kb";
        }
        else
        {
            if (!is_array(getimagesize($_FILES["flUpload"]["tmp_name"])))
            {
                $strmessage = "File type invalid";
            }
            else
            {
                $filecode=strtotime("now").rand();
               
                if (move_uploaded_file($_FILES["flUpload"]["tmp_name"], "uploads/" . $filecode . "." . $filetype))
                {
                       $strmessage = "File uploaded.";
                }
                else
                {
                       $strmessage = "Error was encountered while uploading file.";
                }
            }
        }
    }
    else
    {
        $strmessage="No file selected.";
    }   
}


Alter the HTML to show the variable strmessage.
<div id="pnlMessage"><?php echo $strmessage; ?></div>


Try uploading invalid files, or files that are too big. In this example, I tried to upload a PDF.


And after that, let's add the default variables into the form. Just for the users' convenience.
            <form id="frmUpload" name="frmUpload" action="" method="POST" enctype="multipart/form-data">
                <label for="flUpload">File</label>
                <input type="file" name="flUpload" id="flUpload">
                <input type="hidden" name="hidUploadSize" id="hidUploadSize" value="50000000">
                <br /><br />
                   <label for="txtLine1">Line 1</label>
                <input name="txtLine1" id="txtLine1" maxlength="50" value="<?php echo $line1; ?>" />
                <br /><br />
                   <label for="txtLine2">Line 2</label>
                <input name="txtLine2" id="txtLine2" maxlength="50" value="<?php echo $line2; ?>" />
                <br /><br />
                <label for="txtSlogan">Slogan</label>
               <input name="txtSlogan" id="txtSlogan" maxlength="20" value="<?php echo $slogan; ?>" />
               <br /><br />
               <input type="submit" name="btSubmit" id="btSubmit" value="Create your Meme!">
           </form>




Let's modify the CSS a bit. The memeContainer div needs to have a background image specified, and in this case, we use colinkaepernick.jpg as a default (that's what filecode and filetype are set to). Make sure it covers the entire square by setting background-size to cover. Do whatever you want with the font, but I'd recommend white. The filter property is important here. It shows images in greyscale.
            #memeContainer
            {
                width: 500px;
                height: 500px;
                padding: 5px;
                margin: 5px;
                float: left;
                outline: 1px solid #DDDDDD;
                background: url(<?php echo "uploads/" . $filecode . "." . $filetype; ?>) center center no-repeat;
                background-size: cover;
                font-family: georgia;
                color: #FFFFFF;
                font-size: 25px;
                -webkit-filter: grayscale(100%);
                filter: grayscale(100%);
                text-align: center;
            }


Oooh.


Now, for the text within the meme, I can't be arsed to create a new CSS class for this, so I'll just go with two paragraph tags, one of which is set in the middle of the box, and the other at the bottom. The first paragraph will display line1 and line2. The second paragraph will display the Nike swoosh and the string slogan.
        <div id="memeContainer">
            <p style="margin-top:50%"><?php echo $line1;?><br /><?php echo $line2;?></p>
            <p style="margin-top:30%"><img src="nikelogo.png"> <?php echo $slogan;?></p>
        </div>


There's your meme! Well, the default anyway.


Let's try something here... well now we have a Serena Williams meme! If you're wondering if I'm mocking her for her recent display at the US Open... yes, I really fucking am.


One last thing...

Let's add a bit of CSS so we can print. formContainer and pnlMessage will be totally invisible, while memeContainer will have the float property set to none, and then aligned center of the screen.
            #memeContainer
            {
                width: 500px;
                height: 500px;
                padding: 5px;
                margin: 5px;
                float: left;
                outline: 1px solid #DDDDDD;
                background: url(<?php echo "uploads/" . $filecode . "." . $filetype; ?>) center center no-repeat;
                background-size: cover;
                font-family: georgia;
                color: #FFFFFF;
                font-size: 25px;
                -webkit-filter: grayscale(100%);
                filter: grayscale(100%);
                text-align: center;
            }

            @media print
            {
                #formContainer, #pnlMessage
                {
                    display: none;
                }

                #memeContainer
                {
                    margin: 10% auto 0 auto;
                    float: none;
                }
            }


Do a Ctrl-P. Beautiful, isn't it.


Last words...

Well, I certainly enjoyed myself. Remember to sanitize your inputs (I didn't do it here because it's out of scope) to prevent a nasty XSS attack. And... have fun. Go crazy.

#justdoit
T___T

Tuesday, 11 September 2018

Web Tutorial: The FizzBuzz Solution

Following my piece on FizzBuzz last month, I thought it would be fun (see what my idea of fun is? Man, I'm such a geek) to walk you through the painfully simple process of a FizzBuzz program. Of course, the program is simple enough - what's really important is understanding the process.

To make it even more fun, I'm going to do it in Ruby. Because... well, why not?

First, at the risk of sounding repetitive, let's look at the program specs again.
Write a program that prints the numbers from 1 to 100. But for multiple of three print "Fizz" instead of the number and for the multiples of five print "Buzz". For numbers which are multiples of both three and five print "FizzBuzz".


So, it sounds like this requires some kind of For loop. But let's keep this small, say, 20 instead of 100.
for i in 1..20

end


By default, we print out the number.
for i in 1..20
    puts i
end


And here we are.


Now, this is hardly optimal. We are going to have some conditionals in between. So since the default is printing out the number, let's first create a variable, output, and assign the value of i to it. Then print out output. This will still give you the same output, but your code is more extensible now.
for i in 1..20
    output = i

    puts output
end


Here's the first condition. If the Modulus of i/3 is 0, which means that i is divisible by 3, the value of output is "Fizz".
for i in 1..20
    output = i

    if i % 3 == 0
        output = "Fizz"
    end

    puts output
end


Yep. Seems to be working!


And if i is divisible by 5, the value of output is "Buzz".
for i in 1..20
    output = i

    if i % 3 == 0
        output = "Fizz"
    end

    if i % 5 == 0
        output = "Buzz"
    end

    puts output
end


Getting closer...


Now for the grand slam! If i is divisible by both 3 and 5, the value of output is "FizzBuzz".
for i in 1..20
    output = i
   
    if i % 3 == 0
        output = "Fizz"
    end

    if i % 5 == 0
        output = "Buzz"
    end

    if (i % 3 == 0 and i % 5 == 0)
        output = "FizzBuzz"
    end

    puts output
end


Great. It works. Just one more thing...


Make the program loop 100 times instead of 20.
for i in 1..100
    output = i
   
    if i % 3 == 0
        output = "Fizz"
    end

    if i % 5 == 0
        output = "Buzz"
    end

    if (i % 3 == 0 and i % 5 == 0)
        output = "FizzBuzz"
    end

    puts output
end


Mission accomplished!


Final notes

Yes, it really was a simple piece of work. And does nothing useful at all.

As mentioned, FizzBuzz is really just a way to ensure that a programming candidate understands how to use loops, conditionals and the Modulus operator. We did it in Ruby, but it really could have been done in any programming language.

puts "Bye!"
T___T

Saturday, 8 September 2018

Online Lynch Mob Activated!

It's all over the Internet and Social Media. A group of five - historian PJ Thum, activists Jolovan Wham and Kirsten Han, cartoonist Sonny Liew and former Singapore citizen Tan Wah Piow - headed out to meet Tun Dr Mahathir bin Mohamad, Prime Minister of Malaysia, for a chat about democracy, gay rights and all that jazz. PJ Thum posted a photo of him and Dr M on Facebook, urging him to "take leadership in South-east Asia for the promotion of democracy, human rights, freedom of expression and freedom of information". Considering Dr M's unfriendly attitude towards Singapore, both past and present, this looked suspiciously like a middle finger from Thum cast in the general direction of Singapore's ruling party, the People's Action Party (PAP).

The photo in question.

PAP MP Mr Seah Kian Peng responded with an insinuation that Thum harbored ill intentions for Singapore, and threw some shade about why the other two (Jolovan Wham and Kirsten Han) were associating with such a malcontent. Within a day, the Internet was up in arms with cries of "treason" echoing through Facebook. And from there, things started getting messy. Instead of shutting the hell up like a good boy, Jolovan Wham chose to double down with this decidedly defiant response.

The thing is, treason involves heinous acts like selling state secrets or helping outsiders to overthrow the Government... things that none of them are in any position to do even if that had been their intent. And if one wishes to argue that their intent was treasonous, I'm pretty sure openly committing treason and posting the evidence on Facebook goes against all conventional logic.

Now, all of this is Singapore politics. Ill-advised as I think the antics of the five were, this is a tech blog and I'll leave dissection of their actions to more political minds. What I would like to focus on, are the actions of Mr Seah Kian Peng in this entire debacle. Because this concerns the Internet, and all the riff-raff that go with it. I speak today, not as a fanboy of either side (I'm far too busy being awesome to be any kind of fanboy, period) but as a concerned citizen. And as a web developer, surprise, surprise, I happen to know a thing or two about the Internet.

When Mr Seah accused Thum  - and Kirsten Han and Jolovan Wham by association - of harboring ill intentions, people jumped on the bandwagon. There were cyber screams of righteous outrage, a great deal of chest-thumping, name-calling and accusations of treason (yes, there's that word again), capital punishment and stripping of citizenship. Kirsten Han reported that death threats had been made against her and Jolovan Wham. Mr Seah then put up a statement.

"Whilst we have different points of views, I call on all to maintain a certain decorum in our comments and we should not get personal or abusive. We can all agree to disagree and be civil about it. It is regretful that I see all kinds of abusive remarks that are made by many different individuals (and trolls) against each other. I do not support such types of comments, regardless of what views or positions they take."

On the surface, it was a nice gesture. Gentlemanly speech. Hit all the right notes and even managed to sound sincere. Unfortunately, it was a case of too little, too late. It amounted to a mild admonishment, coupled with an attempt to distance himself from the extremists among the PAP fan club. The damage had been done. He had stirred up an online lynch mob which was baying for blood, and now that he had publicly distanced himself from the unpleasantness, this gave them carte blanche to do as they pleased without fear of implicating the PAP. Arguably, it made things worse, not better.

A mob.

OK, maybe that's just a wee bit too cynical. I'm going to give Mr Seah the benefit of the doubt and assume he wasn't doing this deliberately. The situation simply got away from him. That would be adequate mitigation in most cases... except that Mr Seah is both a Member of Parliament and member of the Select Committee on Deliberate Online Falsehoods, a position which, one might say, requires a certain amount of savvy with the Internet. And that makes this entire situation unacceptable. As a public figure, one has to take responsibility for the impact of his words uttered in public, especially when these words stir up such furor.

It's not enough to say he didn't know better, because a man in his position should know better.

Instead of merely saying he did "not support such types of comments", I submit that he should have gone a step further and warned his audience that he neither condones nor tolerates Hate Speech, and that such would be investigated by the police regardless of whose side they're on. Because, you know, some people are awfully brave when they think there are no consequences for their words.

Final Thoughts

To be clear, I'm not worried about the clowns who are screaming self-aggrandizing rubbish like "if I was there, I would punch that traitor's face". All this is hot air and faux-patriotic bluster, nothing more. This is Singapore, and as much as I love her, she's filled with chickenshit keyboard warriors who talk a good game behind a computer screen but totally lose their nerve when their bluff is called.

No, I'm more concerned about the ones who are getting quietly stirred up. You'll never see them coming.


Remember Amos Yee in 2015? There was some loser who came out of nowhere and slapped Amos Yee while he was exiting the courtroom. He didn't post on Facebook and say "I'm gonna slap that punk". No, he just came right out and did it. Substitute "slap" with something more violent, like "stab", and Amos Yee's name with any of the three currently under fire - PJ Thum, Kirsten Han or Jolovan Wham - and you see how we might have a problem.

Is Mr Seah going to take responsibility for something like this? Someone has to. Like it or not, this is 2018, and this is the Internet. If this gets out of hand, perhaps we need more capable hands.

You see, I have shockingly low moral standards for leaders of my country. They don't have to be of sterling character - they can be utterly annoying, perverts or even ruthless bastards. But what I cannot - will not - condone, is incompetence. That's a hard, non-negotiable line. And if this was a misstep by Mr Seah, it's not quite gross incompetence, but it's close. On the other hand, if Mr Seah had engineered and intended this outcome, I can only say - congratulations and well-played, Sir. I approve.

That's all from me. Heading out for lynch... I mean, lunch!
T___T

Wednesday, 5 September 2018

Five Examples of Terribly Useless Commit Remarks

The ability to work in a team is an oft-understated part of a developer's skillset. Sure, being able to write good working code is always well-received. But being able to collaborate with others is one of the major things a developer is judged on.

Committing changesets to a code repository is one of the ways a developer collaborates with others. And to do that well, at the very minimum, one needs to understand the art of writing useful commit remarks. That's a subject worth investing some time in to study, but for today, let's examine some of the most God-awful useless commit remarks I've ever had the misfortune of encountering. I've categorized them into five groups, not necessarily in order of futility.

1. The Mysterious

Invisible.

Changeset By Time Remarks
11332667 Ms Mysterious 31 July 2018, 15:03:14 Details
11332668 Ms Mysterious 31 July 2018, 15:35:24 Details
11332669 Ms Mysterious 31 July 2018, 16:12:11 Details

Do you see the problem with the commit remarks? No? That's because there are no remarks. Meaning, we have no clue what the commit was for and actually have to delve into the code to make sense of of the why and what.

2. The Nonsensical

Crazy randomness

Changeset By Time Remarks
98090 Nonsensical Jr. 18 August 2018, 09:39:16 Details xyz
98091 Nonsensical Jr. 18 August 2018, 09:42:55 Details abc123
98092 Nonsensical Jr. 18 August 2018, 09:55:21 Details 55555
98093 Nonsensical Jr. 18 August 2018, 13:23:22 Details 454tdfddfhfghhf

Now, there are commit messages. The only problem is, they're not in English. Or any other language you might know. Hell, they're not even in binary! This normally happens when commit messages are mandated at configuration level. The developer can't commit unless he writes a commit remark... any remark. So to fulfill these requirements, they type some random keyboard sequence and click Save. Good for them... though this is probably worse than no message. Having no message is neutral. This is open contempt.

3. The Vague

Nothing solid.

Changeset By Time Remarks
113342667 Mr Vague 15 January 2018, 10:12:22 Details fixbug
113342668 Mr Vague 15 January 2018, 11:10:55 Details fixed bugs
113342669 Mr Vague 15 January 2018, 12:21:40 Details fixes

These irritate me the hardest. This is not some random sequence - it's actually readable (kind of) English. The only problem is, they say absolutely nothing. What in the loving heck is "fixbug", or any of the other permutations? Is the Mr Vague trying to say he fixed a bug? Exactly which bug? Did this provide any useful information, or at least more useful information than if he had not even bothered to leave remarks? Technically, yes. But only marginally. This basically screams, I have nothing useful to say, but I wanna say something just for the sake of saying something.

4. The Redundant

Really damn extra.

Changeset By Time Remarks
5566732 Mdm Redundant 9 March 2018, 23:21:09 Details 45178
5566733 Mdm Redundant 10 March 2018, 09:09:55 Details 45222
5566734 Mdm Redundant 10 March 2018, 11:58:29 Details 45232
5566734 Mdm Redundant 11 March 2018, 11:18:11 Details Mdm Redundant
5566734 Mdm Redundant 12 March 2018, 16:09:03 Details Mdm Redundant

These comments aren't random numbers. No, they're the ticket IDs for which the changesets are intended to fulfill. Are these useful? They might be... if not for the fact that these details are available anyway if you click on the Details link. So they save you a click... at the expense of more pertinent information. Better than no comments? Maybe. But not by much. (OK, I'm being kind. They're still utterly useless.) And in the last two commits, Mdm Redundant went one better... she simply left her name. Genius.

5. The Accusatory

It's all your fault!

Changeset By Time Remarks
103998 Sir Accusatory 30 May 2018, 12:18:49 Details The foreign id was not configured correctly. In my opinion, this would have been avoided if we had gone with denormalization of specific structures, as I recommended, instead of relying on foreign keys for verification of everything.

The first sentence was somewhat useful. The rest of it was smug, petulant and totally unnecessary. Even just "recommend denormalization of specific structures" would be preferred. This is at least neutral. Remember, when you piss people off with your remarks, half of your message is lost. This message started out as something useful. Unfortunately it got lost by the fact that the Sir Accusatory wasn't trying to be helpful, and was just trying to throw shade at the other developers.  Very unprofessional. Don't do this!

Are these commit remarks really all that useless?

Well, nothing's completely useless. If the company needed to assess the competency of their staff, this would be one of the easiest and obvious metrics. Seriously, you don't need to be a programming genius to know that these commit remarks are crap. It's more a matter of common sense.

Commit remarks are supposed to help, not hinder. When they say "soft skills are important", they don't mean software skills (though those are still important!), but rather, communication. If you are going to work in a team, you need to make your work easy to follow.

fixbug,
T___T

Tuesday, 28 August 2018

A look at User Authentication Factors (Part 2/2)

An authentication system is made out of authentication factors. There may be multiple factors, but whether a system is Single-factor Authentication, Two-factor Authentication (2FA) or Three-factor Authentication (3FA), depends on the number of different authentication factor types. For example, a simple Login screen is Single-factor authentication, even though the user has to key in both a login id and a password.

Instagram login screen.
Why? There are two authentication factors. But both of them are the same authentication type - Knowledge. That means there is only one authentication factor type in play. Even if you had to key in five passwords to be allowed entry, that would still be Single-factor Authentication.

Examples of Single-factor Authentication

As previously stated, a typical login screen is Single-factor Authentication. So is any type of system that only uses one authentication factor type.

ActiveSG gantry.
Like the gantries in ActiveSG swimming complexes. You scan your NRIC (a Possession authentication factor type), and it opens up.

Unlocking your mobile phone can be done via thumbprint scan (Inherence), facial recognition (Inherence) or a PIN (Knowledge). That's Single-factor Authentication.

Examples of Two-factor Authentication (2FA)

As mentioned previously, using your SingPass is 2FA. You key in your login id and password (Knowledge), then the systems sends an OTP to your mobile phone (Possession) for you to continue the login process.

Automatic Teller Machine.
Using an Automated Teller Machine (ATM) requires you to have your ATM card (Possession) and your PIN number (Knowledge).

The gantries in Changi Airport (all terminals) are 2FA. First, you scan your passport (Possession) and then your thumbprint (Inherence).

Examples of Three-factor Authentication (3FA)

There are virtually no examples of 3FA on websites. Biometrics are all but impossible right now on browsers. (CAPTCHA doesn't count because while it does - kind of - verify that you're not a bot, it can't verify that you're you.) Therefore, we're limited to only two authentication factor types - Knowledge and Possession.

Hi-tech security.

However, advanced security systems might require an electronic pass, a biometric scan and a passcode. That would qualify as 3FA.

That's all...

I just really wanted to explain 2FA. This might be a little more information than required. Hope this was interesting enough!

Thanks for tuning in! I had a scan-dalously good time.
T___T