Tuesday 26 February 2019

The Sixth Pillar of Total Defence

As of the middle of this month, Digital Defence has officially become the sixth pillar of Singapore's Total Defence framework. The Government had spoken about this in 2018, outlining the need to take cyber-threats and disinformation seriously.

Total Defence

The Total Defense framework is a framework for an all-round defense against threats to the country, and encompasses the following aspects or "pillars". For some context, here's a brief outline.

Military Defence. Our army, navy and air force guard us against external threats such as foreign invasion. Male citizens are expected to perform National Service, and females are encouraged to be supportive or sign up for the military themselves.

Civil Defence. Our police, medical personnel and firefighters protect us in times of crisis. Citizens are taught how to react during emergencies and to stay alert at all times.

Economic Defence. Ensuring a strong economy to maintain stability and good infrastructure. Citizens are expected to remain productive while embracing lifelong learning and constantly upgrading skillsets to better meet the needs of the economy, spend within their means and invest wisely.

Social Defence. Ensuring that Singaporeans live in harmony, build strong bonds and stand united in the face of a threat, and stay vigilant against attempts to undermine the social fabric of society. (Phew, what a mouthful). Examples include guarding against fake news or malicious rumors designed to divide Singapore along racial, religious or political lines, welcoming new citizens and helping them assimilate into our culture, and so on.

Psychological Defence. Developing strength of will and resilience, to build our ability to bounce back after a setback; to understand Singapore's history and appreciate how she got where she is today.

The sixth pillar - Digital Defence

This new pillar basically entails developing the expertise to guard against cyber-terrorism, fake news and other computer-based threats. This came about after Singapore was beset by some high-profile data breaches in the past year and beyond.

This seems rather unnecessary. While I appreciate and fully endorse the reasoning behind this move, as a tech professional, I can't agree with its implementation. The average non-techie whose interaction with technology is pretty much limited to using Facebook to view cat pictures and hailing cab rides on Grab, may be impressed and think that the Government has got this under control. I have my reservations.

Do we need a sixth finger?

For one, I've always thought of Total Defence as a hand with five fingers - each pillar representing a finger. Now we're going to have a sixth finger (A Digit-al aspect, geddit? Hur hur) and this pretty much screws with my mental model. But as quibbles go, this is a relatively minor one.

There's potential for huge backfire. Making Digital Defence the sixth pillar was merely a declaration of intent. Are we confident enough, given everything that has happened up to this point, that we can continue to safeguard against cyber-attacks, and actually back this up? We're going to be mightily embarrassed if we get successfully attacked again after this.

A huge target.

The Government needs to remember that these are hackers they are dealing with, not any other run-of-the-mill class of criminal. Some criminals may be deterred by the presence of numerous armed guards and a padlock, and seek easier gains elsewhere. Hackers aren't necessarily motivated by profit. They're also motivated by the challenge, and in some cases, the need to see the world burn. A visible and high-profile declaration of intent like this Sixth Pillar, only serves to paint a great big nigh-irresistable bulls-eye on our backs.

But for my biggest quibble...

This Sixth Pillar business feels awkward and tacked-on, and is uncannily reminiscent of some backward practices I've observed in companies I've worked in. Some companies don't really understand technology. They see it as something their competitors have, and therefore, to keep up with the Joneses, it's something they've got to have too. This usually manifests in the form of a separate IT Department alongside Logistics, Accounts and what-have-you.

Tacked on.

The problem here is that these companies who set up the IT Department within their organization, see technology as a separate aspect. The rest of the organization is still filled with clueless dinosaurs who can barely operate their email accounts and need help creating reports on spreadsheets. The staff don't have a good understanding of technology, what it can accomplish, what it can't accomplish, and don't have the know-how to keep the company operating using the technological infrastructure to its fullest.

Just like Digital Defence being a separate sixth pillar alongside all the other pillars. See the parallel here?

What should Singapore do, then?

Make Digital Defence part of Military, Civil, Economic, Social and Psychological Defence. For Military Defence, the SAF is already doing this with their Cyber Defence School. The Government released the SGSecure app for Civil Defence. Guarding against fake news is already part of Social Defence. For Economic Defence, train citizens in computer know-how and how to recognize phishing attempts and online scams.

Technology has to be part and parcel of all aspects of Total Defence. Integrate Digital Defence into everything. It is not, and should not be considered, a separate aspect.

Remember, there's a part for everyone!
T___T


Saturday 23 February 2019

Film Review: Silicon Valley Season 3

Silicon Valley continues as the Pied Piper Team get up to even more hijinks. As I'm writing this, Season Five has gone by. This review is just for Season Three, but I'll get there, I promise.


Warning - Strong language and extreme animal nudity!

And I'm not even kidding about the last part! Halfway through the series, you're going to be treated to the sight of two horses having some sexy time. No pictures. Why deprive you of the pleasure of seeing it firsthand, eh?

The Premise

Richard Hendricks has been fired as CEO, and the first half of the season revolves around him trying to get his spot back while chafing under the leadership of the newly installed CEO, Jack Barker. In the second half, he goes head-to-head with Gavin Belson, CEO of Hooli, and the latter actually ends up saving him in very indirect, roundabout ways. All in all, a comedy of errors!

The Characters

