Thursday 30 January 2020

Wuhan Coronavirus: A techie's random thoughts

The outbreak has arrived. It's been a week of worldwide panic as the 2019-nCoV, otherwise known as the Wuhan Coronavirus, started infectng the city-dwellers of Wuhan in the province of Hubei, China. Cases of infection soon hit Singapore and the rest of the world as Wuhan went into lockdown mode.

Contagion.

And this is of interest to me, why?

Well, firstly, here's the personal part. A few months ago, my Chinese national wife returned to her hometown of Zunyi in the province of Guizhou to celebrate the Lunar New Year with her family. Shortly after the outbreak in Wuhan began, there were three reported cases of infection in Guizhou. And as such, it's my matrimonial duty to stay on top of things. Underneath it all is the nagging fear that if things go really south, I could become a bereft husband instead of merely an anxious one.

Yes, this is how I manage anxiety - by blogging. Eat me.

Secondly, as a Singaporean, I have a vested interest in not having the Wuhan Coronavirus take root here. Although it may be a little late for that. As of today, the count of infected cases in Singapore has risen to ten, though thankfully there have been no deaths so far. More on that later...

And lastly, response to this outbreak has produced some truly neat stuff. I'd like to point to this real-time updated website by thebaselab.co which is a great example of a mobile-friendly API-data driven site.

Screenshot.


A cursory look at their source tells me it was quickly hammered out with Twitter Bootstrap and Google APIs. Impressive work. I might have slipped them a few bucks as a token of appreciation for their trouble, and if you found the information useful, you might want to do the same.

How Singaporeans have handled the situation so far

I've seen people step up in recent weeks.

Some have expressed concern for their fellow citizens and distributed supplies such as hand sanitizer and personal thermometers.

Singaporeans stepping up.


An ex-classmate of mine went the extra mile to source for surgical masks so that retailers would be limited in their ability to profiteer off this emergency. At this point, I'm not even sure the masks will be enough to prevent the spread, but come on, that effort has got to be worth something.

Some have done their part to combat the flood of fake news, conspiracy theories and stirred hysteria online, analyzing this outbreak in relation to previous ones such as SARS and MERS. The numbers, so far, have been somewhat reassuring.

Other Singaporeans... not so much.

There's been a petition going round to refuse entry to all Chinese nationals and travelers from China. The latter I could understand (even though that would not be in my personal interests, because obviously if my wife returned, she would be returning from China), but all Chinese nationals? Not all people with a Chinese passport have been to China in the past year. Some stay abroad for, y'know, work and shit. What, all Chinese nationals are suspect by virtue of simply being Chinese nationals? You know this looks suspiciously xenophobic, right? We're all understandably fearful for our families and all, but let's not get stupid.

This is what the SQL statement would look like. Imagine if tblArrivals was a relational table of all incoming people to our airport.

SELECT * FROM tblArrivals WHERE Nationality = 'PRC' and CountryOfOrigin = 'CH'

Number of records returned from that query? Definitely more than 1.4 billion. Because we would be including non-China citizens who just happened to be flying in from China.

Also, petitions don't work in Singapore. Period. A million of us could sign a petition and you would still have a better chance of winning the lottery twice in a row, than of pressuring the Singapore Government to do what we want. The Singapore Government will do what it deems fit, when it deems fit, which is pretty much their job in the first place. And honestly, if we knew better, we would be in governance.

Simply stopping incoming flights from Wuhan wouldn't accomplish anything. There are no incoming flights from Wuhan. As mentioned earlier, the city, indeed most of Hubei, is in lockdown.

What the Singapore Government has done, is stop entry or transit for new visitors who have traveled to Hubei in the last 14 days, as well as holders of Chinese passports issued in Hubei. This is a far more measured and reasonable approach.

This SQL query would look like this. In addition to the tblArrivals table, let's have a tblTravelHistory table.
SELECT * FROM tblArrivals WHERE PassportPlaceOfIssue = 'Hubei' AND ArrivalId IN
(
    SELECT TravellerId FROM tblTravelHistory WHERE Area = 'Hubei' AND Country = 'PRC' AND DateDeparted BETWEEN DATEADD(d, -14, GETDATE()) AND GETDATE()
)

That's a far smaller number than an absolute blanket ban on all Chinese nationals. Because if you really only want to prevent possible carriers from entering Singapore, remember that it's not actually their nationality that matters, but where they've been recently. A British visitor could be transiting from Malaysia, for example, having flown in from Hubei. A Chinese national could have been working in Malaysia for the past year and is now attempting to visit his cousin in Singapore. Who's the bigger risk?

Sorry, I'm rambling...

Did I mention that I'm anxious? God yes, I really fucking am.

The wife assures me that she's feeling fine. The streets are quiet and most of the city are staying indoors. The supermarkets are still open, though there's not much variety at the moment. I'm not a superstitious man by nature, but fingers crossed!

To your health,
T___T

Saturday 25 January 2020

Film Review: Silicon Valley Season 5

Time for more Silicon Valley, and this Season ranks up there as one of my favorites. Possibly because there's so much less padding and we finally see Pied Piper in a place of some progress after watching them struggle for the past four Seasons.



This is the first Season where TJ Miller isn't around to play Erlich Bachmann, and to be honest I was expecting the vibe to change considerably. Well, it did, but the Season is not significantly worse off for it.

Warning

It's crude, it's rude, it's Silicon Valley! But to be honest, without Erlich around, the uncouthness factor has gone down a whole lot. It's still pretty fucking profane, though.

The Premise

