Thursday, 27 December 2018

Spot The Bug: Fixing the ToFixed

Hey guys. It's the final week of 2018 and we're back for some bug-hunting in Spot The Bug.

I spy a bug with
my little eye...

Now, as much as I like to claim that vanilla JavaScript is my bread and butter, there are times when I make some glaring screw-ups. The simpler, the more glaring. Today is just one such example.

See, there was this time I had to tally some kind of report for goods sold, and sum the entire thing up at the bottom. Simple enough, right? So I had it on a webpage, inside a table. The calculations were correct. I'm omitting the code I used to display.

        gst = (grossSales * 0.07);
        sales = (grossSales * 0.93);

        total = sales + gst;

        document.getElementById("lblSales").innerHTML = sales;
        document.getElementById("lblGst").innerHTML = gst;
        document.getElementById("lblTotal").innerHTML = total;   




And here it was! But because I had to tally 7% Goods and Service Tax (GST), inevitably there was some very long numbers. I was requested to trim it down to two decimal places. No problem. I used to toFixed() method and got it done. I also did it for the value of the variable sales.

Holy hell... the GST was correct, but now the total was one horrible mess.



What went wrong

This thankfully did not take long to figure out. The problem was right where I used to toFixed() method. I mean, duh. Everything was peachy before using the toFixed() method, right?

        gst = (grossSales * 0.07).toFixed(2);
        sales = (grossSales * 0.93).toFixed(2);

        total = sales + gst;

        document.getElementById("lblSales").innerHTML = sales;
        document.getElementById("lblGst").innerHTML = gst;
        document.getElementById("lblTotal").innerHTML = total;   


Here's some info on the toFixed() method if you're interested.

Why it went wrong

See, the problem is that the toFixed() method returns a string. Not a number, but a string. And therefore, if we use the "+" operator with a string in JavaScript, the system assumes that you want a string concatenation! So "52182.30" joined with "3927.70" became "52182.303927.70"!

How I fixed it

I used the parseFloat() function in the final calculation, turning the string back into a decimal number, and the calculation was correct! Admittedly, while the solution was simple, I'd actually recommend being more thorough and repeating this with all the numbers just so you don't get any unpleasant surprises if any of the numbers in the equation needs to be changed.

        gst = (grossSales * 0.07).toFixed(2);
        sales = (grossSales * 0.93).toFixed(2);

        total = (parseFloat(sales) + parseFloat(gst)).toFixed(2);

        document.getElementById("lblSales").innerHTML = sales;
        document.getElementById("lblGst").innerHTML = gst;
        document.getElementById("lblTotal").innerHTML = total;


There, everything was peachy now.


Conclusion

There's a larger lesson to be learned here. When using any kind of method or function, always be mindful of what data type the output is in.

Guess that's less one bug toFix,
T___T

Sunday, 23 December 2018

Web Tutorial: A Christmas Letter from the CEO.

Hey guys... and Merry Christmas!

Years ago, I worked in a company where the CEO had this endearing habit of drafting pompous emails during festive seasons to wish us happy-whatever-holidays and pontificate on the meaning of the festival itself. Chinese New Year, Easter, and yes, Christmas. Most of us barely even looked, though some might draft a thank-you email out of courtesy. Some went the extra mile and even read through it.

Well, you know, it takes all sorts.

So one Christmas, I had this idea. If I was going to receive yet another CEO festive letter, I might as well make something of it. I made a nice web template to place the contents of the letter, and even made the background change when the user scrolled. Because it's a really long, rambling message, see? Before I could pitch this, however, shit happened and I was no longer working at the company.

Still, there's no sense in letting a perfectly good idea go to waste, so, let's have at it!

Start with a basic HTML setup.
<!DOCTYPE html>
<html>
    <head>
        <title>A Letter From the CEO</title>

        <style>

        </style>

        <script>

        </script>
    </head>

    <body>

    </body>
</html>


We'll go ahead and style the body tag first. Setting the margin property to 0 will reset whatever cross-browser properties we need for this web tutorial. The background will be a somewhat pale blue.
        <style>
            body
            {
                margin: 0;
                background-color: #AAAAFF;
            }
        </style>




Back to the HTML, add two divs into the body. Both will have the CSS class container. The first will also be styled using the CSS class background, and the second one, foreground.
    <body>
        <div class="background container">

        </div>   

        <div class="foreground container">

        </div>   
    </body>


Now we add code for those styles. container's position property is absolute and takes up the whole of the screen. background's z-index property is lower than that of foreground's. In essence, we made two divs which lie right on top of each other. But since neither of them have a background color, you won't see any difference just yet.
        <style>
            body
            {
                margin: 0;
                background-color: #AAAAFF;
            }

            .container
            {
                position: absolute;
                left: 0;
                top: 0;
                width: 100%;
                height: 100%;
            }

            .background
            {
                z-index: 10;
            }

            .foreground
            {
                z-index: 20;           
            }
        </style>


The next thing to add is another div within the second div. It will be styled using content.
    <body>
        <div class="background container">

        </div>   

        <div class="foreground container">
            <div class="content">

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


Let's style this. content will take up 40% of screen space. The margin property has been set so that it sits nicely in the middle. We set the background color to white. The padding, text-align and font-face properties are up to you; they don't really affect anything other than the visuals.
            body
            {
                margin: 0;
                background-color: #AAAAFF;
            }

            .container
            {
                position: absolute;
                left: 0;
                top: 0;
                width: 100%;
                height: 100%;
            }

            .content
            {
                width: 40%;
                min-height: 100%;
                margin: 0 auto 0 auto;
                background-color: #FFFFFF;
                padding: 1em;
                text-align: justify;
                font-family: georgia;
            }


And here we have a nice div, ready for content!