Thomas Middleditch as the still very adorkable and awkward Richard Hendricks. We see Richard at his most frustrated, and it's hard not to feel for the guy. All he wants to do is make a product, and be in charge of his own company. Unfortunately, this is Silicon Valley and there's a price for all this. As the series goes on, we see the start of Richard's change from nice guy to dick. He never quite makes the full transition, not least because deep down he's just a geek who wants to be left alone to code. And at the end, it's his almost pathological honesty that gets him in trouble just like in the previous Season.

TJ Miller as Erlich Bachmann. Erlich is quintessential TJ Miller - loud, brash, obnoxious... and utterly convinced of his own awesomeness. Yet beneath that abrasive facade is a guy who's capable of caring. And Miller plays this astonishingly well, giving layers to Erlich I never thought possible.

Later on in the series, Erlich has a moment of character growth where he sacrifices himself to save Pied Piper from a crisis. And while it's not all funny, it is genuinely touching to see him and Richard look out for each other. In the finale, there's even a classic Bachman segment where he explains, using masturbation euphemisms, the Fear of Missing Out (FOMO) phenomenon that he uses to improve public perception of Pied Piper.

Zach Woods as Jared Dunn. Supportive, motherly, hopelessly optimistic. This season it's revealed that he's actually quite a ladies' man, and so modest about it too! He's such a big fan of Richard Hendricks that it's almost cringe-worthy to watch... almost. This is a dude whose loyalty would take nothing short of an apocalyptic change to waver. And there's something really earnest and sweet about that.

Kumail Nanjiani is the awkward Dinesh Chugtai. This season, we mostly see him as a bumbling and socially inept jerk who masks his insecurities by constantly claiming credit and engaging in selfish behavior. However, Kumail teams up with Martin Starr exceptionally well to form an antangonistic yet effective partnership.

Martin Starr as Bertram Gilfoyle. His racial slurs towards Dinesh are hilarious. While Gilfoyle does not evolve much as a character this season, he's at least consistent. The snarky one-liners and cynical expositions on life are superbly delivered by Starr.

Stephen Tobolowsky as "Action" Jack Barker. A shrewd tech business guy who keeps harping on the Conjoined Triangles of Success. He can be ruthless one minute and collaborative the other. Tobolowsky nailed this character with his performance. I found myself wanting more Action Jack.

Josh Brener is Nelson "Big Head" Bighetti. Nice guy, if really clueless. Seriously, if he wasn't portrayed as such a genuinely harmless dude, I'd really hate his guts because he seems to succeed even when he fails while making the most harebrained decisions ever.

Amanda Crew as Monica Hall. Frantic, serious and really fun to watch. Especially whenever she does that eye-roll thing in response to Erlich. One of her standouts is the quote below.
"You have everything to do with it! You're the fucking CEO, Richard! Whatever your company does is one hundred percent on you!"


Matt Ross as Gavin Belson, the scheming, ruthless CEO of Hooli. Small-minded, egomaniacal and petty, but his confident facade covers deep insecurities and a need for constant validation. Ross portrays this complex character brilliantly, and with great comedic timing. It's the classic narcissist persona - cruel and vindictive but with a charming and affable exterior.

Suzanne Cryer as Laurie Bream. As with last Season, she comes across as aloof and socially awkward, albeit with a brilliant if somewhat robotic business mind. Could be a force for good or evil, depending on whose side you're on.

Comedian Jimmy O. Yang as Jian Yang. There's an entire hilarious segment where Erlich tries to kick him out but can't. A reliable source of comedy.

Ben Feldman as Ron LaFlamme. They gave this guy more screen time this Season, and it more than paid off. Every time he's on screen, he absolutely kills it as the smarmy laid-back lawyer.
"You remember that shit deal you brought me from Hanneman, and I said, 'Hey, Richie, this is a shit deal,' but you took it anyway because you wanted to do something crazy for once in your life? Well, you basically just loaded a gun and handed it to Hanneman, and Hanneman sold that gun to Raviga, and then Raviga just fucking pistol-whipped you. But hey, at least they're letting you keep your shares and your board seat. You lose a little blood with the dilution for the new CEO, but I've seen worse... like that shit deal you brought me from Hanneman."


Annie Sertich as CJ Cantwell, Code/Rag tech journalist. She did all right, I guess. Came across as really lucky and shrewd, always in the right place and at the right time, scooping up stories she wasn't even intending to cover in the first place!

Chris Williams as Hoover. He turns in a doggedly determined performance as the security guy who wants nothing more than to be useful to Gavin Belson.

Matt McCoy as Pete Monahan, Richard's attorney. Comedy gold. With every appearance, he muses on his past transgressions and gives Richard valuable legal and business advice. All with a dead serious expression. This guy is great!

Bridey Elliott as Winnie. The attractive chick who steals Richard's heart until she starts using spaces instead of tabs. Forgettable.

Ken Lerner as the Bighetti business manager, Arthur Clayman. Gave off a vaguely crooked vibe, but other than that... not really impressed.

Aly Mawji and Brian Tiechnel as the brogrammers at Hooli. This season, they develop a spine and start walking out on Gavin Belson.

Keye Chen as Dang the product designer. Earnest and stoic... a one-note character used more as a prop to bounce jokes off of.

Andy Daly as the doctor who roasts Richard all the time. This season, he seems in an over-the-top jovial mood.