After the events of last Season where they avoided a major legal and moral crisis, Pied Piper is making a little headway as they move into a new office and continue their partnership with Raviga. But Gavin Belson is back, and looking to sabotage their efforts by any means necessary.

The Characters

Thomas Middleditch plays Richard Hendricks, CEO of Pied Piper. There's a quintessential Richard scene where he admits that he's no orator, then proceeds to inspire by example instead, i.e, coding himself into a coma. Richard's far from perfect though. While he seems to have overcome his moral myopia from last Season, he still has a bit of a mean streak. The last episode of the Season features him, at different points, doing a mocking jerky dance while chanting "kiss my piss"! It's awkward in a way only Middleditch seems to be able to pull off. Having seen Middleditch make a cameo appearance in Zombieland: Double Tap recently, more of that earnest geeky awkwardness is on display here.

Zach Woods as Jared Dunn. As in last Season, he's the conscience of the team and this comes into play in the first few episodes where he handles an impending lawsuit like a pro, acting with a lot more maturity and humility than we've seen from the rest of the team combined. The moment where Richard promotes him to COO is a huge heartwarming moment. Couldn't happen to a greater guy.

Of course, Jared wouldn't be Jared if he didn't also come with a huge heaping of neuroses, and Zach Woods plays this to the hilt. Whether it's giving the team pep talks or breathing down the intern's neck, Jared is an integral part of the show's ensemble.

Kumail Nanjiani as Dinesh Chugtai, awkward as ever and trying way too hard to be cool. His insecurities and immaturity are really played up this Season, to almost unrealistic levels. The Tesla subplot was one thing, but that little self-imposed code competition with Gilfolyle really ramped it up. He's become increasingly harder to like as a character.

Martin Starr plays snarky nihilistic Satanist Bertram Gilfoyle with the same deadpan awesomeness he's brought to the role from Day One. While Erlich is no longer around for Gilfoyle to mispronounce his name, I still get the kick out of hearing Gilfyle call Richard "Dick".

And while this Season he continues his longstanding feud with Dinesh, there's also a lot more for this character to do and he plays quite a significant part in the last few episodes.

Amanda Crew as Monica Hall. Monica plays the same role to the team as she has done the past several Seasons - as a voice of reason and support from upper Management. This role appears to have been ramped up in the absence of Erlich - no longer is she even partially defined by borderline sexual harassment from Erlich, there's a certain assertiveness about her I haven't seen before. She tells Gilfoyle to "sit the fuck down", and he does it. And just seconds later, when Gilfoyle delivers one of his snarky one-lines, she shuts him down with nothing more than a withering look. I mean, wow.

I get this feeling that she's gearing up to take Erlich's place in his absence, and I gotta say, they could do a lot worse!

Matt Ross as Gavin Belson, the scheming, ruthless CEO of Hooli. Overall, Gavin doesn't seem to have learned anything from his growth in last Season. He's still megalomaniacal and petty. If anything, he's relapsed and gotten worse. This makes me feel like the entirety of last Season's redemption arc for him was a huge waste of time.

Comedian Jimmy O. Yang as Jian Yang. Oh. My. God. Jimmy O.Yang outdoes himself this Season as he plays the conniving Chinaman with delicious craftiness. That baleful stare, that deadpan snark... there's a whole lot more of Jian Yang this Season and the show's better for it!

Suzanne Cryer has a fantastic Season playing Laurie Bream. Honestly, this is one hell of a capable woman who reveals new levels of human weakness while retaining the impersonal robotic ruthlessness that made her so badass as a character. Cryer really outdid herself here as she portrays Laurie in a new light - as an antagonist, but one who is still somehow likable.

Neil Casey as Colin, K-Hole boss. Comes across as an Erlich-lite - a brash and cocky boss, but very toned down from Erlich levels of hubris. Learns some humility after Laurie Bream ousts him from his own company.

Tzi Ma as Yao, China boss. A scheming business owner who's meant to portray the stereotypical ruthless China businessman.

Ben Feldman puts in a shift as Ron LaFlamme, Pied Piper's lawyer. What can I say, I love seeing this guy on-screen. His involvement this Season isn't quite as pervasive as it was the past couple Seasons, but he milks every moment he gets.

Josh Brener appears once in a while as Nelson "Big Head" Bighetti. Dim-witted as always, his habit of failing at the most basic things turns out to help the team midway through the Season. But I kind of feel his dumbness is overplayed, and his presence kind of forced towards the end.

Tony Winters is Mayor Wilkins of Goldbriar. He does a fair job as the harried politician who accedes to Gavin's demands.

Keye Chen makes a short but welcome appearance as Dang the designer. There's nothing much to say as the actor kind of phones it in. To be fair, he doesn't have a whole lot to do.

Aaron Sanders as Holden the intern. Young, insecure, and utterly terrified of Jared. By the time the Season wraps up, he's been reduced to a quivering wreck.

A.D Miles as Dee Dee.  He's this frazzled gay developer, and the twist is that he's not ashamed of his sexual orientation, but has to keep his religion under wraps. He and Thomas Middleditch play off each other's characters to hilarious effect.

Chris Diamantopoulos is in only one episode as Russ Hannemann, and what a welcome five minutes' worth of fresh air that is. His appearance, seemingly somewhat superfluous with the crassness quota already previously ably handled by Erlich, adds a much needed jab of levity.

Jeff Elam and Gita Reddy as Tom and Viola, bosses of smart refrigerator company Seppen. They're not very technically savvy and don't come across as greedy or vindictive. Even their lawsuit against Pied Piper didn't look like it was driven by malice. It was only Gavin Belson's idea. They see reason pretty quickly though... and mostly because of Gilfoyle's tech cunning and Jared's negotiation smarts.

