Friday 19 December 2014

Web Tutorial: The QBasic Xmas Tree

Merry Christmas and Happy Holidays!

The occasion calls for some festive light-hearted fun, and what better than something I used to fool around with as an awkward geeky teenager?

QBasic! For more on this: http://en.wikipedia.org/wiki/QBasic

Now that I'm a slightly less awkward, even more geeky adult, here's an updated version of a little program I wrote back then, to test my mastery of nested loops and logic - the QBasic Xmas Tree!

Ah, the nostalgia.

This isn't a web tutorial per se, because QBasic has nothing to do with the web. On the other hand, this tutorial is being posted on the web, so... enough dithering! Let's fire up your QBasic editor and get right to it!

First, type the following code in your console.
INPUT "How many sections should your Xmas tree have"; sections

Run this line, and it should be enough to give you the following:

The program starts with user input.

This will serve to obtain user input (only in numerical format) and assign it to the variable sections. This is important because the program will generate a Xmas Tree with that number of sections.

Of course, we're not done yet. The first line works, but it's useless on its own unless you have the rest of the program. But first, a preview of what your Xmas Tree will look like with four sections!

Ta daaaaa


INPUT "How many sections should your Xmas tree have"; sections
CLS

COLOR 14

cols = sections * 20
cols = cols + (cols MOD 2)

filler = (cols - 1) / 2

CLS clears the screen after obtaining input. and COLOR 14 changes the text color to Yellow. You'll need to do this because we're drawing the star!

cols = sections *20 defines the total theoretical amount of width (in spaces) your tree should take up. It should commensurate with the number of sections the user specifies. cols = cols + (cols MOD 2) makes sure it's an odd number.  filler=cols-1 defines the number of empty spaces on the left. In this case, you deduct 1 from it because the first line is going to be your filler, followed by one character dedicated to the star. So add the following lines to draw the star!

INPUT "How many sections should your Xmas tree have"; sections
CLS

COLOR 14
cols = sections * 20
cols = cols + (cols MOD 2)
filler = (cols - 1) / 2
line$ = ""

FOR i = 1 TO filler STEP 1
    line$ = line$ + " "
NEXT i

line$ = line$ + "*"

PRINT line$

The star is supposed to be dead center top of your tree. It's of course, followed by the top of the tree. I'm going to use the character "^" and call it a leaf.

INPUT "How many sections should your Xmas tree have"; sections
CLS

COLOR 14
cols = sections * 20
cols = cols + (cols MOD 2)
filler = (cols - 1) / 2
line$ = ""

FOR i = 1 TO filler STEP 1
    line$ = line$ + " "
NEXT i

line$ = line$ + "*"
PRINT line$

COLOR 2
line$ = ""

FOR i = 1 TO filler STEP 1
    line$ = line$ + " "
NEXT i

line$ = line$ + "^"

PRINT line$

Of course, COLOR 2 changes the text color to Green.

Now, we have the star, and we have the top of the tree. Now we're going to keep using leaves to draw the rest! For that, we'll need to employ a certain amount of logic.

Here are the rules:

The first section starts with two lines, just after the top of the tree. The first line of the first section will be 3 leaves. Subsequent lines will be 2 leaves more than the previous line of the same section, and the filler will be one space less.

Subsequent sections will have one more row than the previous section. And each row will start with the same number of leaves as the second-last row of the previous section!

To show you what I mean, refer to the illustration below:

(star and top)
                    *
                    ^
(section 1)
                   ^^^
                  ^^^^^
(section 2)
                   ^^^
                  ^^^^^
                 ^^^^^^^
(section 3)
                 ^^^^^^^
                ^^^^^^^^^
               ^^^^^^^^^^^
              ^^^^^^^^^^^^^  
(and so on)

So maybe we should represent this numerically, in tabular form, in order to understand better.
section rows leaves per row
1 2 3,5
2 3 3,5,7
3 4 7,9,11,13
4 5 11,13,15,17,19

So now we're going to add the first loop for sections, and implement the rows logic.
INPUT "How many sections should your Xmas tree have"; sections
CLS