Bernard White is Denpok, Gavin's spiritual advisor. Plays Gavin like a fiddle, preying on his insecurities.

Jill E. Alexander as Patrice. She gets more screen time this Season as the formerly starstruck and faithful employee who stands up for what she believes in, and gets summarily fired by Gavin Belson as a result. It's both tragic and funny at the same time. This decision, of course, comes back to bite Gavin's ass in the end, and ends up saving Pied Piper.

Henry Phillips as John the server guy. Stiff and robotic Mr Ponytail. That's the character and the actor does it so well!

Alice Wetterlund as Carla Walton. It's a pity she only shows up in one scene. The character was sassy and tough, and had a lot of potential.

Chris Diamantopoulos as Russ Hannamen. He only appears in one episode but boy does he make the most of it! His entire dialogue with Richard is exquisitely funny.

Emily Chang as herself. Looking good, but pretty much just a prop.

The Mood

It starts off with Richard being informed that he's just been fired as CEO. The mood is sullen and serious. Angsty, even. Soon, the hi-jinks kick in... and it's back to the wacky world of Silicon Valley we all know and love.

What I liked

Scant minutes into the first episode, Erlich attacks a robotic stag named Bam-bot (yes, you read that right). Has to be seen to be believed. Can this season start off on any higher note?

The "dictionary patch" acronym RIGBY. That's just the highlight, but the entire Dinesh-Gilfoyle conversation about Richard is pure gold.

Erlich comes into the room and starts insulting Jack Barker before Jack totally disarms him by claiming to be a fan of his. But the icing on the cake is when Erlich actually checks a cue card for all the insults he's prepared! For the original (and longer) take, watch this video...




This guy, busy with his mobile phone when Gavin Belson starts saying that one in every five Hooli employees deserves to be fired.


Later, this guy is missing!

The Hooli "brogrammers" accidentally discovering the secrets behind Richard's algorithm when they make hand movements similar to the jerk-off scenario that inspired Richard in the first place.

During the presentation: "But if you can get your data, who else can get it? Spies, thieves, criminals and foreigners." Cut to a still of Dinesh. That made me literally choke from laughter. Fuck!


"At Raviga, we ask the big hairy questions". That said by Laurie Bream over a framed question mark made out of human hair. That was so deliciously wacky I can't even....

The whole gag about Dinesh's gold chain. All the names Gilfoyle calls him just crack me up. Even Jarred gets in on it!

The Pied Piper Team are such passionate engineers that even when they're trying to do the bare minimum on a shitty product, they can't help but make it the best shitty product ever. This time, Gilfoyle of all people starts the ball rolling. Their enthusiasm catches on and even rubs off on Dang the designer!

Gavin Belson hoists himself on his own petard this season, even more than usual. It's like every time he does something petty, like gloat to Richard, or scrub Hooli's search engine of nehative mentions of him, he ends up doing him and Pied Piper a huge favor. It's a recurring theme here, and it rocks!

The Hooli engineers finally having had enough and walking out. One priceless moment is Gavin saying "why?" with an expression of utter bewilderment when one of them expresses disappointment in him.

The segment revolving around Gilfoyle, Dinesh and the ugly jacket is to die for... though seems really pointless, until, spoiler alert, it factors into Erlich's major decision later on.


Silicon Valley finds a clever a natural way to add to the diversity quotient: have an offshore team!

What I didn't

The Skunkworks project was really exciting and all, and they let me down with the big twist at the end. Dammit! It was either totally awesome or totally shitty, and I'm gonna go with the latter because it was such an anticlimax!

"You guys just had to make a great box, did't ya? Couldn't phone it in!" And next moment, the phone rings. OK, that's lame. I expect better from this show.

Richard's inarticulateness during periods of high emotion is lampshaded a couple times, to play into the need for a PR person, which sets up the next plot point involving Cantwell. However, those incidents happen twice in one episode and no mention is made of his blabbering ever again. It's not that I didn't like it, in fact that arc is pretty fucking awesome;  I just think it could have been a lot better executed if it had been referenced early on, perhaps even during earlier seasons. After all, this is Season Three.

The whole tabs-vs-spaces issue is a programmer thing, I know... it just feels like needless filler.

Richard humblebragging about how far he went with Winnie is just painful to watch. So is the whole "m'lady" shtick. We get it, Richard doesn't get a whole lot of action. No need to belabor the point, guys.


Jian Yang's method of prank calling is totally inane and inept. I mean, he does it from the next fucking room?!

Conclusion

More of the same. If you liked Seasons One and Two, this one isn't going to disappoint. You'll especially marvel at how these guys always seem to escape calamity through sheer dumb luck. But if you're expecting career growth on the part of the Pied Piper Team... well, not so much. They basically end up near where they started, but on a positive note.

My Rating

8.5 / 10


Catch this season! It's Pied Piping hot!
T___T

Monday 18 February 2019

Thoughts about the LearnToCode Hashtag

Hashtag "LearnToCode" has been trending on Twitter since the beginning of this month. I don't use Twitter at all, but somehow this came to my attention via news feeds and YouTube videos.