Chris Aquino as Danny, Sliceline guy turned Pied Piper employee. Deadpan and... well, just deadpan.

Rachel Rosenbloom as Becky, Optimoji girl turned Pied Piper employee. Snarky and also deadpan.

Krishna Smitha as Priyanka, Tesla buyer Indian girl. She and Kumail Nanjiani do a decent back-and-forth at times.

Todd Louiso as Ariel Eklow, the creepy boss of Eklow Labs. Suzanne Lenz as the robot Fiona whom, according to Colin, he's "definitely fucking".
Armen Weitzman is Jeff Washburn the mole. Scruffy, unkempt and totally dazed most of the time.

Bernard White gets in halfway through the Season to play Denpok, Gavin's former spiritual advisor. It appears that his full name is Denpok Singh. Damn, he's supposed to be Indian?! I totally never caught that! Seriously though, unlike previous Seasons, his presence does very little for the show. Maybe he should have stayed gone.

Andy Daly as the unnamed doctor. Well, not so unnamed anymore. It took several Seasons, but now we know his name is Crawford. And this is also the first time he's actually gotten annoyed with Richard - usually he's the one doing the annoying. And it's satisfying as heck. And all it took was Richard's legendary pedant!

Dan Mintz as Dana, CEO of Quiver. Quiet, stiff and awkward. Gives off creepy vibes, but turns out to be pretty misunderstood.

Benjamin Koldyke as Ben Burkhardt, Dana's COO. A rugged, good-looking middle-aged guy who talks a good game (Radical Candor, Ruinous Empathy, etc) but turns out to be a douchebag. His first piece of advice during the Seppen crisis is to throw Gilfoyle under the bus.

Chloe Wepper as Kira Pickford, boss of Optimoji. Compassionate boss to her staff, but with a take-no-shit style of negotiation.

Andrew Leeds as Duncan, boss of Sliceline. Lame and dorky. Richard thinks he's an asshole, but there are striking similarities in the dork department!

Henry Philips as John the server guy. He only has one appearance in the final episode, but boy did I whoop when he came on!

Jill E. Alexander has one appearance as a returning Patrice, who promptly gets fired again. I laughed a bit too hard at that one.

The Mood

Things move pretty slowly the first few episodes, with Pied Piper adjusting to their new office and new crew, and dealing with all the little obstacles that Gavin Belson throws their way. The little subplots sometimes add to the bloated feeling, but towards the last two episodes, things pick up with terrifying speed. It's like all plot points are being crammed into that one last hour of TV. This serves as a shot of adrenaline to what's ultimately quite an exciting conclusion.

What I liked


Richard introduces the guys to the new workspace and their horrified reaction is priceless. Even Gilfoyle is shaken. Gilfoyle! Special mention to Dinesh's histronics paired beside Gilfoyle's quiet snark. That's barely five minutes into the first episode and already Kumail Nanjiani and Martin Starr are showing great chemistry together.


"We're not dicking around," says Gilfoyle when he, Dinesh and Richard are discussing potential new hires. Cut to the above shot. Juvenile? Yes? Worth a chuckle? Also yes.




The graphic work for Sliceline and Optimoji is bitching! I like how the show producers put that kind of effort into the background.



Jian Yang's Chinese translation for "New Pied Piper" is actually "new Happy Internet"!


Well, if you can actually read Chinese, you're in for an interesting time.

That scene where the team confronts Jeff about being the mole. Jared is livid and drops F-bombs. Dinesh is sweetly naive and acts all betrayed. And Gilfoyle? Gilfoyle destroys his computer with a bolt gun, then calmly destroys his guitar just out of sheer spite.

Gavin Belson makes a throwaway remark and his team of sycophants assign it way more meaning than was ever intended. It leads to a sideplot which takes up screen time, but totally worth it in the end.

The entire subplot about Dee Dee being a Christian pokes delicious fun at the real Silicon Valley's liberal hangups. In fact, by extension, the entire show does. Ron LaFlamme and Jared express concern about Richard's possible racism and being gay is considered perfectly mainstream, but Christianity? Cue the hysteria.


Not only was the entire subplot about Gavin Belson's signature darn funny, this shot as he's unveiling the Gavin Belson Signature Box Three to the world... with his arms raised and his head bowed, he really looks like he's lifting up a gigantic penis and straining under the weight. Also, the subtext: Gavin Belson is a huge dick.


I don't know how much effort it must have taken to make Jian Yang's knockoff of Pied Piper to look this lame, but I love it!

The entire segment detailing Gavin's stay in China. He finds himself stonewalled by Jian Yang.
"If oil company wants to buy your house, there is oil underneath."


The final series of twists and double-crosses has to be seen to be believed. Richard wins by exploiting Gavin Belson's utterly predictable penchant for treachery. It's the final nail in Gavin's coffin for now as he loses, once again, to the same skinny geek as he's done for the past several Seasons, and as usual due to his own failings as a person.


That last parting pan-out shot that shows just how big Pied Piper is about to grow. This is their new office. It's a happy ending; well, happier than any ending they've ever had at Season end. This is an unambiguous victory. In fact, their triumph so mirrors the astounding success at the end of Season One that Richard does exactly what he did back then - puke his guts out.

What I didn't

Richard spending 19,000 dollars on vengeance is a little too close to Gavin Belson's Modus Operandi. Not that it wasn't clever or funny, but I thought he'd grown past that jerk phase... and even if he hadn't, it seemed just a little too early in the Season for stuff like that.