COLOR 14
cols = sections * 20
cols = cols + (cols MOD 2)
filler = (cols - 1) / 2
line$ = ""

FOR i = 1 TO filler STEP 1
    line$ = line$ + " "
NEXT i

line$ = line$ + "*"
PRINT line$

COLOR 2
line$ = ""

FOR i = 1 TO filler STEP 1
    line$ = line$ + " "
NEXT i

line$ = line$ + "^"

PRINT line

FOR i = 1 TO sections STEP 1
    rows = 1 + i

NEXT i

And then we'll nest another FOR loop within the first one,
INPUT "How many sections should your Xmas tree have"; sections
CLS

COLOR 14
cols = sections * 20
cols = cols + (cols MOD 2)
filler = (cols - 1) / 2
line$ = ""

FOR i = 1 TO filler STEP 1
    line$ = line$ + " "
NEXT i

line$ = line$ + "*"
PRINT line$

COLOR 2
line$ = ""

FOR i = 1 TO filler STEP 1
    line$ = line$ + " "
NEXT i

line$ = line$ + "^"

PRINT line

FOR i = 1 TO sections STEP 1
    rows = 1 + i

    FOR j = 1 TO rows STEP 1
        line$ = ""
        nextstartcol = 0

    NEXT j
NEXT i

In the nested loop, we initialize the variable line to nothing and nextstartcol to 0, because they will be changed frequently. Now, next  one's a biggie. It's a nested IF loop that implements the logic of leaves per row.
INPUT "How many sections should your Xmas tree have"; sections
CLS

COLOR 14
cols = sections * 20
cols = cols + (cols MOD 2)
filler = (cols - 1) / 2
line$ = ""

FOR i = 1 TO filler STEP 1
    line$ = line$ + " "
NEXT i

line$ = line$ + "*"
PRINT line$

COLOR 2
line$ = ""

FOR i = 1 TO filler STEP 1
    line$ = line$ + " "
NEXT i

line$ = line$ + "^"

PRINT line

FOR i = 1 TO sections STEP 1
    rows = 1 + i

    FOR j = 1 TO rows STEP 1
        line$ = ""
        nextstartcol = 0

        IF i = 1 THEN
            IF j = 1 THEN
                sectioncols = 3
                nextstartcols = 3
            ELSE
               
sectioncols = sectioncols + 2
            END IF
        ELSE
            IF j = 1 THEN
               
sectioncols = nextstartcols
            ELSE
               
sectioncols = sectioncols + 2

                IF j = rows - 1 THEN
                    nextstartcols =
sectioncols
                END IF
            END IF
        END IF

    NEXT j
NEXT i

Now that the hard part's out of the way, we've determined nextstartrows and sectioncols for each row. Time to draw it!
INPUT "How many sections should your Xmas tree have"; sections
CLS

COLOR 14
cols = sections * 20
cols = cols + (cols MOD 2)
filler = (cols - 1) / 2
line$ = ""

FOR i = 1 TO filler STEP 1
    line$ = line$ + " "
NEXT i

line$ = line$ + "*"
PRINT line$

COLOR 2
line$ = ""

FOR i = 1 TO filler STEP 1
    line$ = line$ + " "
NEXT i

line$ = line$ + "^"

PRINT line

FOR i = 1 TO sections STEP 1
    rows = 1 + i

    FOR j = 1 TO rows STEP 1
        line$ = ""
        nextstartcol = 0

        IF i = 1 THEN
            IF j = 1 THEN
                sectioncols = 3
                nextstartcols = 3
            ELSE
                sectioncols = sectioncols + 2
            END IF
        ELSE
            IF j = 1 THEN
                sectioncols = nextstartcols
            ELSE
                sectioncols = sectioncols + 2

                IF j = rows - 1 THEN
                    nextstartcols = sectioncols
                END IF
            END IF
        END IF

        filler = (cols - sectioncols) / 2

        FOR k = 1 TO filler STEP 1
            line$ = line$ + " "
        NEXT k

        FOR k = 1 TO sectioncols STEP 1
            line$ = line$ + "^"
        NEXT k

        PRINT line$

    NEXT j