Apparently, this came in response to a number of staff being offloaded by the US media such as Huffington Post and BuzzFeed. Some of these journalists tweeted their newly unemployed statuses, and this was replied by several variations of "Learn to code", with the hashtag and very snarky undertones. Some of those tweets are pretty damn funny, though I'm detecting a certain amount of hostility mixed with the snark.

What's the reason for all this?

Back as far as 2014, President Barack Obama started shutting down coal mining operations. When the now-jobless coal miners, who had been doing this for decades, protested, they were told (rather condescendingly as it turns out) by these reporters to "learn to code", echoing Obama's campaign.

Coal mine.

It's now 2019, and the shoe's on the other foot. Media jobs are being cut, and many of these reporters are freshly unemployed and being told, just as smugly, to "learn to code". Payback's a bitch, ain't it?

Advising others to "learn to code"

I'm of the opinion that people outside of the tech industry, i.e, people who have never coded for a living, have no business giving career advice of this sort. The reporters might have been well-intentioned, but they came off, at best clueless and tone-deaf; at worst, smug and narcissistic.

It's just a very douchebaggy thing to say to someone who has just lost a job he's been doing the past few decades and doesn't know anything else. Yes, theoretically he or she could learn to code. What, then? Simply learning to code is not an end in itself. Software development is not only about coding (though a sizeable part is) and anyone who thoughtlessly simplifies it to merely "coding" does us all a disservice. Even more so, when the people giving this advice, aren't even part of the industry. Yes, Mr Obama, this includes you.

Just shut up already.

So, before you tell others to "learn to code", you'd be well-advised to have done it yourself first, and actually done it professionally. Otherwise, do us actual devs a favor and just shut the hell up.

That said...