OK, let's populate this with content. It's Lorem Ipsum I generated, to simulate the long-ass content.
    <body>
        <div class="background container">

        </div>   

        <div class="foreground container">
            <div class="content">
                <h1>Merry Christmas!</h1>

                <p>
                Dear colleagues,
                </p>

                <p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec lobortis quis risus non cursus. Sed id posuere erat. Donec augue purus, accumsan fermentum neque in, mollis mattis ligula. Sed ornare, risus vel tristique vestibulum, nisl tellus maximus ex, eget tempor ligula turpis eu nibh. Vestibulum vehicula fringilla elit vel viverra. Aenean hendrerit scelerisque sollicitudin. Cras convallis tellus vitae sapien sagittis, et finibus tortor vestibulum. Donec cursus elit ante, ut ultricies elit cursus eu. Suspendisse ac interdum elit. Praesent lorem augue, sodales a urna ut, mollis vehicula nunc. Proin eu viverra lectus. In ut tortor eget nisi vestibulum euismod vitae eu est. Nullam lacinia, lorem eget dictum vehicula, orci felis dapibus nunc, vitae ornare nisi est ut turpis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec vitae tincidunt mauris. Maecenas id luctus velit.
                </p>

                <p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec lobortis quis risus non cursus. Sed id posuere erat. Donec augue purus, accumsan fermentum neque in, mollis mattis ligula. Sed ornare, risus vel tristique vestibulum, nisl tellus maximus ex, eget tempor ligula turpis eu nibh. Vestibulum vehicula fringilla elit vel viverra. Aenean hendrerit scelerisque sollicitudin. Cras convallis tellus vitae sapien sagittis, et finibus tortor vestibulum. Donec cursus elit ante, ut ultricies elit cursus eu. Suspendisse ac interdum elit. Praesent lorem augue, sodales a urna ut, mollis vehicula nunc. Proin eu viverra lectus. In ut tortor eget nisi vestibulum euismod vitae eu est. Nullam lacinia, lorem eget dictum vehicula, orci felis dapibus nunc, vitae ornare nisi est ut turpis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec vitae tincidunt mauris. Maecenas id luctus velit.
                </p>

                <p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec lobortis quis risus non cursus. Sed id posuere erat. Donec augue purus, accumsan fermentum neque in, mollis mattis ligula. Sed ornare, risus vel tristique vestibulum, nisl tellus maximus ex, eget tempor ligula turpis eu nibh. Vestibulum vehicula fringilla elit vel viverra. Aenean hendrerit scelerisque sollicitudin. Cras convallis tellus vitae sapien sagittis, et finibus tortor vestibulum. Donec cursus elit ante, ut ultricies elit cursus eu. Suspendisse ac interdum elit. Praesent lorem augue, sodales a urna ut, mollis vehicula nunc. Proin eu viverra lectus. In ut tortor eget nisi vestibulum euismod vitae eu est. Nullam lacinia, lorem eget dictum vehicula, orci felis dapibus nunc, vitae ornare nisi est ut turpis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec vitae tincidunt mauris. Maecenas id luctus velit.
                </p>

                <p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec lobortis quis risus non cursus. Sed id posuere erat. Donec augue purus, accumsan fermentum neque in, mollis mattis ligula. Sed ornare, risus vel tristique vestibulum, nisl tellus maximus ex, eget tempor ligula turpis eu nibh. Vestibulum vehicula fringilla elit vel viverra. Aenean hendrerit scelerisque sollicitudin. Cras convallis tellus vitae sapien sagittis, et finibus tortor vestibulum. Donec cursus elit ante, ut ultricies elit cursus eu. Suspendisse ac interdum elit. Praesent lorem augue, sodales a urna ut, mollis vehicula nunc. Proin eu viverra lectus. In ut tortor eget nisi vestibulum euismod vitae eu est. Nullam lacinia, lorem eget dictum vehicula, orci felis dapibus nunc, vitae ornare nisi est ut turpis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec vitae tincidunt mauris. Maecenas id luctus velit.
                </p>

                <p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec lobortis quis risus non cursus. Sed id posuere erat. Donec augue purus, accumsan fermentum neque in, mollis mattis ligula. Sed ornare, risus vel tristique vestibulum, nisl tellus maximus ex, eget tempor ligula turpis eu nibh. Vestibulum vehicula fringilla elit vel viverra. Aenean hendrerit scelerisque sollicitudin. Cras convallis tellus vitae sapien sagittis, et finibus tortor vestibulum. Donec cursus elit ante, ut ultricies elit cursus eu. Suspendisse ac interdum elit. Praesent lorem augue, sodales a urna ut, mollis vehicula nunc. Proin eu viverra lectus. In ut tortor eget nisi vestibulum euismod vitae eu est. Nullam lacinia, lorem eget dictum vehicula, orci felis dapibus nunc, vitae ornare nisi est ut turpis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec vitae tincidunt mauris. Maecenas id luctus velit.
                </p>

                <p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec lobortis quis risus non cursus. Sed id posuere erat. Donec augue purus, accumsan fermentum neque in, mollis mattis ligula. Sed ornare, risus vel tristique vestibulum, nisl tellus maximus ex, eget tempor ligula turpis eu nibh. Vestibulum vehicula fringilla elit vel viverra. Aenean hendrerit scelerisque sollicitudin. Cras convallis tellus vitae sapien sagittis, et finibus tortor vestibulum. Donec cursus elit ante, ut ultricies elit cursus eu. Suspendisse ac interdum elit. Praesent lorem augue, sodales a urna ut, mollis vehicula nunc. Proin eu viverra lectus. In ut tortor eget nisi vestibulum euismod vitae eu est. Nullam lacinia, lorem eget dictum vehicula, orci felis dapibus nunc, vitae ornare nisi est ut turpis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec vitae tincidunt mauris. Maecenas id luctus velit.
                </p>

                <p class="signoff">
                Season's blessings,<br />
                Your Chief Executive Officer
                </p>
            </div>   
        </div>   
    </body>