NEXT i

And there you have your Xmas Tree. I'm gonna add one last segment of code as a message:
INPUT "How many sections should your Xmas tree have"; sections
CLS

COLOR 14
cols = sections * 20
cols = cols + (cols MOD 2)
filler = (cols - 1) / 2
line$ = ""

FOR i = 1 TO filler STEP 1
    line$ = line$ + " "
NEXT i

line$ = line$ + "*"
PRINT line$

COLOR 2
line$ = ""

FOR i = 1 TO filler STEP 1
    line$ = line$ + " "
NEXT i

line$ = line$ + "^"

PRINT line

FOR i = 1 TO sections STEP 1
    rows = 1 + i

    FOR j = 1 TO rows STEP 1
        line$ = ""
        nextstartcol = 0

        IF i = 1 THEN
            IF j = 1 THEN
                sectioncols = 3
                nextstartcols = 3
            ELSE
                sectioncols = sectioncols + 2
            END IF
        ELSE
            IF j = 1 THEN
                sectioncols = nextstartcols
            ELSE
                sectioncols = sectioncols + 2

                IF j = rows - 1 THEN
                    nextstartcols = sectioncols
                END IF
            END IF
        END IF

        filler = (cols - sectioncols) / 2

        FOR k = 1 TO filler STEP 1
            line$ = line$ + " "
        NEXT k

        FOR k = 1 TO sectioncols STEP 1
            line$ = line$ + "^"
        NEXT k

        PRINT line$
    NEXT j
NEXT i

COLOR 15
filler = (cols - 15) / 2
line$ = ""

FOR i = 1 TO filler STEP 1
    line$ = line$ + " "
NEXT i

line$ = line$ + "MERRY CHRISTMAS!"

FOR i = 1 TO filler STEP 1
    line$ = line$ + " "
NEXT i

PRINT line$

filler = (cols - 5) / 2
line$ = ""

FOR i = 1 TO filler STEP 1
    line$ = line$ + " "
NEXT i

line$ = line$ + "T___T"

PRINT line$

And that's the entire piece of code for the QBasic Xmas Tree. Pretty old-school stuff, especially when you consider it was done way back before the Internet came with color.

Pretty easy, wasn't it? One could even say it was... wait for it... elemen-tree!
T___T

Sunday 7 December 2014

Establishing a Transition Sequence in CSS3

Transitions can be rewarding in CSS3. Gone are the days a developer had to manipulate DOM properties and multiple timing functions in JavaScript. With the right combination of JavaScript and CSS3 - sometimes with only CSS3 - one can work wonders.

Take the following HTML/CSS3/JavaScript code below:

<!DOCTYPE html>
<html>
    <head>
        <title>CSS3 test</title>
        <style type="text/css">
            .bigcircle
            {
                width:200px;
                height:200px;
                border:1px solid #777777;
                background-color:#FFAA00;
                border-radius:150px;
                margin-left:0px;
                -webkit-transition: all 5s;
                transition: all 5s;   
            }

            .newpos
            {
                -webkit-transform: rotate(0deg);
                -moz-transform: rotate(720deg);
                -o-transform: rotate(720deg);
                -ms-transform: rotate(720deg);
                transform: rotate(720deg);
                margin-left:500px;
            }

            .oldpos
            {
                margin-left:0px;
            }

            .smallcircle
            {
                width:20px;
                height:20px;
                margin-top:5px;
                border-radius:9px;
                margin-left:auto;
                margin-right:auto;
                background-color:#FFCC00;          
            }

        </style>

        <script>
            function start_rolling()
            {  
                var pos=(document.getElementById("wheel").className=="bigcircle newpos"?"oldpos":"newpos");
                document.getElementById("wheel").className="bigcircle "+pos;

                if (pos=="oldpos")
                {
                    document.getElementById("btRoll").value="click me to see the ball roll";
                }
                else
                {
                    document.getElementById("btRoll").value="click me to see the ball roll back";
                }
            }
        </script>
    </head>

    <body>
        <input id="btRoll" type="button" value="click me to see the ball roll" onclick="start_rolling();">
        <div id="wheel" class="bigcircle">
            <div class="smallcircle">

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