I felt like entirely too much time was spent on Dinesh and his Tesla. Yes, even with its relevance at the end of the Season. Gilfoyle's choice of ride was a little more interesting, but still didn't compensate adequately for the sheer banality of the subplot.

Richard acting like a blushing virgin when Ben proposes being his COO. Like, totally cringe-city.

I don't know if this is deliberate, but the Mandarin spoken by both Gavin Belson and Laurie Bream is painful. Mr Yao's English is actually better than their Mandarin. Fuck, Jian Yang's shitty English is better than their Mandarin!


Richard cosplaying as The Pied Piper. Oh sweet Jesus... why?

Holden screaming "lock them up" like a lunatic. Look, I'm all for mocking Donald Trump supporters (and the douchey Hillary Clinton supporters too, while I'm at it), but this smacks of pandering. Can we keep lame USA politics out of tech shows, please?

Gilfoyle and Monica seem like an unlikely pair, but they work very well together. What I don't like is springing their chemistry on the viewers on the last fucking episode of the Season. Come on!

Conclusion


Do I like this Season? That's a resounding yes. Not only do we get more of the same general tech-related hilarity, the team finally seems to be making strides after five entire Seasons of floundering. And when you consider that this Season is missing Erlich Bachmann, that's not a small thing. TJ Miller's absence was felt... but not that keenly.

This Season felt a lot more fast-paced because there were noticeably fewer tiny subplots to keep track of, and most of those subplots actually ended up, like in previous Seasons, contributing to the final outcome. Though I really could have done without the Telsa thing. What an absolute time-waster.

Looking forward to the further adventures of the Pied Piper team!

My Rating

9 / 10

Till the next Season arrives, Kiss My Piss!
T___T

Wednesday 22 January 2020

Web Tutorial: Animated CNY SVG

Squeak!

The Year of the Rat is upon us, and I'm still high on the buzz of playing with Scalable Vector Graphics, otherwise known as SVGs. In fact, today I want to introduce another concept in SVG animation - timed animations!

Sure, all animations are timed one way or another, but what if you needed a sequence of one-time animations? Like the one below. (refresh this page if you want to view it again)


HAPPY YEAR OF THE RAT


The letters "2020" moved and morphed into a stylized rat head. Awesome, right?! I'm going to show you how to get this done.

First, we'll need a HTML page with an orange background. For good measure, set default font size too.
<!DOCTYPE html>
<html>
    <head>
        <title>CNY 2020</title>

        <style>
            body
            {
                background-color: #FF4400;
                font-size: 10px;
            }
        </style>
    </head>
   
    <body>

    </body>
</html>


Then we need to have a div to contain the SVG. Give it an id of svgContainer. Let's make it 800 by 400 pixels, and give it a red border and align it middle of the screen.
<!DOCTYPE html>
<html>
    <head>
        <title>CNY 2020</title>

        <style>
            body
            {
                background-color: #FF4400;
                font-size: 10px;
            }

            #svgContainer
            {
                width: 800px;
                height: 400px;
                margin: 10% auto 0 auto;
                outline: 1px solid #FF0000;
            }
        </style>
    </head>
   
    <body>
        <div id="svgContainer">

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


Great, here we go!


Next up is the SVG itself. It should go inside the container.
<div id="svgContainer">
    <svg>

    </svg>
</div>


The next tricky bit is the "2020". We need to animate this sucker later, so we can't use text. We need to draw it out. First, add this into the CSS, so the lines we draw will be nice, thick and red.
        <style>
            body
            {
                background-color: #FF4400;
                font-size: 10px;
            }

            #svgContainer
            {
                width: 800px;
                height: 400px;
                margin: 10% auto 0 auto;
                outline: 1px solid #FF0000;
            }

            svg
            {
                width: 800px;
                height: 400px;
            }

            line, ellipse, path, text
            {
                stroke-width: 3em;
                stroke: rgba(255, 0, 0, 1);
                fill: none;
            }
        </style>


The "0"s are easy enough - just use ellipses! Make them tall, and spread them out to make room for the "2"s.
<div id="svgContainer">
    <svg>
        <ellipse cx="335" cy="200" rx="40" ry="100">

        </ellipse>

        <ellipse cx="615" cy="200" rx="40" ry="100">

        </ellipse>
    </svg>
</div>


Like I said - easy.


Each "2" will use a horizontal straight line...
<div id="svgContainer">
    <svg>
        <line x1="140" y1="300" x2="250" y2="300">

        </line>

        <ellipse cx="335" cy="200" rx="40" ry="100">

        </ellipse>

        <line x1="415" y1="300" x2="525" y2="300">

        </line>

        <ellipse cx="615" cy="200" rx="40" ry="100">

        </ellipse>
    </svg>
</div>


Do you see it taking shape?


And now let's have a vertical line, using a path tag instead of a line tag. Each path goes 200 pixels vertically down from the origin point.
<div id="svgContainer">
    <svg>
        <path d="M 150 100 l 0 200">

        </path>

        <line x1="140" y1="300" x2="250" y2="300">

        </line>

        <ellipse cx="335" cy="200" rx="40" ry="100">

        </ellipse>

        <path d="M 425 100 l 0 200">

        </path>

        <line x1="415" y1="300" x2="525" y2="300">

        </line>

        <ellipse cx="615" cy="200" rx="40" ry="100">

        </ellipse>
    </svg>
</div>


"LOLO"? Patience, we'll get there!