Great. Now we need to scroll to read all of this stuff. But this is where things get interesting...


Let's animate the background!

So my bright idea was to ensure that the background moved each time the user scrolled. But not in a in-your-face kind of way. Something... subtle.

What we do here, is add more divs to the first div. Therefore they will appear behind the Letter from the CEO. Each of these will be styled using the CSS class snowflake. Six of them will be styled using the CSS class left, and the other six using CSS class right.
        <div class="background container">
            <div class="snowflake left"></div>
            <div class="snowflake left"></div>
            <div class="snowflake left"></div>
            <div class="snowflake left"></div>
            <div class="snowflake left"></div>
            <div class="snowflake left"></div>
            <div class="snowflake right"></div>
            <div class="snowflake right"></div>
            <div class="snowflake right"></div>
            <div class="snowflake right"></div>
            <div class="snowflake right"></div>
            <div class="snowflake right"></div>
        </div>


Here's the CSS code for snowflake. There is no CSS code for left or right; that will be handled via JavaScript. So, the position property is set to fixed, which means the div will stay in place even if you scroll. The transform-origin property is set to dead center of the div. We'll need this because we may be rotating the divs later. After this, you still won't see any visible changes to your screen, so don't bother refreshing.
            .foreground
            {
                z-index: 20;           
            }

            .snowflake
            {
                position: fixed;
                -webkit-transform-origin: 50% 50%;
                transform-origin: 50% 50%;
            }

            .content
            {
                width: 40%;
                min-height: 100%;
                margin: 0 auto 0 auto;
                background-color: #FFFFFF;
                padding: 1em;
                text-align: justify;
                font-family: georgia;
            }


Here are some images I looted off this site. They will be stored in the img folder.

snowflake1.png

snowflake2.png

snowflake3.png

Let's write some JavaScript. First, change your body tag to run the initSnowflakes() function upon loading.
<body onload="initSnowflakes()">


Then write the function.
        <script>
            function initSnowflakes()
            {

            }
        </script>


We begin by grabbing all the divs that are styled using the CSS class snowflake, and putting them in an array snowflakes.
        <script>
            function initSnowflakes()
            {
                var snowflakes = document.getElementsByClassName("snowflake");
            }
        </script>


Then we iterate through the snowflakes array...
        <script>
            function initSnowflakes()
            {
                var snowflakes = document.getElementsByClassName("snowflake");

                for (var i = 0; i < snowflakes.length; i++)
                {
           
                }
            }
        </script>


...and change the background of that div to a random image from the img folder! Of course, to do that, you'll need the generateRandomNumber() function. Make sure the backgroundSize property is set to contain; this is gonna be relevant soon.
        <script>
            function initSnowflakes()
            {
                var snowflakes = document.getElementsByClassName("snowflake");

                for (var i = 0; i < snowflakes.length; i++)
                {
                    snowflakes[i].style.background = "url(img/snowflake" + generateRandomNo(1, 3) + ".png) left top no-repeat";
                    snowflakes[i].style.backgroundSize = "contain";           
                }
            }
        </script>


Here, I provided the generateRandomNumber() function for you. Now isn't that nice?
        <script>
            function initSnowflakes()
            {
                var snowflakes = document.getElementsByClassName("snowflake");

                for (var i = 0; i < snowflakes.length; i++)
                {
                    snowflakes[i].style.background = "url(img/snowflake" + generateRandomNo(1, 3) + ".png) left top no-repeat";
                    snowflakes[i].style.backgroundSize = "contain";           
                }
            }

            function generateRandomNo(varmin, varmax)
            {
                return Math.floor((Math.random() * (varmax-varmin+1)) + varmin);
            }
        </script>


You still won't see any results. Not unless you specify the width and height of the divs. For the sake of experimentation, let's set both height and width to 100 pixels.
            function initSnowflakes()
            {
                var snowflakes = document.getElementsByClassName("snowflake");

                for (var i = 0; i < snowflakes.length; i++)
                {
                    snowflakes[i].style.background = "url(img/snowflake" + generateRandomNo(1, 3) + ".png) left top no-repeat"
                    snowflakes[i].style.backgroundSize = "contain";
                    snowflakes[i].style.width = "100px";
                    snowflakes[i].style.height = "100px";               
                }
            }


Check out the result now... you see the top left hand corner? It's all twelve divs, now cluster-fucking there because the left and top properties have not been specified. But they're big enough that you can see them!


OK, now comment out the last two lines. Those were just to show you stuff. At the end of the function, make a call to the transitSnowflakes() function. And start creating that function.
            function initSnowflakes()
            {
                var snowflakes = document.getElementsByClassName("snowflake");

                for (var i = 0; i < snowflakes.length; i++)
                {
                    snowflakes[i].style.background = "url(img/snowflake" + generateRandomNo(1, 3) + ".png) left top no-repeat"
                    snowflakes[i].style.backgroundSize = "contain";
                    //snowflakes[i].style.width = "100px";
                    //snowflakes[i].style.height = "100px";               
                }

                transitSnowflakes();
            }

            function transitSnowflakes()
            {

            }


Here, let's do what we did for initSnowflakes(). Get all the divs and put them in the snowflakes array. Then iterate through that array.
            function transitSnowflakes()
            {
                var snowflakes = document.getElementsByClassName("snowflake");

                for (var i = 0; i < snowflakes.length; i++)
                {

                }
            }