When the button is clicked, the wheel rolls to the right. Click the button again, the ball rolls to the left. Try it. It works here!



But what happens if you want the wheel to first be invisible, then pop up and roll to the right? And then turn invisible again after rolling back to the left?

Try changing the code below:

<!DOCTYPE html>
<html>
    <head>
        <title>CSS3 test</title>
        <style type="text/css">
            .bigcircle
            {
                width:200px;
                height:200px;
                border:1px solid #777777;
                background-color:#AA7700;
                border-radius:150px;
                margin-left:0px;
                -webkit-transition: all 5s;
                transition: all 5s;
                display:none;
            }

            .newpos
            {
                -webkit-transform: rotate(0deg);
                -moz-transform: rotate(720deg);
                -o-transform: rotate(720deg);
                -ms-transform: rotate(720deg);
                transform: rotate(720deg);
                margin-left:500px;
            }

            .oldpos
            {
                margin-left:0px;
            }

            .smallcircle
            {
                width:20px;
                height:20px;
                margin-top:5px;
                border-radius:9px;
                margin-left:auto;
                margin-right:auto;
                background-color:#FFAA00;          
            }

        </style>

        <script>
            function start_rolling()
            {  
                var pos=(document.getElementById("wheel").className=="bigcircle newpos"?"oldpos":"newpos");
                document.getElementById("wheel").style.display="block";
                document.getElementById("wheel").className="bigcircle "+pos;

                if (pos=="oldpos")
                {
                    document.getElementById("btRoll").value="click me to see the ball roll";
                    document.getElementById("wheel").style.display="none"; 
                }
                else
                {
                    document.getElementById("btRoll").value="click me to see the ball roll back";
                }
            }
        </script>
    </head>

    <body>
        <input id="btRoll" type="button" value="click me to see the ball roll" onclick="start_rolling();">
        <div id="wheel" class="bigcircle">
            <div class="smallcircle">

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

Did it work? Guess not! The ball remained hidden.

Why?

Simply put, not every property can be manipulated by a CSS3 transition. The display property is one of these. While we specified that the change to the margin-left property would take 5 seconds to fully finish, the truth is that both changes to the display and margin-left properties were started simultaneously.

And this confused the processor.

To rectify this, we need to establish a proper sequence for the changes. So we're going to make the following change to the JavaScript.

        <script>
            function start_rolling()
            {  
                var pos=(document.getElementById("wheel").className=="bigcircle newpos"?"oldpos":"newpos");
                document.getElementById("wheel").style.display="block";
                setTimeout(function() {document.getElementById("wheel").className="bigcircle "+pos;},100);

                if (pos=="oldpos")
                {
                    document.getElementById("btRoll").value="click me to see the ball roll";
                    setTimeout(function() {document.getElementById("wheel").style.display="none";},5500);
                }
                else
                {
                    document.getElementById("btRoll").value="click me to see the ball roll back";
                }
            }
        </script>

Magic! Now the ball appears and rolls to the right. And when you click the second time, it rolls back to the left and disappears!

Read more about JavaScript timing functions here: http://www.w3schools.com/js/js_timing.asp

What sorcery is this?!

We introduced a slight time delay, about 100 milliseconds, for the margin-left property to change after the display property change. And when the ball rolled left, we set a time delay (5500 milliseconds) for the ball to disappear. The processor no longer tries to execute changes to a non-transitionable property (display) and a transitionable property (margin-left) at the same time. No more conflict!

Hope you enjoyed reading this. It's how I roll, yo.
T___T

Thursday 4 December 2014

Big Bang Media Undersells

Following the unintended comedy generated by a workplace happiness survey, conceived by the Singapore Human Resources Institute and consulting firm Align Group, a new phrase was born: Under Happy.

I'm not even going to go into the numerous and obvious wicked puns derivable from this one, but take a gander at this job ad.
Click to enlarge