Let's apply a curve to the paths. The curves will pull the path 200 pixels to the right, and occur 75 pixels down.
<div id="svgContainer">
    <svg>
        <path d="M 150 100 q 200 75 0 200">

        </path>

        <line x1="140" y1="300" x2="250" y2="300">

        </line>

        <ellipse cx="335" cy="200" rx="40" ry="100">

        </ellipse>

        <path d="M 425 100 q 200 75 0 200">

        </path>

        <line x1="415" y1="300" x2="525" y2="300">

        </line>

        <ellipse cx="615" cy="200" rx="40" ry="100">

        </ellipse>
    </svg>
</div>


Presto! Two "2"s! Here's your "2020".


Time to animate!

Of all the digits, only the second "2" will be mostly stationary. For starters, let's rotate the first "2". Add an animate tag within the path tag which defines the curve of the "2". Give it an id of animateFlipCurve.
<path d="M 150 100 q 200 75 0 200">
    <animate
        id="animateFlipCurve"
    />
</path>


What we're going to animate is the d attribute. While the origin point and end point remains the same, the curve now goes negative 200 pixels horizontally.
<path d="M 150 100 q 200 75 0 200">
    <animate
        id="animateFlipCurve"
        attributeName="d"
        from="M 150 100 q 200 75 0 200"
        to="M 150 100 q -200 75 0 200"
    />
</path>


The fill attribute, set to "freeze", means that the curve is stuck this way after the current animation ends. Set it to begin after 2 seconds, by setting the begin attribute. Set the duration to half a second, and ensure that it runs only once by setting the repeatCount property.
<path d="M 150 100 q 200 75 0 200">
    <animate
        id="animateFlipCurve"
        attributeName="d"
        from="M 150 100 q 200 75 0 200"
        to="M 150 100 q -200 75 0 200"
        fill="freeze"
        begin="2s"
        dur="0.5s"
        repeatCount="1"
    />
</path>


Let's take a look. Does the first "2" change shape after two seconds?


Now that we've flipped the curve, we want to move it horizontally so that it forms the rat's head with the second "2". For this, we use the animateMotion tag. Give it an id of animateMoveCurve.
<path d="M 150 100 q 200 75 0 200">
    <animate
        id="animateFlipCurve"
        attributeName="d"
        from="M 150 100 q 200 75 0 200"
        to="M 150 100 q -200 75 0 200"
        fill="freeze"
        begin="2s"
        dur="0.5s"
        repeatCount="1"
    />

    <animateMotion
        id="animateMoveCurve"
    />
</path>


Now, set the dur and fill attributes.
<path d="M 150 100 q 200 75 0 200">
    <animate
        id="animateFlipCurve"
        attributeName="d"
        from="M 150 100 q 200 75 0 200"
        to="M 150 100 q -200 75 0 200"
        fill="freeze"
        begin="2s"
        dur="0.5s"
        repeatCount="1"
    />

    <animateMotion
        id="animateMoveCurve"
        fill="freeze"
        dur="0.5s"
    />
</path>


Ensure that this only starts moving after the curve is flipped, by setting the begin attribute. animateFlipCurve is the animation object to take reference form, and we use its end property here.
<path d="M 150 100 q 200 75 0 200">
    <animate
        id="animateFlipCurve"
        attributeName="d"
        from="M 150 100 q 200 75 0 200"
        to="M 150 100 q -200 75 0 200"
        fill="freeze"
        begin="2s"
        dur="0.5s"
        repeatCount="1"
    />

    <animateMotion
        id="animateMoveCurve"
        fill="freeze"
        begin="animateFlipCurve.end"
        dur="0.5s"
    />
</path>


Next, we'll want to define the path upon which the curve will travel. (0, 0) is the origin and the next point is (250, 0) that means that the curve will travel 20 pixels right.
<path d="M 150 100 q 200 75 0 200">
    <animate
        id="animateFlipCurve"
        attributeName="d"
        from="M 150 100 q 200 75 0 200"
        to="M 150 100 q -200 75 0 200"
        fill="freeze"
        begin="2s"
        dur="0.5s"
        repeatCount="1"
    />

    <animateMotion
        id="animateMoveCurve"
        fill="freeze"
        begin="animateFlipCurve.end"
        dur="0.5s"
        path="M 0 0 l 250 0"
    />
</path>


Kind of messy, but it's working!


Now, we want the horizontal base of the "2" to move with the curve, right? So we add an animateMotion tag within the line tag. The begin, dur and fill attributes will mirror those of animateMoveCurve. This does not equire an id because no other animation will take reference from this one.
<path d="M 150 100 q 200 75 0 200">
    <animate
        id="animateFlipCurve"
        attributeName="d"
        from="M 150 100 q 200 75 0 200"
        to="M 150 100 q -200 75 0 200"
        fill="freeze"
        begin="2s"
        dur="0.5s"
        repeatCount="1"
    />

    <animateMotion
        id="animateMoveCurve"
        fill="freeze"
        begin="animateFlipCurve.end"
        dur="0.5s"
        path="M 0 0 l 250 0"
    />
</path>

<line x1="140" y1="300" x2="250" y2="300">
    <animateMotion
        dur="0.5s"
        begin="animateFlipCurve.end"
        fill="freeze"
    />
</line>


The path here means that the line will travel 160 pixels to the right.
<line x1="140" y1="300" x2="250" y2="300">
    <animateMotion
        dur="0.5s"
        begin="animateFlipCurve.end"
        fill="freeze"
        path="M 0 0 l 160 0"
    />
</line>


Do you see it?


Moving the "0"s to form the ears