If the div is styled using snowflake and left, set the left property to a value between 0 to 5%. If it's styled using snowflake and right, do this for the right property.
            function transitSnowflakes()
            {
                var snowflakes = document.getElementsByClassName("snowflake");

                for (var i = 0; i < snowflakes.length; i++)
                {
                    if (snowflakes[i].className == "snowflake left")
                    {
                        snowflakes[i].style.left = generateRandomNo(0, 5) + "%";
                    }

                    if (snowflakes[i].className == "snowflake right")
                    {
                        snowflakes[i].style.right = generateRandomNo(0, 5) + "%";
                    }
                }
            }


As you can see, some are left of the screen, and some are right! But they're still overlapped. Let's fix that...


We'll generate a value between 0 and 80 % for the top property.
            function transitSnowflakes()
            {
                var snowflakes = document.getElementsByClassName("snowflake");

                for (var i = 0; i < snowflakes.length; i++)
                {
                    snowflakes[i].style.top = generateRandomNo(0, 80) + "%";

                    if (snowflakes[i].className == "snowflake left")
                    {
                        snowflakes[i].style.left = generateRandomNo(0, 5) + "%";
                    }

                    if (snowflakes[i].className == "snowflake right")
                    {
                        snowflakes[i].style.right = generateRandomNo(0, 5) + "%";
                    }
                }
            }


Ah, now we're talking. Randomly scattered snowflakes!


But you'll notice when you scroll, they change positions. That's expected behavior, but the movement's way too jerky, so let's set the transition property to time the movement between 5 to 30 seconds. Now when you refresh the page, see how slowly and gracefully the snowflakes move!
            function transitSnowflakes()
            {
                var snowflakes = document.getElementsByClassName("snowflake");

                for (var i = 0; i < snowflakes.length; i++)
                {
                    snowflakes[i].style.top = generateRandomNo(0, 80) + "%";

                    if (snowflakes[i].className == "snowflake left")
                    {
                        snowflakes[i].style.left = generateRandomNo(0, 5) + "%";
                    }

                    if (snowflakes[i].className == "snowflake right")
                    {
                        snowflakes[i].style.right = generateRandomNo(0, 5) + "%";
                    }

                    snowflakes[i].style.transition = "all " + generateRandomNo(5, 30) + "s";
                    snowflakes[i].style.WebkitTransition = "all " + generateRandomNo(5, 30) + "s";
                }
            }


Let's have some more fun...

Set the width and height properties, then rotate the snowflakes in different directions. And set the opacity randomly too.
            function transitSnowflakes()
            {
                var snowflakes = document.getElementsByClassName("snowflake");

                for (var i = 0; i < snowflakes.length; i++)
                {
                    snowflakes[i].style.width = generateRandomNo(20, 500) + "px";
                    snowflakes[i].style.height = generateRandomNo(20, 500) + "px";
                    snowflakes[i].style.top = generateRandomNo(0, 80) + "%";
                    snowflakes[i].style.transform = "rotate(" + generateRandomNo(-150, 150) + "deg)";
                    snowflakes[i].style.WebkitTransform = "rotate(" + generateRandomNo(-150, 150) + "deg)";   
                    snowflakes[i].style.opacity = "0." + generateRandomNo(1, 5);

                    if (snowflakes[i].className == "snowflake left")
                    {
                        snowflakes[i].style.left = generateRandomNo(0, 5) + "%";
                    }

                    if (snowflakes[i].className == "snowflake right")
                    {
                        snowflakes[i].style.right = generateRandomNo(0, 5) + "%";
                    }

                    snowflakes[i].style.transition = "all " + generateRandomNo(5, 30) + "s";
                    snowflakes[i].style.WebkitTransition = "all " + generateRandomNo(5, 30) + "s";
                }
            }


Great, eh?


One more thing before I go...
Let's style the final signoff with... well, signoff.
                <p class="signoff">
                Season's blessings,<br />
                Your Chief Executive Officer
                </p>


And here's the code. First, we align the text right.
            p.signoff
            {
                text-align: right;
            }