Last month, we took a look at a spectacularly bad job ad by Sugar Technologies, and now we have an actual example of wit from Big Bang Media Pte Ltd. A sly dig at the workplace happiness survey in a mercifully short piece. Less is more, so a favorite developer maxim goes, and this one doesn't disappoint.

It's probably not the recommended way to write a job ad, but it's still a better love story than Twilight sight better than the pretentious crap on offer by Sugar Technologies.

I chortled.

Watch and learn, Sugar.


Now that's what I call under-stated humor!
T___T

Tuesday 2 December 2014

How I became a Web Developer (Part 2/2)

Battle of the Bottle

And then, like many young people, I got carried away with the fact that I had money. I started drinking. It began as weekend binges, then trickled down to weekdays as well. Waking up with strangers, puking my guts out. That kind of thing. I started calling in sick. I could have still worked, I just didn't want to. It showed in my attitude. I became snarky, unhelpful and short-tempered.

Pretty soon, I was going through the motions at work and waiting for the monthly paycheck just so there would have money for booze. And of course, I needed money to drink because it helped me deal with how much I hated this job. If at this point, you're thinking that this sounds stupid, you're absolutely right. I was a stupid kid. I wasn't being fair to the company or myself, and this was definitely not how a responsible working adult should carry himself.

Yep, this loser.


One day all this came to a head.

The company presented me with a gift: a nice wristwatch engraved with my name, and a letter congratulating me for having completed five years in their employ. I'm sure they meant well, but it was like a slap in the face.

Five. Fucking. Years.

I was supposed to have been gone by the third year. What happened to the wildly ambitious twenty-three year old who stepped into this company five years ago? That kid got sidetracked. He got stuck in a job with precious few prospects, because, as technology advances and becomes increasingly ingrained into our daily lives, fewer users are dumb enough to need much desktop support anymore. That kid hated his job, so in the past few years he hadn't learned a damned thing about networking or server support. He basically followed orders and went through the motions. Meanwhile, his pay kept rising. Whereas once he was good value for money, he was now rapidly becoming an expensive liability.

This kid's relationship with this company was over. It was just a matter of who realized it first.

Epiphany

I got drunk again that night. The following morning, I looked in the mirror. My wasted unshaven face and bloodshot eyes stared back at me judgmentally. I'd run out of excuses. What was holding me back? Stagnating economy? IT employment squeeze? Bad timing?

Bullshit. I was the one holding myself back. My fate was in my hands, and always had been. And from that moment of clarity, came resolve. I still liked to drink, but I hated my job more than I liked to drink. And if I was tired of being treated like desktop support, the answer was simple. Stop being desktop support.

Action

From that day, I stopped drinking. No allowances, no excuses. And made a plan. To make myself employable somewhere else without having to leverage on years of desktop support experience, I would need a skill upgrade. Fortune favored me then. There was a polytechnic offering post-grad courses. After some careful deliberation, I enrolled for a course in e-commerce technology.

So now instead of drinking, I was spending my time after office hours studying, experimenting and doing research. A year later, I obtained my certification. Another company offered me a web developer's position, but at a pay cut. I took it without hesitation. And never looked back. I've stayed (mostly) dry since, and since that day I have never needed to call in sick.

That's how I finally became a web developer. I was earning less than before and had to start from the bottom, but I was free.

Was it smooth sailing from then on? Oh hell, no. This was just the beginning. There was a looming mountain in front of me and a journey that promised to be rough and treacherous. I dug in and started climbing.


Just the beginning, kiddo.

What's the point of this story? 

To congratulate myself on a job well done? To make a big song and dance about my personal and professional journey?

Well, I'd be lying if I told you I don't have a healthy amount of self-esteem from having clawed my way out of that pit. Sure, there are stories out there way more amazing, and struggles way more epic than mine. And I wouldn't be the first person in the world to wake up one day, stop drinking, and take control of his life.

But it's my blog. It's my experience. I get to tell my tale, and if you get something out of this as well, good for you.