This will be comparatively easy. In the first ellipse create two animate tags. The first one has an id of animateEllipseSize1 (because another animation will take reference from it soon) and the second will have no id. They will effectively resize the ellipse will modifying the ry and rx attributes of the ellipse to 70 pixels. Both will be set to begin after the animateFlipCurve animation ends. As with the rest, set the fill attribute to "freeze" and also set the dur and repeatCount attributes.
<ellipse cx="335" cy="200" rx="40" ry="100">
    <animate
        id="animateEllipseSize1"
        attributeName="ry"
        from="100"
        to="70"
        fill="freeze"
        begin="animateFlipCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animate
        attributeName="rx"
        from="40"
        to="70"
        fill="freeze"
        begin="animateFlipCurve.end"
        dur="0.5s"
        repeatCount="1"
    />
</ellipse>

<path d="M 425 100 q 200 75 0 200" />

<line x1="415" y1="300" x2="525" y2="300">

</line>

<ellipse cx="615" cy="200" rx="40" ry="100">

</ellipse>


Do the same for the other ellipse. Only, the id should be set to animateEllipseSize2.
<ellipse cx="335" cy="200" rx="40" ry="100">
    <animate
        id="animateEllipseSize1"
        attributeName="ry"
        from="100"
        to="70"
        fill="freeze"
        begin="animateFlipCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animate
        attributeName="rx"
        from="40"
        to="70"
        fill="freeze"
        begin="animateFlipCurve.end"
        dur="0.5s"
        repeatCount="1"
    />
</ellipse>

<path d="M 425 100 q 200 75 0 200" />

<line x1="415" y1="300" x2="525" y2="300">

</line>

<ellipse cx="615" cy="200" rx="40" ry="100">
    <animate
        id="animateEllipseSize1"
        attributeName="ry"
        from="100"
        to="70"
        fill="freeze"
        begin="animateFlipCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animate
        attributeName="rx"
        from="40"
        to="70"
        fill="freeze"
        begin="animateFlipCurve.end"
        dur="0.5s"
        repeatCount="1"
    />
</ellipse>


Try it. Did the "0"s become circles?


So now that both ellipses have been resized, let's move them to form ears! Add two more animate tags inside the first ellipse. They will both take reference from animateEllipseSize1, beginning only when it ends. Then modify the cy and cx attributes to move the ellipse towards the top left till it aligns neatly to the side of the "rat head". You may need to engage in a bit of trial and error here.
<ellipse cx="335" cy="200" rx="40" ry="100">
    <animate
        id="animateEllipseSize1"
        attributeName="ry"
        from="100"
        to="70"
        fill="freeze"
        begin="animateFlipCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animate
        attributeName="rx"
        from="40"
        to="70"
        fill="freeze"
        begin="animateFlipCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animate
        attributeName="cy"
        from="200"
        to="100"
        fill="freeze"
        begin="animateEllipseSize1.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animate
        attributeName="cx"
        from="335"
        to="265"
        fill="freeze"
        begin="animateEllipseSize1.end"
        dur="0.5s"
        repeatCount="1"
    />
</ellipse>

<path d="M 425 100 q 200 75 0 200" />

<line x1="415" y1="300" x2="525" y2="300">

</line>

<ellipse cx="615" cy="200" rx="40" ry="100">
    <animate
        id="animateEllipseSize2"
        attributeName="ry"
        from="100"
        to="70"
        fill="freeze"
        begin="animateFlipCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animate
        attributeName="rx"
        from="40"
        to="70"
        fill="freeze"
        begin="animateFlipCurve.end"
        dur="0.5s"
        repeatCount="1"
    />
</ellipse>


Lovely!


Do the same for the other ellipse. The new animation tags should take reference from animateEllipseSize2 instead. Again, adjust the animation as you see fit.
<ellipse cx="335" cy="200" rx="40" ry="100">
    <animate
        id="animateEllipseSize1"
        attributeName="ry"
        from="100"
        to="70"
        fill="freeze"
        begin="animateFlipCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animate
        attributeName="rx"
        from="40"
        to="70"
        fill="freeze"
        begin="animateFlipCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animate
        attributeName="cy"
        from="200"
        to="100"
        fill="freeze"
        begin="animateEllipseSize1.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animate
        attributeName="cx"
        from="335"
        to="265"
        fill="freeze"
        begin="animateEllipseSize1.end"
        dur="0.5s"
        repeatCount="1"
    />
</ellipse>

<path d="M 425 100 q 200 75 0 200" />

<line x1="415" y1="300" x2="525" y2="300">

</line>

<ellipse cx="615" cy="200" rx="40" ry="100">
    <animate
        id="animateEllipseSize2"
        attributeName="ry"
        from="100"
        to="70"
        fill="freeze"
        begin="animateFlipCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animate
        attributeName="rx"
        from="40"
        to="70"
        fill="freeze"
        begin="animateFlipCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animate
        attributeName="cy"
        from="200"
        to="100"
        fill="freeze"
        begin="animateEllipseSize2.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animate
        attributeName="cx"
        from="615"
        to="565"
        fill="freeze"
        begin="animateEllipseSize2.end"
        dur="0.5s"
        repeatCount="1"
    />
</ellipse>


Looks good!


The whiskers