So the text is nicely aligned right, but there's something missing. A signature! We'll use this one. Save it in the img folder. (No, that's not his real signature. And no, I have no clue whose signature this is. Just looted it off a stock photo site.)

signature.jpg

                <p class="signoff">
                    Season's blessings,<br />
                    <img src="img/signature.jpg" height="150"/><br />
                    P. Smith<br />
                    Your Chief Executive Officer
                </p>


And there, we've got a nicely signed letter!


That's it. Merry Christmas once again...

Enjoy your festive season!

Not your CEO,
T___T

Sunday, 16 December 2018

My Year in Training and Assessment (Part 2/2)

The final month of 2017 ended quickly, and the subject matter of the classes was pretty fascinating. We covered different learning profiles and how different people reacted to different methods of information delivery. Looking up the internet and the library, I discovered even more stuff in addition to the reading materials.

My classmates were a fun bunch. Sure, they were mostly older folks and some of them said things I would have found cringe-worthy in another setting. Here, I tried to keep an open mind. The group discussions we were put through were insightful. Most of us tried to be nice to each other because we were depending on each other to get through the course. I soon learned that I got on better with some of the others, and even consulted one of them personally on my upcoming marriage.

Assignments

For the most part, I didn't have a problem digesting whatever information was given. A lot of it seemed to be common sense. When handing in a lesson plan, which was one of our assignments, the instructor even commented that I seemed to be getting the gist of it quite handily, and had nothing further to add. He wasn't just saying that, because he had a lot to say when others were handing in their lesson plans. On my part, I was just glad that I seemed to be on the right track.

We also had to keep a learning journal of sorts, detailing what we had learned and our reflections on it. I went a step further - I actually blogged about it. (Garry Mitchel's Ten Principles of Adult Learning made quite a nice listicle.) The act of doing so helped me digest the information and cement the principles in my head. Besides, that was actually how I best learned - via repetition and practice. My fellow coursemates thought I was this super student because I did my stuff way in advance.

I was a hardworking but woefully
untalented kid.

I'm afraid they were mistaken.

A lot of it isn't intelligence or diligence, but pragmatic time management. Every weekend, I dedicated a certain amount of time keeping the journal up to date so that I would have any problems handing in my work in March. One of the best ways to combat stress, is not to allow yourself to get into any unnecessarily stressful situations. Knowing that I'm not some extraordinarily smart individual that could produce written assignments on demand, it seemed foolhardy to leave everything to last-minute work and hope for the best.

Incidentally, it was the same way for me when I was younger. Study early, study often. I was never an A student. Mostly Bs. But boy, nobody knew how hard I had to slog for those Bs. People just thought I was really clever and shit. Word of advice: very few people are actually that clever. It takes a hell lot of work. And, of course, once again, time management.

Assessment on Classroom Facilitation

Midway through the third month, we all had to conduct lessons as part of the requirement. Each of us would decide on a topic which we would then have to "teach" our fellow coursemates. This was where I started floundering. People thought I wouldn't have a problem because I seemed quite at ease presenting to the class during lessons. What that was different - I mostly wasn't trying to impress anybody and nothing was at stake. Now, we were actually going to be assessed on how well we conducted the lesson plan we had developed, and I'm afraid the pressure got to me. No matter how much I rehearsed for the day, when it was time to actually do the job, my voice trembled.

One of the things an instructor is supposed to do, is assure the course participants that he or she is qualified to instruct them, and that they are "in good hands". In practice, if there's a way to say "I have a degree and three diplomas" without sounding like a conceited dickhole, I haven't discovered it yet. Some of my fellow coursemates had a better idea - they merely displayed their credentials on presentation slides to they could toot their horn without sounding like they were, well, tooting their horn. Well damn, why hadn't I thought of that? Because I'm an idiot, that's why.

Depending too much on
the whiteboard.

I kept the knowledge transfer small, facilitated group discussions and basically made sure items on the assessment checklist were met. Everyone was watching me because, well, I was the first to be assessed. I had actively chosen to be the first - to get it out of the way, and also, when you're the first to go, expectations are generally lower because you're expected to make a whole bunch of mistakes the others can learn from.

My chosen topic was "web development", and true to form, I had elected to prepare web pages instead of presentation slides. The rest of it, I reasoned, I could use the whiteboards for. Eliminate the chance of being stymied by technical failure. Surprise, surprise. The classroom we ended up in, had whiteboards that were blocked by heavy desks and assorted clutter. And here I thought I was being so clever. What the fuck, right?

As the "lesson" went on, I realized that very little of it was going the way it had played out in my head. I was nervous, my voice cracked, and sometimes I talked too fast and had too many pauses. And then the class, comprised of my fellow coursemates, began to act up.

This wasn't done out of malice - the instructor had told them they were supposed to act up so that he could assess me on how I handled disruptions. So I had people asking me blatantly stupid questions, making small talk loudly, defying instructions and so on.

Ironically, I was feeling like an utter failure by then and decided, to heck with it, I was just gonna do my thing and to hell with impressing the instructor. I totally forgot my fear in that instant. Have I mentioned that I've taught classes before? Well, when my fellow coursemates acted up that evening, I simply reacted, as if by instinct, the same way I did all those years ago. Blatantly stupid questions were shrugged off or waved away. When people made small talk loudly, I upped the volume of my voice for about two seconds, jolting them back to attention without missing a beat. When people attempted to start an argument, I told them I acknowledged their point and we could revisit this after the class. Basically, I came on strong, and backed the hell off when I needed to. The iron-fist-sheathed-in-silk-glove approach.

And I smiled. A lot.

When it was over, I went over the checklist and discovered, to my amazement, that I had covered a ton of items under "Handling Disruptions" without even trying. I hadn't even been consciously attempting to do it by the book! That was an epiphany for me - I do best when I don't try so goddamn hard.

Then it was over, and during the course of the next few weeks, I sat back and watched my fellow coursemates go through their own assessment. It was of small comfort that many of them faced the same problems I did, and some even had to repeat their assessment. It was my turn to conduct a peer assessment for some of them, and in those instances, I opted to be kind. After all, my remarks would make no difference at all to their final score, and overdoing the criticism seemed unnecessary.

E-Learning

The next module dealt with understanding the WSQ system. To that end, we were put through an E-learning program which was supplemented by webinar sessions. This was pretty dry, and the E-learning system absolutely sucked. To go into full detail about how much it sucked would be devoting too many words to it, so I won't. Again, I supplemented my learning with more blog entries, such as one about Five Elements of Competency and using WSQ Competency Standards.

My ex-boss from the startup had also completed his ACTA, and his advice and supplementary reading were invaluable. Another case for not burning bridges you don't have to. Never know when someone in your network can help you.

I was suffering from serious burnout by this time, and it was all I could do to keep my journal entries up to date. Also, the then-girlfriend and I were going through the arduous process of getting married. Let me assure you that nothing about it was fun, and mostly involved the logistics of making space for one more person in the house. More about that another time, though...

Assessment on Assessing

After the last excruciatingly boring module was the one on being an Assessor. We were trained on how to deliver an Assessment to a test candidate in a fair, empathetic and diplomatic manner. How to provide an optimal environment for Assessment. Things like that.

Assessing...

And then came the assessment... on our Assessment abilities. This involved live-action roleplaying with a prepared background scenario. We were divided into groups for this, and my group aced the entire thing without any do-overs. I can't claim any credit for this one - one of my team members was a right pain in the arse where details were concerned. He was also meticulous and not one to leave anything to chance. He prepared scripts for us to follow, and even had the bright idea of having them vetted by our instructor.

So, after we had made the changes recommended by our instructor, all we had to do was follow the script... and viola, another module out of the way.

Some drama occurred during the Assessment, things that made me come to new realizations. One of our team members lost his temper at another member. Harsh words were exchanged. To be fair, the guy being raged at, was slow to grasp the material and seemed to be going off half-cocked in the wrong direction... and this wasn't the first time either.

However, being a WSQ instructor is not just about having the skills and knowledge in facilitation of learning. Like many other professions, it is also about having the correct temperament. Often, instructors don't get a choice as to what kind of people are being allowed in the courses they are teaching. They are going to get people who are merely doing this on a whim. They are going to get the ones who think they already know everything. They are going to get the ones who aren't actually interested in the subject matter. Basically, those who are all but impossible to teach. And if we're going to lose our shit everytime someone like that shows up, maybe we should consider another line of work.

The Final Assessment

The day of the Final Assessment arrived. By then, my nervousness was gone and all I really wanted to do was get it over with. My time studying the WSQ Assessment System had all but assured me I wouldn't be failing this one (unless, of course, I failed to show up). After all, in order to justify a failure, a lot of paperwork had to be done by the Assessor. And honestly, I'd done the work. I had blog entries in addition to journal entries. And I had passed all previous modules. I can say with no false modesty that failing me at this point would require one hell of a justification.

I walked out of the assessment room with my ACTA...

Epilogue

... and on the very next day, I put that ring on my girlfriend's finger, and made her my wife. What have I done with that ACTA? Nothing to date, sadly. But it's there if I ever need it, and the experience proved enriching. Exhausting, yes, but enriching.

My fellow coursemates still hang out. Most of us are still in the original WhatsApp group we used during the course. Sometimes, we meet up to catch up. Yep, even if I never get to use that ACTA, I definitely don't regret taking that course. It was a blast. I don't know that it actually made me a better software developer, but it sure as hell rounded out my resume nicely.

Your certified Trainer and Assessor,
T___T

Friday, 14 December 2018

My Year in Training and Assessment (Part 1/2)

2018 has been a really busy year for me. Not only did I have to grind at a job where I was (and still am!) struggling, I had a woman I was seeing (and whose finger I put a ring on in that same friggin' year!), and I was in school.

What was I studying, this time? Nothing directly tech-related. I was taking my Advanced Certification in Training and Assessment (ACTA), certification necessary to become an instructor in any academic setting. Did I harbor aspirations in that direction? Not exactly. But it certainly was riveting subject matter.

How it all began

Back in 2017, the startup I was working for, had folded. I was out of a job again, and soon found myself interviewing at a training institute, for the position of programming instructor. I've had prior experience teaching, and part of why I was putting up web tutorials on this blog is because I firmly believe that part of what helps a developer grow, is the culture of sharing, and the act of imparting knowledge. So the position was interesting enough for me to give it a shot.

Surprise - my interviewer turned out to be my very first programming lecturer from Temasek Polytechnic! His hair was all white now, but I remember the guy. In fact, every time I pick up a new programming language, I can kind of hear his voice droning on about If blocks, For loops and arrays.

Over a pleasant chat, it was revealed that I needed an ACTA to even be legally allowed to teach. I would have taken it right away, but he informed me that upon turning forty, which would be almost half a year away, I would be eligible for a ninety percent discount on the school fees. Now, to someone who's out of a job, a few thousand dollars is nothing to sniff at. I soon gained employment somewhere else, but resolved to revisit the subject of obtaining this certification in the near future.

With that in mind, once things stabilized at my job, I signed up for the next available ACTA course. I would be in classes twice a week, from 7 to 10 PM. It would be a bit of a squeeze, but I'd make it work.

The first day

The class turned out to be filled with professionals from various trades. There were even a couple of actual trainers in there. Our instructor for this module was an elderly gent with a reassuring demeanor. To get all of us to know each other better, he had us play a game.

Breaking the ice.

We formed a circle. The first one would state his or her name, preceded by a descriptive term whose first letter should match the first letter of their name. (ie, Responsible Robert, Jolly Jacintha, etc), their occupation, how they best learned and what knowledge they hoped to gain from this course. And then the next in line would repeat the previous trainee's name, along with his own, and repeat the sequence. Which meant that I, being the the thirteenth, would have to repeat twelve names. Luckily, the instructor had written down the names as we went along, so if we were in any doubt, we could refer to the whiteboard.

And then it was my turn.

To my astonishment, I could repeat the names and descriptions of all twelve of the preceding trainees without referring to the whiteboard. Not even once.

"... and I'm Terrible Tan. I'm a software developer..." Here, I paused, wondering how to answer the next question. Then it came to me. "...I learn best through repetition. And I hope that by learning how to teach others, I can become a less terrible software developer."

Why "Terrible"?

Some asked me why I chose "Terrible" when the others were using terms like "Jovial", "Noble" and "Nice". I wasn't simply being cheeky, nor was I having a serious inferiority complex. You see, I am a software developer. And by definition, we software devs are all terrible. There is so much tech knowledge out there, and all of us, even the most knowledgeable ones, know but a fraction of it all. The key to improvement is to first acknowledge how much we all suck, and how much we each have to learn.

Someone who does not think he has anything to learn, is simply predisposed to not learn anything. That's just the way it is. A software developer cannot afford to think he is anything but terrible. That leads to false confidence, and eventually stagnation.

Why "Repetition"?

Each of my coursemates had had their names repeated over and over by the time it was my turn. The first one's name had been repeated thirteen times, the second one's name twelve times, and so on.

I'm not the brightest bulb in the box; I've known that since forever. I can't be told something once and immediately understand. But when I learn something, I get good at it by repeating it endlessly till it becomes second nature.

Why "better software developer"?

At first, in my new job, I was too busy struggling to even consider evening classes. However, an encounter with a colleague changed that.

Now, I have nothing against this guy personally. For all I know, he could be a totally awesome dude outside of the office. But he was exactly the kind of person I dread working with - loud, combative and dramatic. Add that to a ton of insecurities that seemed to compel him to constantly toot his own horn about his "workaholism" and drive... and you'll see why having to work alongside him made my job a lot less pleasant than it should have been. Also, his code sucked monkey balls... but that's neither here nor there. We'll speak more of this guy another time. What's relevant here is that a few months in the job, he got an offer from another company and decided to tender his resignation. And that, of course, involved handing over stuff.

Aww, poor baby.

Halfway through one of the knowledge transfer sessions, he asked us if we had any questions. When he was answered with an awkward silence, he threw a tantrum and started lecturing us about how he used to have many questions when he was in our shoes, how we just expected to be spoonfed...

Jesus, talk like that wasn't going to induce me to ask questions, that was for sure.

We were there as a professional obligation, and doing our best to absorb. We weren't here to listen to him yammer on about how enthusiastic and driven he was compared to the rest of us. I certainly didn't feel like asking any goddamn questions. All I felt inclined to do was wait for him to shut the hell up so I could get on with my work. Pro tip: Handing over work is a basic professional courtesy when you're leaving the company. So, if you're ever in the position to hand work over, stop acting like you're doing everyone such a huge fucking favor, OK?

And that, in a nutshell, was what convinced me that being a professional tech - in fact, any professional - required skills in knowledge transfer. Communication. You can be a really gifted tech, but if you can't transfer knowledge, your usefulness is pretty limited, isn't it?

In retrospect

The instructor, later on during the course, informed us of something I had been half-suspecting - that this icebreaker game had actually served a higher purpose other than getting to know one another.

Firstly, it was meant to show the lecturer who was more or less predisposed to learning. Those who had cited interest in teaching, or interest in the certification for career advancement, were sufficiently motivated. Those who were here simply because they needed to spend some SkillsFuture credits, less so.

Secondly, it was meant for each participant to self-examine how he or she best learned something. Different people learn differently, and being able to accept that is one of the basic requirements of a trainer.
Self-reflection.

The third purpose, I suspect, was psychological - for each participant to present their own self-concept to the class. Whether or not they were "Clever Chandran" or "Slow Serena", each participant's self-concept was something that could affect the speed at which they absorbed and digested new information.

Next

We'll go into more detail about what went on during those classes. Be back soon!

Friday, 7 December 2018

Fiction Review: The Girl Who Gives An Eye For An Eye.

There's a new addition to The Millennium Series! Lisbeth Salander is back in the follow-up to The Girl In The Spider's Web, and to be honest, I was not expecting a sequel so soon. On hindsight, I should have known better. Stieg Larsson created a phenomenal cast of characters, with endless possibilities and stories to be told. It only makes good business sense to milk the franchise for all it's worth.


This time round, David Lagercrantz seems to have improved on his previous work. There are still terribly tedious bits, but most of the complaints I had about the last book appear resolved, or at least mitigated.

The Premise

Lisbeth Salander has been sent to prison following the events of the last novel. In it, she gets intrigued by a mystery and enlists the help of both Holger Palmgren and Mikael Blomkvist on the outside. This leads to Holger's death, and draws Mikael and Lisbeth into a world of neurological experiments and sinister threats.

The Characters

Here are the major players in the book...

Lisbeth Salander. Our dangerous computer hacker is back, and more badass than ever. At the start of the novel, she's her usual anti-social self solving complicated math puzzles and engaging in all manner of computer badassery. Then she starts plotting, and David Lagercrantz seems to play up her martial abilities in addition to her computer hacking cred. Holger's death pushes her over the edge and we all know a Lisbeth Salander revenge is never pretty. Her snappiness and blunt retorts are a fun read, and she's absolutely brutal to Olsen.

Mikael Blomkvist. He's still the truth-seeking journalist we know and love, and even though Michael Nyqvist passed away last year, I'm still picturing him as Mikael as I read the novel. This novel's Mikael seemed a little washed-out, though, like I was reading about a less intense and colorful version. He just seems a little less assertive and decisive than usual, and events simply sweep him up along the way. I miss the old Mikael from the first three novels, the fired-up investigator with a great heart, and a devious bastard to boot.

Leo Mannheimer. Long-lost twin brother of Dan Brody. A musically-talented finance expert who suffers from extreme sensitivity to sound.

Dan Brody. Long-lost twin brother of Leo Mannheimer. Unlike his brother who plays the piano, he plays the guitar. Had an underprivileged childhood which he resents his brother for even as he rejoices at being reunited with him.

Rakel Greitz. I know she's the bad guy here, but man, she's totally awesome. In her seventies, suffering from cancer and still managing to kill people. Driven by purity of purpose,sheer will and the absolute certainty that she's serving a higher calling to science. Her only discernible weakness is pride, and an age-old grudge with Lisbeth she just won't let go.

Hilda von Kanterborg. A psychologist and part of the neurology experiminetation team. Racked by guilt and drinks a lot. She's instrumental in discovering what Rakel Gretz is up to.

The supporting cast with a significant amount of "screen" time.

Holder Palmgren, Lisbeth's old friend and former legal guardian. He's pretty much an invalid, and is subject to the indignity of having to be washed and changed by nurses. But he's eager to help as always, and this leads to his murder. It's pretty sad. This geezer has been around for the past four novels.

Faria Kazi is a Pakistani woman who we first meet in the prison being abused by Benito. Her tale is even sadder and as the story moves along, it becomes apparent that she's not just a victim of stereotypical oppression in the Middle East, but one hell of a survivor. In fact, she pulls herself together enough to hep in Lisbeth's rescue near the end.

Benito Andersson. A cartoonishly psychotic female prisoner who manages to intimidate, bully and abuse just about everyone in the prison - except for Lisbeth Salander. Gets her ass handed to her by Lisbeth in an awesome but not altogether realistic moment. Not a really complicated character, really. Batshit crazy would be a somewhat fitting assessment.

Jan Bublanski. He gets more of the action than I expected, certainly more than most other series regulars such as Annika Giannini and Erika Berger.

Bashir and Razan Kazi, Faria's older brothers. They're caricatures of violently misogynistic Islamic males who terrorize Faria and eventually meet their comeuppance at Lisbeth's hands.

Khalil Kazi, Faria's spineless youngest brother. He's the nicest by far, which makes it all the more unforgiveable in Faria's eyes when it's revealed that he killed her boyfriend.

Alvar Olsen, a prison warden who tries hard to do his job well, but has been cowed into surrender by Benito Andersson. He's also a man who takes pride in his masculinity and physical strength, so when Lisbeth almost effortlessly disables him, it's a huge blow to his ego.

Rickard Fager, prison governor. He's a pompous and vainglorious ass who only cares about the positive image of the prison and turns a blind eye to whatever goes on within. He finds out the hard way that Lisbeth Salander cannot be intimidated.

Malin Frode. Press secretary at the Foreign Ministry. A feminist and one of Mikael's ex-lovers, and very sexually aggressive. Plays a not-inconsiderable role in the novel helping Mikael uncover more about Leo Mannheimer.

Ellenor Hjort. Fiancee to the deceased Carl Seger, who was Leo Mannheimer's mentor. Provides Mikael with valuable information on Leo.

Plague, a hacker legendary for his lack of personal hygiene as much as his computer prowess. Good ol' Plague features here again (albeit only during a couple chapters), as he did in the last four novels, and I'd be disappointed if he weren't included in this one.

Minor characters, or familiar characters who perform bit-part roles in the novel.

Lulu Magoro, an African woman of sweet disposition who is Holger Palmgren's nurse. She and Holgen share a great mutual affection. Their easygoing banter is delightful.

Hassan Ferdousi. He is an imam, and this puts him at odds with Jewish Jan Bublanski over the subject of Isreal. He helps bring Khalil for his confession to Jamal Chowdhury's murder.

Charlotte "Lotta" von Kanterborg. Serves as one of the leads Mikael follows while trying to find her sister Hilda.

Sonia Modig, Jerker Holmberg and Curt Andersson (who's inexplicably called "Svensson" here). The trio, as Bublanski's officers, don't feature much except for an amusing paragraph or two in some comic-relief segment. A far cry from their presence in The Girl Who Kicked The Hornet's Nest.

Greitz's sidekick Benjamin. Lagercrantz does attempt, feebly, to give him some depth, but all he does ultimately is serve as cannon fodder for Lisbeth's ass-kicking prowess.

Annika Giannini, Lisbeth's lawyer and Mikael's sister. She doesn't get much to do in the novel other than act as a sounding board (and rather briefly too, I might add) for Mikael's thinking-out-loud sessions.

Erika Berger. Head honcho of The Millennium. She's reduced to minor exposition here and not even the obligatory sex scene with Mikael.

The Mood

It was gloomy from the outset, and the tension seemed lacking. Somehow Lagercrantz's attempts to make me think Lisbeth was in very real danger in the prison, just weren't working. I did experience some anxiety though, when it looked like Holger wasn't going to make it. Later on, the dangerous situations seemed kind of forced and I just wasn't getting into it. No, as far as sense of danger does, this novel didn't have it. In fact, in certain areas, the darker themes made it outright depressing without the adrenaline-inducing action to counterbalance it.

The novel ends on a sweet note as Lisbeth delivers Holger's eulogy. And thankfully, that part doesn't drag on too long.

What I liked

Hacker Republic. I like the fact that when Lisbeth's being kidnapped, there are some things even these powerful hackers can't handle. Makes things more realistic, somehow. On a somewhat related note, Lisbeth's shortcut buttons to Hacker Republic functions such as cloud upload and SOS alarm with GPS tracking, is seriously cool.

Mikael's back to his philandering ways after seemingly going celibate in The Girl In The Spider's Web. Not that I liked it in the first place (I think Larsson way overdid it), but at least it's consistent.

Killing off Holger Palmgren. This was a gutsy move on Lagercrantz's part. As mentioned earlier, the old dude has been a part of the last four novels and is perhaps the only man Lisbeth Salander loves unreservedly.

Lagercrantz is focused, and doesn't detract from the story with meandering sideplots. This leads to a shorter novel, which doesn't give the reader enough time to get tired of it before finishing it.

What I didn't

The title. I can't ready see what relevance "an eye for an eye" has here. Unless the author was just thinking along the lines of Lisbeth's revenge, and even then it seems an overly grandiose title.

"Glint of steel". Lagercrantz gets repetitive here. I might have seen that description three times within a few pages.

The little inconsistencies from canon. Wasn't Sonia Modig supposed to be married? What's this shit about her being in love? Also, what gives with the references to Peter Teleborian? Wasn't he arrested for possession of child pornography back in The Girl Who Kicked The Hornet's Nest?

Too much focus on the story of the twins. Honestly, I'd rather this novel be about Lisbeth and Mikael, as usual. I can take a few paragraphs here and there from the point of view of other characters, but entire chapters? Lisbeth and Mikael seem like guest stars in this novel at times.

Conclusion

It's not great, but it's bearable and there are good bits in it. Especially in the middle. But the rest of it lacks a certain substance. Compared to the others, it seems to be only half a novel in terms of plot content. That's not neccesarily a bad thing; Larsson, rest his soul, tended to be very wordy. Sometimes excessively so.

My Rating

6 / 10

An eye for an eye, a tooth for a tooth. And 30 bucks for this novel!
T___T