If there's anyone out there who's at a vastly different place than you envisioned yourself to be and are feeling dissatisfied with life, perhaps this will help you reach the same realizations. With far less fuss.

Sometimes the answer really is that simple - stop whining and move on. And if you're telling me it isn't easy, well of course it isn't, sunshine. It isn't supposed to be easy at all.


You're in a boat and life is a stream. Start rowing!
T___T

Monday 1 December 2014

How I Became a Web Developer (Part 1/2)

I just turned thirty-seven two weeks ago. It's been almost fifteen years since I embarked on this journey. Warning: long story ahead, make yourself comfortable!

Some Background

It was 2001 and I had just graduated with a Bachelor's Degree in Information Technology. The possibilities were endless. The problem was, in the face of a slumbering economy and lack of job opportunities, I soon wound up taking odd jobs. Basic computer literacy training. Small websites.

And in the course of building one of those small projects that had been outsourced to me from a vendor, I visited his shophouse office in Little India. He took me around and introduced me to his team. It was a tiny dingy room with precious little furniture. Four PCs in the room, and a big smoldering ash-tray in the middle. The air reeked of sweat and old cigarette smoke.

It was heaven to my young eyes. These Indians, were, to me, the epitome of cool. This was what I was going to do for the rest of my life. I was hooked.

I didn't become a full-fledged web developer right away. It took years of screwing up to get to this point. In retrospect, perhaps my dreams could have been a little bit bigger.

But, for better or worse, this is what I am. This is what I do.

And after that day...

The path towards becoming a web developer turned out to be slightly more complicated.

Somehow I landed a job as desktop support in a legal firm. My first full-time job ever. It wasn't where I envisioned myself being, but it would do for a start. I would leech whatever experience I could from this, and move on in maybe three years.

At least, that was the plan.

It started out interesting. I was brimming with youthful enthusiasm after going from temp job to temp job. Because some in-house development was needed, I picked up a book on my desk, and learned ASP from there. It wasn't too difficult for someone with a Visual Basic background.


I learned all my ASP from this!


The first year was filled with wonder. Friendships were forged, some of which are still ongoing today. I honed my web scripting skills, which, as it turned out, would prove invaluable down the road. In fact, as much as I eventually grew to hate the job, there's no denying that the experience hardened me. Whenever someone complains to me about user stupidity, I tend to go "You think that's stupid? I've seen worse. I spent six years in desktop support".

By the third year, my enthusiasm waned. There was only so much development I could do, and the other aspects of my job were less than thrilling. Networking was one of my least favorite subjects in school, and having hands-on experience with it didn't remove my distaste for it. And as for desktop support...

What can I say about desktop support that won't sound overly uncharitable? It involved moving PCs from location to location, setting up email accounts, tending to all the little problems that users seemed to encounter all the time. It wasn't exciting to begin with, but by the third year it had become positively tedious. There's only so much stupidity a man can take before he goes nuts.

Someone once described desktop support to me as "the IT equivalent of leading a man to the urinal and holding his dick while he takes a piss". He was being kind. It's way worse. Lack of computer savvy I could forgive. One gets those users all the time - without them, desktop support would not exist. And then there was the other kind of user - entitled, obnoxious and utterly inept. Special breeds of stupid who thought desktop support automatically extended to all things electronic such as microwave ovens, paper shredders and phones. Special strains of asshole who thought nothing of interrupting a man at his toilet break just because there was a printing problem. I was being ordered around by people who, in soccer parlance, weren't good enough to carry my boots.

I was a university graduate, dammit. I deserved better. Or so I thought.

The truth is, a man deserves exactly what he will accept. Each time my pay got raised or I received my annual bonus, I looked the other way and delayed moving on. And here's the thing about the annual bonus in that company - it was divided in two and each half was doled out at intervals of six months.  People who felt that the bonus was their own money and were entitled to it, would delay their departure by another half-year to avoid forfeiting it. It was genius. A brilliant maneuver to keep unambitious, unmotivated 9-to-5ers slaving away. Do I blame the company? In retrospect, no. They dangled that carrot; I was the fool who took it.

Next...

How I got out.