We're coming to the most complicated part of this tutorial. Here, we want each line to split into three and form "whiskers". What we're going to do is create copies of each line, like so. For the first line, copy even the animations! You should not see anything upon refreshing. That's because all these lines have the exact same properties and are overlapping each other perfectly, even during the animation.
<path d="M 150 100 q 200 75 0 200">
    <animate
        id="animateFlipCurve"
        attributeName="d"
        from="M 150 100 q 200 75 0 200"
        to="M 150 100 q -200 75 0 200"
        fill="freeze"
        begin="2s"
        dur="0.5s"
        repeatCount="1"
    />

    <animateMotion
        id="animateMoveCurve"
        fill="freeze"
        begin="animateFlipCurve.end"
        dur="0.5s"
        path="M 0 0 l 250 0"
    />
</path>

<line x1="140" y1="300" x2="250" y2="300">
    <animateMotion
        dur="0.5s"
        begin="animateFlipCurve.end"
        fill="freeze"
        path="M 0 0 l 160 0"
    />
</line>

<line x1="140" y1="300" x2="250" y2="300">
    <animateMotion
        dur="0.5s"
        begin="animateFlipCurve.end"
        fill="freeze"
        path="M 0 0 l 160 0"
    />
</line>

<line x1="140" y1="300" x2="250" y2="300">
    <animateMotion
        dur="0.5s"
        begin="animateFlipCurve.end"
        fill="freeze"
        path="M 0 0 l 160 0"
    />
</line>

<ellipse cx="335" cy="200" rx="40" ry="100">
    <animate
        id="animateEllipseSize1"
        attributeName="ry"
        from="100"
        to="70"
        fill="freeze"
        begin="animateFlipCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animate
        attributeName="rx"
        from="40"
        to="70"
        fill="freeze"
        begin="animateFlipCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animate
        attributeName="cy"
        from="200"
        to="100"
        fill="freeze"
        begin="animateEllipseSize1.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animate
        attributeName="cx"
        from="335"
        to="265"
        fill="freeze"
        begin="animateEllipseSize1.end"
        dur="0.5s"
        repeatCount="1"
    />
</ellipse>

<path d="M 425 100 q 200 75 0 200" />

<line x1="415" y1="300" x2="525" y2="300">

</line>

<line x1="415" y1="300" x2="525" y2="300">

</line>

<line x1="415" y1="300" x2="525" y2="300">

</line>

<ellipse cx="615" cy="200" rx="40" ry="100">
    <animate
        id="animateEllipseSize2"
        attributeName="ry"
        from="100"
        to="70"
        fill="freeze"
        begin="animateFlipCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animate
        attributeName="rx"
        from="40"
        to="70"
        fill="freeze"
        begin="animateFlipCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animate
        attributeName="cy"
        from="200"
        to="100"
        fill="freeze"
        begin="animateEllipseSize2.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animate
        attributeName="cx"
        from="615"
        to="565"
        fill="freeze"
        begin="animateEllipseSize2.end"
        dur="0.5s"
        repeatCount="1"
    />
</ellipse>


OK, the idea here is for each of these copied line tags to thin, then rotate. Add one animate tag and one animateTransform tag within each line tag, and set them to take reference from animateMoveCurve, beginning the animation only when animateMoveCurve ends. Also set fill, dur and repeatCount attributes.
<line x1="140" y1="300" x2="250" y2="300">
    <animateMotion
        dur="0.5s"
        begin="animateFlipCurve.end"
        fill="freeze"
        path="M 0 0 l 160 0"
    />

    <animate
        fill="freeze"
        begin="animateMoveCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animateTransform
        begin="animateMoveCurve.end"
        fill="freeze"
        dur="0.5s"
        repeatCount="1"
    />
</line>

<line x1="140" y1="300" x2="250" y2="300">
    <animateMotion
        dur="0.5s"
        begin="animateFlipCurve.end"
        fill="freeze"
        path="M 0 0 l 160 0"
    />

    <animate
        fill="freeze"
        begin="animateMoveCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animateTransform
        begin="animateMoveCurve.end"
        fill="freeze"
        dur="0.5s"
        repeatCount="1"
    />
</line>

<line x1="140" y1="300" x2="250" y2="300">
    <animateMotion
        dur="0.5s"
        begin="animateFlipCurve.end"
        fill="freeze"
        path="M 0 0 l 160 0"
    />

    <animate
        fill="freeze"
        begin="animateMoveCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animateTransform
        begin="animateMoveCurve.end"
        fill="freeze"
        dur="0.5s"
        repeatCount="1"
    />       
</line>


For each line tag, the second animation changes the stroke-width attribute from 3em to 1em. That's pretty straightforward.
<line x1="140" y1="300" x2="250" y2="300">
    <animateMotion
        dur="0.5s"
        begin="animateFlipCurve.end"
        fill="freeze"
        path="M 0 0 l 160 0"
    />

    <animate
        attributeName="stroke-width"
        from="3em"
        to="1em"
        fill="freeze"
        begin="animateMoveCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animateTransform
        begin="animateMoveCurve.end"
        fill="freeze"
        dur="0.5s"
        repeatCount="1"
    />
</line>

<line x1="140" y1="300" x2="250" y2="300">
    <animateMotion
        dur="0.5s"
        begin="animateFlipCurve.end"
        fill="freeze"
        path="M 0 0 l 160 0"
    />

    <animate
        attributeName="stroke-width"
        from="3em"
        to="1em"
        fill="freeze"
        begin="animateMoveCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animateTransform
        begin="animateMoveCurve.end"
        fill="freeze"
        dur="0.5s"
        repeatCount="1"
    />
</line>