I've been laid off before. Twice. And it's never pleasant. (OK, I wasn't being entirely truthful there. The first time I was laid off, it came as a huge relief because the company had become a gigantic pain in the arse. But still... not pleasant.)

Kicking these recently unemployed journalists while they're down, is just needlessly cruel. They've got families to feed, bills to pay and mortgages to service. I've been there. It sucks.

Am I saying I'm sorry that BuzzFeed, HuffPost, et al, had to restructure due to poor revenue? Hell, no. After all the stunts they pulled during the tumultuous 2016 US Presidential Elections, publishing heavily biased news and trying to force the narrative to fit their opinions, I have an exceedingly low opinion of these publications. If this translates to them taking a hit, great! Maybe this will inspire them to raise the level of their so-called journalism.

Trash publication.

Is it a good thing that these journalists (and I'm using the term loosely) no longer get paid to publish their crap? Oh absolutely, yes. The profession deserves better.

On the other hand, is it sad that suddenly a lot of people are jobless? Of course it is. Even if said people are a bunch of feckless assclowns who dabble in the politics of outrage.

So no, I wouldn't shit on them while they're down. Firstly, I'm not a Twitter user and have better use for my time, And secondly, it's just... petty. These ex-journalists may be dicks, but that doesn't mean we need to adhere to their abysmal standards. I'm not saying they don't deserve it, because they damn well do. I'm saying that we should be better than this. And, let's face it, being an ex-employee of a rag like BuzzFeed is already punishment enough.

Reactions

Apparently, Twitter received a lot of complaints about the #LearnToCode hashtag, because Twitter then announced that it would be considered "harrassment" to Tweet "learn to code" (or any variation thereof) to an ex-journalist from BuzzFeed, HuffPost, et al.

Seriously, this boggles the mind. If I were laid off, my topmost priority would be to land another job, pronto. The last thing on my mind would be Twitter trolls and my own hurt feelings. Then again, these are the infamous shit-stirring rabble-rousers from BuzzFeed we're talking about, so this could be some kind of occupational hazard, or something.

Really, take a look in the mirror. Of course it sucks that people are kicking you while you're down. But whose fault is it that people hate you that much?

So what if all this is really, as claimed by Talia Lavin, a harassment campaign by 4Chan users? Lady, you're out of a friggin' job. That should be your first and primary concern. Here's some advice for people who obviously can't handle Social Media: Get. Off. The. Internet.

Editor's Note: After an online search, it appears that this Talia Lavin was the same bright spark who caused a disabled US Marine to be falsely accused of being a Nazi. Who would've thought?

Conclusion

I think people need to lay off that hashtag for a while. It's getting tedious.

As for the newly unemployed, you may want to re-evaluate some of your life choices. I'm not saying you should learn to code, but... perhaps journalism just isn't your thing, if your work in BuzzFeed or HuffPost is anything to go by.

0100110001100101011000010111001001101110
0101010001101111
01000011011011110110010001100101
T___T

Wednesday 13 February 2019

Web Tutorial: The Valentine Heart Animation

It's the Season of Love, folks! Valentine's Day is approaching!

This Valentine's Day, I have a web tutorial that's both simple and exciting. We will be playing with jQuery and jQuery UI.

What, jQuery?

Yes, jQuery. You didn't think I was going to do this the old-fashioned way, did you? Too much like work. Trust me, it'll be fun.

Here we go...

For this, we'll begin with a basic HTML page with a simple black background. Remember to add script links to jQuery and jQuery UI.
<!DOCTYPE html>
<html>
    <head>
        <title>Hearts</title>

        <style>
            body
            {
                background-color: #000000;
            }
        </style>

        <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
        <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>

        <script>

        </script>
    </head>

    <body>

    </body>
</html>


Nothing much to see here... yet.


Let's put a div in the HTML, and give it an id of placeholder.
    <body>
        <div id="placeholder"></div>
    </body>


Now, we style placeholder. margin properties are set for it to be squarely in the middle of the screen. Note that we're not going to define height and width properties yet. Let's also give it a white outline so we can see what we're dealing with.
        <style>
            body
            {
                background-color: #000000;
            }

            #placeholder
            {
                margin: 10% auto 0 auto;
                outline: 1px solid #FFFFFF;
            }
        </style>


And all the divs within it. Yes, there will be divs. All of them will float left. They'll all have orange outlines for visibility.
        <style>
            body
            {
                background-color: #000000;
            }

            #placeholder
            {
                margin: 10% auto 0 auto;
                outline: 1px solid #FFFFFF;
            }

            #placeholder div
            {
                text-align: center;
                float: left;
                outline: 1px solid #FF4400;
            }
        </style>


See that thick white line? That's actually a div with a white outline and a height of 0 pixels (because we didn't specify height) and 100% width (because we didn't specify width).


For the purposes of this web tutorial, we'll do most of our animation from an object, named objAnimation. Now after declaring that object, use the ready() method, but don't place anything in there right now. It's a placeholder for more code to be executed later on. For that to happen, we must first get the objAnimation object in order.
        <script>
            var objAnimation =
            {

            }

            $(document).ready
            (
                function()
                {
                  
                }
            );
        </script>


One of the properties of objAnimation will be a method named generateRandomNo(). You guessed it, it generates a number between min and max.
            var objAnimation =
            {
                generateRandomNo: function(min, max)
                {
                    return Math.floor((Math.random() * (max - min + 1)) + min);
                },
            }


Next, we specify other properties such as color (set to red), a font size and what will be the width and height of each div inside the placeholder div. The property content is set to "x". We'll change it later on; this is just for simplicity.
            var objAnimation =
            {
                generateRandomNo: function(min, max)
                {
                    return Math.floor((Math.random() * (max - min + 1)) + min);
                },
                content: "x",
                color: "rgba(255, 0, 0, 1)",
                fontSize: "30px",
                unitSize: 30,
            }


OK, we're now going to define shape, the next property. It's a 10 x 10 matrix... OK fine, it's an array of arrays. You'll notice that the 1s form a heart! That's not a coincidence.
            var objAnimation =
            {
                generateRandomNo: function(min, max)
                {
                    return Math.floor((Math.random() * (max - min + 1)) + min);
                },
                content: "x",
                color: "rgba(255, 0, 0, 1)",
                fontSize: "30px",
                unitSize: 30,
                shape:
                [
                    [0, 0, 1, 1, 0, 0, 1, 1, 0, 0],
                    [0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
                    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                    [0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
                    [0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
                    [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
                    [0, 0, 0, 0, 1, 1, 0, 0, 0, 0]
                ],
            }


Now for the really big stuff. Declare the next property as render(), a method.
            var objAnimation =
            {
                generateRandomNo: function(min, max)
                {
                    return Math.floor((Math.random() * (max - min + 1)) + min);
                },
                content: "x",
                color: "rgba(255, 0, 0, 1)",
                fontSize: "30px",
                unitSize: 30,
                shape:
                [
                    [0, 0, 1, 1, 0, 0, 1, 1, 0, 0],
                    [0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
                    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                    [0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
                    [0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
                    [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
                    [0, 0, 0, 0, 1, 1, 0, 0, 0, 0]
                ],
                render: function()
                {

                },
            }


Remember this block? Well, you can fill it in now. When the page loads, objAnimation's render() method will run.
            $(document).ready
            (
                function()
                {
                    objAnimation.render();  
                }
            );


Now, inside render(), we declare a few variables. The first, ph, is set to the placeholder div. The rest are set to properties within the same object, thus the use of this.
                render: function()
                {
                    var ph = $("#placeholder");
                    var shape = this.shape;
                    var content = this.content;
                    var color = this.color;
                    var fontSize = this.fontSize;
                    var unitSize = this.unitSize;
                },


Now, we set some properties of ph. What we're trying to create here is a square made out of many smaller squares, to form the shape in shape. (Remember the heart?) First, we'll define the height and width of ph here. Since shape has 10 elements, the placeholder div will contain 10 squares by 10 squares. Each square will be unitSize pixels by unitSize pixels. Therefore placeholder's height and width should be (unitSize x shape.length) pixels.
                    var ph = $("#placeholder");
                    var shape = this.shape;
                    var content = this.content;
                    var color = this.color;
                    var fontSize = this.fontSize;
                    var unitSize = this.unitSize;

                    ph.attr
                    (
                        "style", "width:" + (unitSize * shape.length) + "px;"
                        + "height:" + (unitSize * shape.length) + "px;"
                    );


Aren't we clever... we just turned the thick white line into a box! Specifically, a box (unitSize x shape.length = 30 x 10 = 300) pixels in height and width!


Next, let's iterate through each element of shape...
                    ph.attr
                    (
                        "style", "width:" + (unitSize * shape.length) + "px;"
                        + "height:" + (unitSize * shape.length) + "px;"
                    );

                    $(shape).each
                    (
                        function (index)
                        {

                        }
                    );


Declare variable shapeRow and make it the current element pointed to by index. Then iterate through each element of shapeRow. shape is a two-dimensional array, remember?
                    $(shape).each
                    (
                        function (index)
                        {
                            var shapeRow = shape[index];

                            $(shapeRow).each
                            (
                                function (indexRow)
                                {

                                }
                            );
                        }
                    );


And for each element in shapeRow, we declare a variable piece and set it to a newly created div. Add classes according to the row and column. This will be useful later.
                    $(shape).each
                    (
                        function (index)
                        {
                            var shapeRow = shape[index];

                            $(shapeRow).each
                            (
                                function (indexRow)
                                {
                                    var piece = $("<div></div>");
                                    piece.addClass("row" + index);
                                    piece.addClass("col" + indexRow);
                                }
                            );
                        }
                    );


Then set the attributes of piece, which are the attributes of each and every div within ph! And then append piece to ph using the append() method.
                                function (indexRow)
                                {
                                    var piece = $("<div></div>");
                                    piece.addClass("row" + index);
                                    piece.addClass("col" + indexRow);
                                    piece.attr
                                    (
                                        "style", "color:" + color + ";"
                                        + "font-size:" + fontSize + ";"
                                        + "width:" + unitSize + "px;"
                                        + "height:" + unitSize + "px;"
                                    );

                                    ph.append(piece);
                                }


A white box filled with orange boxes!


OK, next let's fill each div with content.
                                function (indexRow)
                                {
                                    var piece = $("<div></div>");
                                    piece.addClass("row" + index);
                                    piece.addClass("col" + indexRow);
                                    piece.attr
                                    (
                                        "style", "color:" + color + ";"
                                        + "font-size:" + fontSize + ";"
                                        + "width:" + unitSize + "px;"
                                        + "height:" + unitSize + "px;"
                                    );

                                    if (shapeRow[indexRow] == 1)
                                    {
                                        piece.html(content);
                                    }

                                    ph.append(piece);
                                }


You can now see the heart being formed.


Let's get rid of the outlines...
            #placeholder
            {
                margin: 10% auto 0 auto;
                outline: 0px solid #FFFFFF;
            }

            #placeholder div
            {
                text-align: center;
                float: left;
                outline: 0px solid #FF4400;
            }


And change the content property to use the ♥ symbol.
            var objAnimation =
            {
                generateRandomNo: function(min, max)
                {
                    return Math.floor((Math.random() * (max - min + 1)) + min);
                },
                content: "&hearts;",
                color: "rgba(255, 0, 0, 1)",
                fontSize: "30px",
                unitSize: 30,
                shape:


Ain't this just adorable?!

Animating the heart (or, er, hearts)

You didn't think we were done, did you? What we just did was to lay the groundwork for some truly neat stuff.

After we've rendered the heart of hearts, declare variable anim and set it to the current object. Then use the setInterval() function with an interval of, say, 2.5 seconds. Then, in the callback, run the animateObject() method with 0 passed in as the argument.
                    $(shape).each
                    (
                        function (index)
                        {
                            var shapeRow = shape[index];

                            $(shapeRow).each
                            (
                                function (indexRow)
                                {
                                    var piece = $("<div></div>");
                                    piece.addClass("row" + index);
                                    piece.addClass("col" + indexRow);
                                    piece.attr
                                    (
                                        "style", "color:" + color + ";"
                                        + "font-size:" + fontSize + ";"
                                        + "width:" + unitSize + "px;"
                                        + "height:" + unitSize + "px;"
                                    );

                                    if (shapeRow[indexRow] == 1)
                                    {
                                        piece.html(content);
                                    }

                                    ph.append(piece);
                                }
                            );
                        }
                    );

                    var anim = this;

                    setInterval
                    (
                        function()
                        {
                            anim.animateObject(0);
                        },
                        2500
                    );


We'll create the animateObject() method next. It will accept a parameter, animateId.
            var objAnimation =
            {
                generateRandomNo: function(min, max)
                {
                    return Math.floor((Math.random() * (max - min + 1)) + min);
                },
                content: "&hearts;",
                color: "rgba(255, 0, 0, 1)",
                fontSize: "30px",
                unitSize: 30,
                shape:
                [
                    [0, 0, 1, 1, 0, 0, 1, 1, 0, 0],
                    [0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
                    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                    [0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
                    [0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
                    [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
                    [0, 0, 0, 0, 1, 1, 0, 0, 0, 0]
                ],
                render: function()
                {
                    var ph = $("#placeholder");
                    var shape = this.shape;
                    var content = this.content;
                    var color = this.color;
                    var fontSize = this.fontSize;
                    var unitSize = this.unitSize;

                    ph.attr
                    (
                        "style", "width:" + (unitSize * shape.length) + "px;"
                        + "height:" + (unitSize * shape.length) + "px;"
                    );

                    $(shape).each
                    (
                        function (index)
                        {
                            var shapeRow = shape[index];

                            $(shapeRow).each
                            (
                                function (indexRow)
                                {
                                    var piece = $("<div></div>");
                                    piece.addClass("row" + index);
                                    piece.addClass("col" + indexRow);
                                    piece.attr
                                    (
                                        "style", "color:" + color + ";"
                                        + "font-size:" + fontSize + ";"
                                        + "width:" + unitSize + "px;"
                                        + "height:" + unitSize + "px;"
                                    );

                                    if (shapeRow[indexRow] == 1)
                                    {
                                        piece.html(content);
                                    }

                                    ph.append(piece);
                                }
                            );
                        }
                    );

                    var anim = this;

                    setInterval
                    (
                        function()
                        {
                            anim.animateObject(0);
                        },
                        2500
                    );
                },
                animateObject: function (animateId)
                {

                }


Again, declare the variables and set them to the properties of this object. Then let's have an If block to handle animateId being 0.
                animateObject: function (animateId)
                {
                    var shape = this.shape;
                    var color = this.color;
                    var fontSize = this.fontSize;

                    if (animateId == 0)
                    {

                    }
                }


Next, declare changeSize, changeColor and genRan. genRan is set to the generateRandomNo() method of this object. changeSize and changeColor are set to the animateSize() and animateColor() methods of this object respectively.
                animateObject: function (animateId)
                {
                    var shape = this.shape;
                    var color = this.color;
                    var fontSize = this.fontSize;
                    var changeSize = this.animateSize;
                    var changeColor = this.animateColor;
                    var genRan = this.generateRandomNo;

                    if (animateId == 0)
                    {

                    }
                }


We should, of course, create those methods now. We've already created generateRandomNo() earlier. Each of these methods accepts three parameters - obj, delay and color or size. They then run jQuery UI's animate() method from the object referred to by obj. The duration of the animation is set by delay. The property to be manipulated depends on the method. animateColor() animates the color, changing it to color. And animateSize animates the font size, changing it to size pixels.
                animateObject: function (animateId)
                {
                    var shape = this.shape;
                    var color = this.color;
                    var fontSize = this.fontSize;
                    var changeSize = this.animateSize;
                    var changeColor = this.animateColor;
                    var genRan = this.generateRandomNo;

                    if (animateId == 0)
                    {

                    }
                },
                animateColor: function(obj, delay, color)
                {
                    $(obj).animate
                    (
                        {
                            color: color
                        },
                        delay
                    );
                },
                animateSize: function(obj, delay, size)
                {
                    $(obj).animate
                    (
                        {
                            fontSize: size
                        },
                        delay
                    );
                }


Now, back to the animateObject() method. Declare variable colorToChange and set it to a new rgba string by running genRan() for each red, green or blue value. You can use any range of values between 0 to 255. I've chosen these values to keep the heart mostly red or warm colors.
                    if (animateId == 0)
                    {
                        var colorToChange =
                        "rgba(" +
                        genRan(255, 255)
                        + "," +
                        genRan(50, 200)
                        + "," +
                        genRan(50, 200)
                        + ", 1)";
                    }


Now, iterate through each instance of shape.
                    if (animateId == 0)
                    {
                        var colorToChange =
                        "rgba(" +
                        genRan(255, 255)
                        + "," +
                        genRan(50, 200)
                        + "," +
                        genRan(50, 200)
                        + ", 1)";

                        $(shape).each
                        (
                            function (index)
                            {

                            }
                        );
                    }


During each iteration, use the setTimeout() function with an interval of (index x 100). This gives variable delays, which will result in a beautiful pattern. Just trust me on this...

And once the interval is reached, run the changeColor() method using the class name, a delay of 200 milliseconds, and colorToChange!
                    if (animateId == 0)
                    {
                        var colorToChange =
                        "rgba(" +
                        genRan(255, 255)
                        + "," +
                        genRan(50, 200)
                        + "," +
                        genRan(50, 200)
                        + ", 1)";

                        $(shape).each
                        (
                            function (index)
                            {
                                setTimeout
                                (
                                    function()
                                    {
                                        changeColor(".row" + index, 200, colorToChange);
                                    },
                                    index * 100
                                )
                            }
                        );
                    }


Ah, it's changed! Watch! Every 2.5 seconds, the object gradually changes a different color in a vertical cascade!


Now what if we changed it back a slight delay (index x 200) milliseconds later?
                    if (animateId == 0)
                    {
                        var colorToChange =
                        "rgba(" +
                        genRan(255, 255)
                        + "," +
                        genRan(50, 200)
                        + "," +
                        genRan(50, 200)
                        + ", 1)";

                        $(shape).each
                        (
                            function (index)
                            {
                                setTimeout
                                (
                                    function()
                                    {
                                        changeColor(".row" + index, 200, colorToChange);
                                    },
                                    index * 100
                                )
                            }
                        );

                        $(shape).each
                        (
                            function (index)
                            {
                                setTimeout
                                (
                                    function()
                                    {
                                        changeColor(".row" + index, 1000, color);
                                    },
                                    index * 200
                                )
                            }
                        );
                    }


Admit it, this is gorgeous. It changes from red, to a random color, then back to red.


Now, if you got the general idea, we can accelerate past the next part. In the render() method, change this.
                    setInterval
                    (
                        function()
                        {
                            anim.animateObject(1);
                        },
                        2500
                    );


In the animateObject() method, add an If block for if animateId is 1. In fact, go ahead and add If blocks for 2 and 3 as well.
                animateObject: function (animateId)
                {
                    var shape = this.shape;
                    var color = this.color;
                    var fontSize = this.fontSize;
                    var changeSize = this.animateSize;
                    var changeColor = this.animateColor;
                    var genRan = this.generateRandomNo;

                    if (animateId == 0)
                    {
                        var colorToChange =
                        "rgba(" +
                        genRan(250, 255)
                        + "," +
                        genRan(50, 200)
                        + "," +
                        genRan(50, 200)
                        + ", 1)";

                        $(shape).each
                        (
                            function (index)
                            {
                                setTimeout
                                (
                                    function()
                                    {
                                        changeColor(".row" + index, 200, colorToChange);
                                    },
                                    index * 100
                                )
                            }
                        );

                        $(shape).each
                        (
                            function (index)
                            {
                                setTimeout
                                (
                                    function()
                                    {
                                        changeColor(".row" + index, 1000, color);
                                    },
                                    index * 200
                                )
                            }
                        );
                    }

                    if (animateId == 1)
                    {

                    }

                    if (animateId == 2)
                    {

                    }

                    if (animateId == 3)
                    {

                    }


This next one repeats what we did earlier, accept the transition is from left to right! Copy and paste the code from the previous If block, but instead on operating on shape, operate on the first element of shape. Fittingly, we'll change index to indexCol to reflect what we're doing here - operating on columns. To that end, also make sure the class names are changed in the calls to changeColor().
                    if (animateId == 1)
                    {
                        var colorToChange =
                        "rgba(" +
                        genRan(250, 255)
                        + "," +
                        genRan(50, 200)
                        + "," +
                        genRan(50, 200)
                        + ", 1)";

                        $(shape[0]).each
                        (
                            function (indexCol)
                            {
                                setTimeout
                                (
                                    function()
                                    {
                                        changeColor(".col" + indexCol, 200, colorToChange);
                                    },
                                    indexCol * 100
                                )
                            }
                        );

                        $(shape[0]).each
                        (
                            function (indexCol)
                            {
                                setTimeout
                                (
                                    function()
                                    {
                                        changeColor(".col" + indexCol, 1000, color);
                                    },
                                    indexCol * 200
                                )
                            }
                        );
                    }


Great, right?!


Change this again...
                    setInterval
                    (
                        function()
                        {
                            anim.animateObject(2);
                        },
                        2500
                    );


This next one is also a transition from left to right, but this time, it uses the changeSize() method, thus changing the size! Kind of like a Kallang Wave. Copy the code from the previous If block, and instead of using the changeColor() method, use the changeSize() method. Of course, instead of colorToChange, declare and use sizeToChange. sizeToChange here is a size between 10 to 25 pixels, but feel free to implement your own.
                    if (animateId == 2)
                    {
                        var sizeToChange = genRan(10, 25) + "px";

                        $(shape[0]).each
                        (
                            function (indexCol)
                            {
                                setTimeout
                                (
                                    function()
                                    {
                                        changeSize(".col" + indexCol, 500, sizeToChange);
                                    },
                                    indexCol * 100
                                )
                            }
                        );

                        $(shape[0]).each
                        (
                            function (indexCol)
                            {
                                setTimeout
                                (
                                    function()
                                    {
                                        changeSize(".col" + indexCol, 500, fontSize);
                                    },
                                    indexCol * 200
                                )
                            }
                        );
                    }


Sweet!


Change this again!
                    setInterval
                    (
                        function()
                        {
                            anim.animateObject(3);
                        },
                        2500
                    );


This one uses both the changeSize() and changeColor() methods, passing in random colors and sizes respectively! I'll let you figure out on your own how this is done...
                    if (animateId == 3)
                    {
                        $(shape).each
                        (
                            function (index)
                            {
                                $(shape[index]).each
                                (
                                    function (indexCol)
                                    {
                                        setTimeout
                                        (
                                            function()
                                            {
                                                var colorToChange =
                                                "rgba(" +
                                                genRan(250, 255)
                                                + "," +
                                                genRan(50, 200)
                                                + "," +
                                                genRan(50, 200)
                                                + ", 1)";

                                                var sizeToChange = genRan(10, 65) + "px";

                                                changeSize(".row" + index + ".col" + indexCol, 500, sizeToChange);
                                                changeColor(".row" + index + ".col" + indexCol, 300, colorToChange);
                                            },
                                            0
                                        )
                                    }
                                );
                            }
                        );

                        $(shape).each
                        (
                            function (index)
                            {
                                $(shape[index]).each
                                (
                                    function (indexCol)
                                    {
                                        setTimeout
                                        (
                                            function()
                                            {
                                                changeSize(".row" + index + ".col" + indexCol, 500, fontSize);
                                                changeColor(".row" + index + ".col" + indexCol, 300, color);
                                            },
                                            100
                                        )
                                    }
                                );
                            }
                        );
                    }


Groovy! There are so many different ways you could play with this!


One last change. Instead of passing in an arbitrary number as an argument, pass in a random number between 0 and 3. This way, you get a random animation every 2.5 seconds.
                    setInterval
                    (
                        function()
                        {
                            anim.animateObject(anim.generateRandomNo(0, 3));
                        },
                        2500
                    );


We're done!

I went a bit overboard with the animation, but damn that felt good. We could have done it without jQuery, but this web tutorial might have taken twice as long. So yeah, I think it was worth it.

In my heart of hearts, I salute you!
T___T