<line x1="140" y1="300" x2="250" y2="300">
    <animateMotion
        dur="0.5s"
        begin="animateFlipCurve.end"
        fill="freeze"
        path="M 0 0 l 160 0"
    />

    <animate
        attributeName="stroke-width"
        from="3em"
        to="1em"
        fill="freeze"
        begin="animateMoveCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animateTransform
        begin="animateMoveCurve.end"
        fill="freeze"
        dur="0.5s"
        repeatCount="1"
    />       
</line>


The third animation rotates the line. We set the attributeName attribute to "transform" and the type attribute to "rotate". The from and to attribues each are a series of three numbers. The first number is the angle in which to rotate by. The second and third numbers are the point of origin of the rotation. We want that point of origin to be the far right of the lines, which is, if you use the x2 and y2 attributes, (250, 300). Note that the first line is rotated by negative 5 degrees, the second line is rotated by negative 15 degrees, and the third by negative 25 degrees.
<line x1="140" y1="300" x2="250" y2="300">
    <animateMotion
        dur="0.5s"
        begin="animateFlipCurve.end"
        fill="freeze"
        path="M 0 0 l 160 0"
    />

    <animate
        attributeName="stroke-width"
        from="3em"
        to="1em"
        fill="freeze"
        begin="animateMoveCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animateTransform
        attributeName="transform"
        type="rotate"
        from="0 250 300"
        to="-5 250 300"
        begin="animateMoveCurve.end"
        fill="freeze"
        dur="0.5s"
        repeatCount="1"
    />
</line>

<line x1="140" y1="300" x2="250" y2="300">
    <animateMotion
        dur="0.5s"
        begin="animateFlipCurve.end"
        fill="freeze"
        path="M 0 0 l 160 0"
    />

    <animate
        attributeName="stroke-width"
        from="3em"
        to="1em"
        fill="freeze"
        begin="animateMoveCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animateTransform
        attributeName="transform"
        type="rotate"
        from="0 250 300"
        to="-15 250 300"
        begin="animateMoveCurve.end"
        fill="freeze"
        dur="0.5s"
        repeatCount="1"
    />
</line>

<line x1="140" y1="300" x2="250" y2="300">
    <animateMotion
        dur="0.5s"
        begin="animateFlipCurve.end"
        fill="freeze"
        path="M 0 0 l 160 0"
    />

    <animate
        attributeName="stroke-width"
        from="3em"
        to="1em"
        fill="freeze"
        begin="animateMoveCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animateTransform
        attributeName="transform"
        type="rotate"
        from="0 250 300"
        to="-25 250 300"
        begin="animateMoveCurve.end"
        fill="freeze"
        dur="0.5s"
        repeatCount="1"
    />
</line>


Aha!


Now let's repeat for the other three lines, but in reverse! Instead of the point of origin being the right end, make it the left end!
<line x1="415" y1="300" x2="525" y2="300">
    <animate
        attributeName="stroke-width"
        from="3em"
        to="1em"
        fill="freeze"
        begin="animateMoveCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animateTransform
        attributeName="transform"
        type="rotate"
        from="0 415 300"
        to="5 415 300"
        begin="animateMoveCurve.end"
        fill="freeze"
        dur="0.5s"
        repeatCount="1"
    />
</line>

<line x1="415" y1="300" x2="525" y2="300">
    <animate
        attributeName="stroke-width"
        from="3em"
        to="1em"
        fill="freeze"
        begin="animateMoveCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animateTransform
        attributeName="transform"
        type="rotate"
        from="0 415 300"
        to="15 415 300"
        begin="animateMoveCurve.end"
        fill="freeze"
        dur="0.5s"
        repeatCount="1"
    />
</line>

<line x1="415" y1="300" x2="525" y2="300">
    <animate
        attributeName="stroke-width"
        from="3em"
        to="1em"
        fill="freeze"
        begin="animateMoveCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animateTransform
        attributeName="transform"
        type="rotate"
        from="0 415 300"
        to="25 415 300"
        begin="animateMoveCurve.end"
        fill="freeze"
        dur="0.5s"
        repeatCount="1"
    />
</line>


And there's your rat head.


Finishing up...

Modify svgContainer to remove the red outline. Also, add some styling for text tag.
#svgContainer
{
    width: 800px;
    height: 400px;
    margin: 10% auto 0 auto;
    outline: 0px solid #FF0000;
}

svg
{
    width: 800px;
    height: 400px;
}

line, ellipse, path, text
{
    stroke-width: 3em;
    stroke: rgba(255, 0, 0, 1);
    fill: none;
}

text
{
    stroke-width: 1px;
    fill: rgba(255, 0, 0, 1);
    font: bold 40px arial;
}


When you're done, add some text at the end of the svg object.
<ellipse cx="615" cy="200" rx="40" ry="100">
    <animate
        id="animateEllipseSize2"
        attributeName="ry"
        from="100"
        to="70"
        fill="freeze"
        begin="animateFlipCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animate
        attributeName="rx"
        from="40"
        to="70"
        fill="freeze"
        begin="animateFlipCurve.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animate
        attributeName="cy"
        from="200"
        to="100"
        fill="freeze"
        begin="animateEllipseSize2.end"
        dur="0.5s"
        repeatCount="1"
    />

    <animate
        attributeName="cx"
        from="615"
        to="565"
        fill="freeze"
        begin="animateEllipseSize2.end"
        dur="0.5s"
        repeatCount="1"
    />
</ellipse>

<text x="150" y="400">
    HAPPY YEAR OF THE RAT
</text>


Adjust as necessary!


That's it, we're done...

That was fun. And hopefully, that's just a prelude to the awesomeness that will be The Year of The Rat!

Wishing you an enor-mouse-ly auspicious Lunar New Year!
T___T