Monday 26 September 2016

On the fast track: Project Nilgiri

At the beginning of the year, we took a look at Facebook's Free Basics, and how that initiative was panning out in India. As it happened, not very well. The Telecom Regulatory Authority of India (TRAI) issued a ban on Free Basics, leaving Facebook out in the cold and Mark Zuckerberg back to the drawing board.

Fast forward eight months later...

Google has had a great deal more success in India as Google Fiber and Indian Railways negotiated a partnership. This has recently come to be known as Project Nilgiri. (You were expecting something like "Goograil" or "Indian Fiber"? Dude...)

Free WiFi!

What's Project Nilgiri?

I'm going to keep it simple (and it really is that simple) and say that Google builds WiFi stations all throughout the train stations operated by Indian Railways. To date, it's covered 10 of these and looks to be building on that number by the end of this year. What this means is that passengers on the train now have access to free WiFi at staggeringly high internet speeds for about 30 minutes upon the issuance of a one-time password. The access persists after the time limit but at a reduced rate.

The target is 400 railway stations, making Project Nilgiri the largest WiFi network in India, ever.

That's not all. This is only Phase One. Phase Two involves providing WiFi to moving trains, not just train stations!

What's in it for Google?

I'd like to believe that it's purely because Google CEO Sundar Pichai  was born in India and thus would like to aid in its economic growth. But let's get real and look at the huge amount of exposure and potential deals Google is going to get from this. Already, usage has hit astonishing heights as users stream music, videos, even porn, at the railway stations. I bet this hasn't hurt Indian Railway's consumer rate either. And that's considering Google Fiber and Indian Railways are not even done yet!

There are licensing costs associated with being an ISP in India. With this partnership, Google probably will not have to be overly concerned about those costs. In short - brilliant!

Now the burning question...

Why did Google succeed where Facebook failed so spectacularly? I mean, approval from TRAI aside, the reception to the Project Nilgiri seems to have garnered much less controversy and way less resistance. I have some theories about this...

Nationality

It could all just boil down to skin color. Sundar Pichai is India-born. Mark Zuckerberg comes across as the white boy trying to muscle in on India territory. Personally, I think kind of mentality is so last century, but I won't discount the possibility.

Keeping it simple

Project Nilgiri is presented as a value-add rather than a product in itself. Take the train and you get free high speed WiFi. No fuss, no caveats, no conditions. Free Basics, on the other hand, makes someone jumps through a whole lot of hoops and then subjects them to restrictions. Buy a SIM card, register an account and only certain sites are free for access, yadda yadda.

No Preaching

Facebook makes an awfully big song and dance about eliminating poverty and bringing Internet access to the impoverished masses. That's a big dream, a noble dream. Always good to aim high. And no, I don't doubt Zuckerberg's sincerity. But yes, fairly or not, the whole thing does smack of condescension. And people react negatively to that.

Google has kept their aims manageable. Give train passengers free WiFi. That's all there is to it. No grand marketing campaign to sell the nobility of the enterprise, no epic scope, at least not on a moral level. Far more achievable, and something people can get behind.

The epic irony is, Google may have done more towards lifting India out of third-world status without actually even (apparently) meaning to.

Conclusion

Whatever the case is, Project Nilgiri appears to be going places. It'll be exciting to see how this impacts India as a whole eventually.

Is that railly cool, or what?!
T___T

Monday 19 September 2016

Web Tutorial: The Browser Butterfly (Part 3/3)

Your butterfly has begun to move, and now it needs to go places. Specifically, around your browser.

We'll start with some JavaScript. The global variables x, y, size, rotation and wingtimer point to the CSS properties that will be randomized. The variable nexttimer is is also randomized - it is the number of milliseconds to the next transition. The variable transitiontimer is just to set animation durations for everything else.
        <script>
        var x=0;
        var y=0;
        var size=0;
        var rotation=0;
        var transitiontimer;
        var wingtimer;
        var nexttimer;
        </script>


Of course, we'll need a random number generator function.
        <script>
        var x=0;
        var y=0;
        var size=0;
        var rotation=0;
        var transitiontimer;
        var wingtimer;
        var nexttimer;

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


Next, we define the function flutter(). It accepts a variable vartimer, which is the number of milliseconds it will take to execute the next transition. First of all, we set the variable wrapper as the object pointing to the butterfly_wrapper div.
        var x=0;
        var y=0;
        var size=0;
        var rotation=0;
        var transitiontimer;
        var wingtimer;
        var nexttimer;

        function flutter(vartimer)
        {
            var wrapper=document.getElementById("butterfly_wrapper");
        }

        function generaterandomno(varmin,varmax)
        {
            return Math.floor((Math.random() * (varmax-varmin+1)) + varmin);
        }


Next, we set a random value to nexttimer. If the result is not between 1500 and 3000, it uses the default of 1500. You can change this if you like. Finally, we use the nexttimer variable to call the flutter() function again in the setTimeout() method. So the flutter() method will call itself repeatedly after a randomized number of milliseconds (between 1500 and 300).
        function flutter(vartimer)
        {
            var wrapper=document.getElementById("butterfly_wrapper");

            nexttimer=vartimer+(generaterandomno(-200,200));
            nexttimer=(nexttimer<1500||nexttimer>3000?1500:nexttimer);

            setTimeout(function(){flutter(nexttimer);},vartimer);
        }


Now, we generate the values for x, y, size, rotation and timer. Each of them has a minimum and maximum value. For example, size is the size of the butterfly. If it gets too small, it'll disappear. If it gets too large, it'll eat up your entire screen. So we need to provide a happy medium, say, between 10 to 50 pixels. Feel free to alter the defaults. It's all up to you!
        function flutter(vartimer)
        {
            var wrapper=document.getElementById("butterfly_wrapper");

            nexttimer=vartimer+(generaterandomno(-200,200));
            nexttimer=(nexttimer<1500||nexttimer>3000?1500:nexttimer);

            x+=generaterandomno(-80,80);
            y+=generaterandomno(-80,80);

            x=(x<20?30:x);
            y=(y<20?30:y);
            x=(x>250?240:x);
            y=(y>250?240:y);

            size+=generaterandomno(-10,10);
            size=(size<10?20:size);
            size=(size>50?40:size);

            rotation+=generaterandomno(-10,10);
            rotation=(rotation<-20?0:rotation);
            rotation=(rotation>20?0:rotation);

            transitiontimer=generaterandomno(20,50)/10;

            setTimeout(function(){flutter(nexttimer);},vartimer);
        }


Now use those variables to set the CSS properties of the variable wrapper. x determines the number of pixels from the left, and y determines the number of pixels from the top. size determines the width and height of wrapper. rotation determines the, well, rotation of wrapper. And transitiontimer determines how slowly or quickly the wrapper moves.
        function flutter(vartimer)
        {
            var wrapper=document.getElementById("butterfly_wrapper");

            nexttimer=vartimer+(generaterandomno(-200,200));
            nexttimer=(nexttimer<1500||nexttimer>3000?1500:nexttimer);

            x+=generaterandomno(-80,80);
            y+=generaterandomno(-80,80);

            x=(x<20?30:x);
            y=(y<20?30:y);
            x=(x>250?240:x);
            y=(y>250?240:y);

            size+=generaterandomno(-10,10);
            size=(size<10?20:size);
            size=(size>50?40:size);

            rotation+=generaterandomno(-10,10);
            rotation=(rotation<-20?0:rotation);
            rotation=(rotation>20?0:rotation);

            transitiontimer=generaterandomno(20,50)/10;

            wrapper.style.marginLeft=x+"px";
            wrapper.style.marginTop=y+"px";
            wrapper.style.width=size+"px";
            wrapper.style.height=size+"px";
            wrapper.style.transform="rotate("+rotation+"deg)";
            wrapper.style.webkitTransform="rotate("+rotation+"deg)";       
            wrapper.style.transition="all "+transitiontimer+"s";   
            wrapper.style.webkitTransition="all "+transitiontimer+"s";

            setTimeout(function(){flutter(nexttimer);},vartimer);
        }


Now we randomize the variable wingtimer, and declare the variables upperwings and lowerwings. Then we assign to them the array returned by the method getElementsByClassName(). So now upperwings points to the divs styled by the upperwing CSS class, while lowerwings points to the divs styled by the lowerwing CSS class. Then we use a For loop and iterate through each of these arrays, modifying the animation-duration property. This causes the wings to flap at random speeds. Here, I've taken the lazy way out and setting the variable k to a range between 0 and 1, because I know there are only two upper wings and lower wings.
        function flutter(vartimer)
        {
            var wrapper=document.getElementById("butterfly_wrapper");

            nexttimer=vartimer+(generaterandomno(-200,200));
            nexttimer=(nexttimer<1500||nexttimer>3000?1500:nexttimer);

            x+=generaterandomno(-80,80);
            y+=generaterandomno(-80,80);

            x=(x<20?30:x);
            y=(y<20?30:y);
            x=(x>250?240:x);
            y=(y>250?240:y);

            size+=generaterandomno(-10,10);
            size=(size<10?20:size);
            size=(size>50?40:size);

            rotation+=generaterandomno(-10,10);
            rotation=(rotation<-20?0:rotation);
            rotation=(rotation>20?0:rotation);

            timer=generaterandomno(20,50)/10;

            wrapper.style.marginLeft=x+"px";
            wrapper.style.marginTop=y+"px";
            wrapper.style.width=size+"px";
            wrapper.style.height=size+"px";
            wrapper.style.transform="rotate("+rotation+"deg)";
            wrapper.style.webkitTransform="rotate("+rotation+"deg)";       
            wrapper.style.transition="all "+timer+"s";   
            wrapper.style.webkitTransition="all "+timer+"s";

            wingtimer=generaterandomno(1,5);
            var upperwings=document.getElementsByClassName("upperwing");
            var lowerwings=document.getElementsByClassName("lowerwing");

            for (var k=0;k<=1;k++)
            {
                upperwings[k].style.animationDuration="0."+wingtimer+"s";
                upperwings[k].style.webkitAnimationDuration="0."+wingtimer+"s";
                lowerwings[k].style.animationDuration="0."+wingtimer+"s";
                lowerwings[k].style.webkitAnimationDuration="0."+wingtimer+"s";       
            }

            setTimeout(function(){flutter(nexttimer);},vartimer);
        }


Modify your HTML to run the flutter() function upon loading the page, with an arbitrary value of 1500. Again, change this value if you wish.
<body onload="flutter(1500);">


Run your code. You should now have a beautiful butterfly roaming around your page.


Other changes possible

The code sample restricts your butterfly to a small section of the page. You can actually make it go  all around the entire page by setting x and y to values between 0 and 100, and using percentages instead of pixels.

You can also make multiple butterflies with different colors. Just replicate the divs and name the ids differently, then modify the flutter() function to animate each one. I won't spoonfeed you here, figure this out yourself! The possibilities are endless.

Now that was pretty fly.
T___T

Friday 16 September 2016

Web Tutorial: The Browser Butterfly (Part 2/3)

How do a butterfly's wings move? Or more precisely, how do we simulate the movement of a butterfly's wings?

The divs have been created, now it's all a matter of animating each of them. To do that, we'll leverage on CSS3's 3D transformations and animations. Alter the CSS class perspective as follows. This will allow the divs styled using perspective to act as 3D perspective containers.
        .perspective
        {
            position:relative;
            width:100%;
            height:50%;
            -webkit-perspective:150px;
            -webkit-perspective-origin:50% 50%;
            perspective:150px;
            perspective-origin:50% 50%;
        }


The divs to be animated, of course, are the divs using the CSS classes upperwing and lowerwing. So make the following changes. Here, we haven't specified the animation yet, only the values. The animation-duration property is set at 0.3 seconds, though this will be randomized later. animation-count is set to infinite because we don't want the animation to end. animation-direction is alternate so that the wings will flap back and forth.
        .upperwing,.lowerwing
        {
            /* Permalink - use to edit and share this gradient: http://colorzilla.com/gradient-editor/#FF4400+0,FFEE00+50,FF4400+100 */
            background: #FF4400; /* Old browsers */
            background: -moz-radial-gradient(center, ellipse cover, #FF4400 0%, #FFEE00 50%, #FF4400 100%); /* FF3.6-15 */
            background: -webkit-radial-gradient(center, ellipse cover, #FF4400 0%,#FFEE00 50%,#FF4400 100%); /* Chrome10-25,Safari5.1-6 */
            background: radial-gradient(ellipse at center, #FF4400 0%,#FFEE00 50%,#FF4400 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
            filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FF4400', endColorstr='#FF4400',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */
            -webkit-animation-duration: 0.3s;
            -webkit-animation-iteration-count: infinite;
            -webkit-animation-direction: alternate;
            animation-duration: 0.3s;
            animation-iteration-count: infinite;
            animation-direction: alternate;
        }


Now we alter the CSS classes for upperwing_left, upperwing_right, lowerwing_left and lowerwing_right to use the animations movewing_left and movewing_right, which will be defined soon. Basically, left wings use movewing_left and right wings use movewing_right.
        .upperwing
        {
            position:absolute;
            width:100%;
            height:100%;
        }

        .upperwing_left
        {
            border-top-left-radius: 10%;
            border-top-right-radius: 80%;
            border-bottom-right-radius: 0%;
            border-bottom-left-radius: 30%;
            -webkit-animation-name: movewing_left;
            animation-name: movewing_left;
        }

        .upperwing_right
        {
            border-top-left-radius: 80%;
            border-top-right-radius: 10%;
            border-bottom-right-radius: 30%;
            border-bottom-left-radius: 0%;
            -webkit-animation-name: movewing_right;
            animation-name: movewing_right;
        }

        .lowerwing
        {
            position:absolute;
            top:0;
            width:80%;
            height:80%;
        }

        .lowerwing_left
        {
            right:0;
            border-top-left-radius: 30%;
            border-top-right-radius: 0%;
            border-bottom-right-radius: 80%;
            border-bottom-left-radius: 10%;
            -webkit-animation-name: movewing_left;
            animation-name: movewing_left;
        }

        .lowerwing_right
        {
            left:0;
            border-top-left-radius: 0%;
            border-top-right-radius: 30%;
            border-bottom-right-radius: 10%;
            border-bottom-left-radius: 80%;
            -webkit-animation-name: movewing_right;
            animation-name: movewing_right;
        }


Now add this code to define the animations movewing_left and movewing_right. The 3D transformation in question is rotateY.
        .upperwing
        {
            position:absolute;
            width:100%;
            height:100%;
        }

        .upperwing_left
        {
            border-top-left-radius: 10%;
            border-top-right-radius: 80%;
            border-bottom-right-radius: 0%;
            border-bottom-left-radius: 30%;
            -webkit-animation-name: movewing_left;
            animation-name: movewing_left;
        }

        .upperwing_right
        {
            border-top-left-radius: 80%;
            border-top-right-radius: 10%;
            border-bottom-right-radius: 30%;
            border-bottom-left-radius: 0%;
            -webkit-animation-name: movewing_right;
            animation-name: movewing_right;
        }

        .lowerwing
        {
            position:absolute;
            top:0;
            width:80%;
            height:80%;
        }

        .lowerwing_left
        {
            right:0;
            border-top-left-radius: 30%;
            border-top-right-radius: 0%;
            border-bottom-right-radius: 80%;
            border-bottom-left-radius: 10%;
            -webkit-animation-name: movewing_left;
            animation-name: movewing_left;
        }

        .lowerwing_right
        {
            left:0;
            border-top-left-radius: 0%;
            border-top-right-radius: 30%;
            border-bottom-right-radius: 10%;
            border-bottom-left-radius: 80%;
            -webkit-animation-name: movewing_right;
            animation-name: movewing_right;
        }

        @-webkit-keyframes movewing_left{
            from {-webkit-transform:rotateX(0deg);}
            to {-webkit-transform:rotateY(65deg);}
        }
           
        @keyframes movewing_left{
            from {transform:rotateY(0deg);}
            to {transform:rotateY(65deg);}
        }

        @-webkit-keyframes movewing_right{
            from {-webkit-transform:rotateX(0deg);}
            to {-webkit-transform:rotateY(-65deg);}
        }
           
        @keyframes movewing_right{
            from {transform:rotateY(0deg);}
            to {transform:rotateY(-65deg);}
        }


Now run that code. See a problem? That's right - the wings are moving, but they're moving on their center and not the center of the butterfly.


We need to use the transform-origin property here. Left wings have this set to 100% 50% (rotated on the right side) and right wings have this set to 0% 50% (rotated on the left side).
        .upperwing
        {
            position:absolute;
            width:100%;
            height:100%;
        }

        .upperwing_left
        {
            border-top-left-radius: 10%;
            border-top-right-radius: 80%;
            border-bottom-right-radius: 0%;
            border-bottom-left-radius: 30%;
            -webkit-transform-origin:100% 50%;
            transform-origin:100% 50%;
            -webkit-animation-name: movewing_left;
            animation-name: movewing_left;
        }

        .upperwing_right
        {
            border-top-left-radius: 80%;
            border-top-right-radius: 10%;
            border-bottom-right-radius: 30%;
            border-bottom-left-radius: 0%;
            -webkit-transform-origin:0% 50%;
            transform-origin:0% 50%;
            -webkit-animation-name: movewing_right;
            animation-name: movewing_right;
        }

        .lowerwing
        {
            position:absolute;
            top:0;
            width:80%;
            height:80%;
        }

        .lowerwing_left
        {
            right:0;
            border-top-left-radius: 30%;
            border-top-right-radius: 0%;
            border-bottom-right-radius: 80%;
            border-bottom-left-radius: 10%;
            -webkit-transform-origin:100% 50%;
            transform-origin:100% 50%;
            -webkit-animation-name: movewing_left;
            animation-name: movewing_left;
        }

        .lowerwing_right
        {
            left:0;
            border-top-left-radius: 0%;
            border-top-right-radius: 30%;
            border-bottom-right-radius: 10%;
            border-bottom-left-radius: 80%;
            -webkit-transform-origin:0% 50%;
            transform-origin:0% 50%;
            -webkit-animation-name: movewing_right;
            animation-name: movewing_right;
        }


Try again! This time, your butterfly should be flapping its wings smoothly.


Next

Moving the butterfly around the screen, and other niceties. Stay tuned!

Tuesday 13 September 2016

Web Tutorial: The Browser Butterfly (Part 1/3)

Nature sometimes inspires. And at the risk of sounding like some tree-hugger wannabe, the sight of a butterfly flitting around my neighbor's potted flowers spurred me to create my own version - a browser-based version, that is.

Imagine a butterfly moving around your web page, in random directions and speeds...

Done imagining? Ponder no more; we're going to make this a reality.

This web tutorial leverages heavily on CSS3 animations, 3D transformations in particular, and JavaScript Timer functions. But in the first part of this tutorial, we're just going to concentrate on building the butterfly.

This is the initial HTML. We start off with a div tag and assign it an id of butterfly_wrapper. This is the div that will be moved around the screen, rotated and resized at random later on. It will contain the wings of the butterfly.
<html>
    <head>
        <title>Butterfly</title>

        <style type="text/css">

        </style>

        <script>

        </script>
    </head>

    <body>
        <div id="butterfly_wrapper">

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


Here's the CSS code for butterfly_wrapper. We're giving it a position of absolute because it needs to move around the page and avoid displacing other DOM objects while it does so. Width and height are set to an initial value of 150 pixels. The final product is not going to be that big, but let's set it at this size to make things clearer.
    <style type="text/css">
        #butterfly_wrapper
        {
            width:150px;
            height:150px;
            position:absolute;
        }
    </style>


To make things visually easier for us, let's add this to the code. This ensures that all divs will have a nice red border so you can see what's happening as we change the code.
        div {border:1px solid #FF0000;}

        #butterfly_wrapper
        {
            width:150px;
            height:150px;
            position:absolute;
        }


See?


Now, let's put in some placeholders for the wings. These are divs that are assigned the CSS class leftwings and rightwings, respectively.
    <div id="butterfly_wrapper">
        <div class="leftwings">

        </div>
        <div class="rightwings">

        </div>
    </div>


The CSS classes are like so. Both leftwings and rightwings take up 50% of butterfly_wrapper's width, and 100% of its height. They will adhere to the top of butterfly_wrapper. leftwings will stick to the left side of butterfly_wrapper, while rightwings will stick to the right side.
        div {border:1px solid #FF0000;}

        #butterfly_wrapper
        {
            width:150px;
            height:150px;
            position:absolute;
        }

        .leftwings,.rightwings
        {
            position:absolute;
            width:50%;
            height:100%;
            top:0;
        }

        .leftwings
        {
            left:0;
        }

        .rightwings
        {
            right:0;
        }


So far, this is what you should see.


OK now, for leftwings and rightwings, we include two divs in each of them, with a CSS class of perspective. This will be necessary for 3D transformations later on.
    <div id="butterfly_wrapper">
        <div class="leftwings">
            <div class="perspective">

            </div>
            <div class="perspective">

            </div>
        </div>
        <div class="rightwings">
            <div class="perspective">

            </div>
            <div class="perspective">

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


The CSS class for perspective is like so. They'll take up the full width of their parent divs (which in turn are 50% of butterfly_wrapper's width) and only 50% of the height. That's because  the butterfly's wings are segmented into upper and lower wings.
        .leftwings
        {
            left:0;
        }

        .rightwings
        {
            right:0;
        }

        .perspective
        {
            position:relative;
            width:100%;
            height:50%;
        }


So far so good?


Now add a div inside each of these divs. These divs will have two classes each. This is deliberate as the classes have overlapping style elements. We could simply style each wing individually, but that would entail a fair bit of unnecessary repetition.
    <div id="butterfly_wrapper">
        <div class="leftwings">
            <div class="perspective">
                <div class="upperwing upperwing_left">

                </div>
            </div>
            <div class="perspective">
                <div class="lowerwing lowerwing_left">

                </div>
            </div>
        </div>
        <div class="rightwings">
            <div class="perspective">
                <div class="upperwing upperwing_right">

                </div>
            </div>
            <div class="perspective">
                <div class="lowerwing lowerwing_right">

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


Pay close attention - this next part could be tricky. The CSS classes upperwing and lowerwing determine the sizes of the upper and lower wings. This is true for both left and right wings. Upper wings are larger, and lower wings smaller. This is reflected in the width and height values. lowerwing has top set to 0 in order to keep the upper and lower wings from looking disjointed. This may not be strictly necessary, but good to have.
        .perspective
        {
            position:relative;
            width:100%;
            height:50%;
        }

        .upperwing
        {
            position:absolute;
            width:100%;
            height:100%;
        }

        .lowerwing
        {
            position:absolute;
            top:0;
            width:80%;
            height:80%;
        }


Starting to look a mite complicated, isn't it?


Now, we shape the wings based on their positions. You may want to refer to this documentation on the border-radius property.
        .upperwing
        {
            position:absolute;
            width:100%;
            height:100%;
        }

        .upperwing_left
        {
            border-top-left-radius: 10%;
            border-top-right-radius: 80%;
            border-bottom-right-radius: 0%;
            border-bottom-left-radius: 30%;
        }

        .upperwing_right
        {
            border-top-left-radius: 80%;
            border-top-right-radius: 10%;
            border-bottom-right-radius: 30%;
            border-bottom-left-radius: 0%;
        }

        .lowerwing
        {
            position:absolute;
            top:0;
            width:80%;
            height:80%;
        }

        .lowerwing_left
        {
            right:0;
            border-top-left-radius: 30%;
            border-top-right-radius: 0%;
            border-bottom-right-radius: 80%;
            border-bottom-left-radius: 10%;
        }

        .lowerwing_right
        {
            left:0;
            border-top-left-radius: 0%;
            border-top-right-radius: 30%;
            border-bottom-right-radius: 10%;
            border-bottom-left-radius: 80%;
        }


Ah yes, starting to take shape!


Now add this code. This styles both upperwing and lowerwing classes with a nice radial pattern I shamelessly generated from colorzilla. Feel free to apply your own colors!
        .perspective
        {
            position:relative;
            width:100%;
            height:50%;
        }

        .upperwing,.lowerwing
        {
            background: #FF4400; /* Old browsers */
            background: -moz-radial-gradient(center, ellipse cover, #FF4400 0%, #FFEE00 50%, #FF4400 100%); /* FF3.6-15 */
            background: -webkit-radial-gradient(center, ellipse cover, #FF4400 0%,#FFEE00 50%,#FF4400 100%); /* Chrome10-25,Safari5.1-6 */
            background: radial-gradient(ellipse at center, #FF4400 0%,#FFEE00 50%,#FF4400 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
            filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FF4400', endColorstr='#FF4400',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */
        }

        .upperwing
        {
            position:absolute;
            width:100%;
            height:100%;
        }


Getting warmer...


Do this to your code. This will remove the red border.
    div {border:0px solid #FF0000;}


Damn, that's pretty.


We've created the basic shape of the butterfly. But it's cold and lifeless as a fossil. Soon, we'll be emulating Mary Shelley's Frankenstein and injecting some life into it!

Next

Animating the wings!

Tuesday 6 September 2016

Social Media Mishap

Last year around this time, I was employed in an SME as an in-house web developer. How that came about is a tale for another day. This story is about an ex-colleague. My colleague was dismissed from her position. And how it happened will be a good bit of food for thought.

Things had been a little tense between the CEO and her lately, with her being very vocal about her displeasure as to how things were transpiring. It all came to a head one fateful evening when she posted an epic rant on Facebook, not naming any names, but using very colorful language and leaving no doubt, to those in the know, as to whom she was referring to. As it happened, the HR Manager was on her Friends List, and saw it. This was escalated to the COO, who in turn made it known to the CEO that this employee was dissing him on Social Media. There was an enquiry, which took place over some conversation where my now ex-colleague was asked to explain herself, after which she voluntarily resigned.

Tendering.

That's not being dismissed...

Splitting hairs a bit here, aren't we? Technically, yes, she was not dismissed and thus she had no grounds to sue for unfair dismissal. But if she had not resigned, things would have gotten very unpleasant. In spirit, there's not much difference there.

There have been several incidences of employees being dismissed due to something they posted on Social Media, such as Twitter, Facebook and Instagram. So many that I won't even bother to link you to an example. Just do a Google search.

That sucks!

Sure it does. It's a crappy thing to happen to anyone. But allow me to explain my position here.

My ex-colleague's a nice lady. Sure, she's a little dramatic and hot-tempered. So she isn't perfect. But we do get along and I wish her no ill. That said, I harbor no sympathy for her in this situation. She had it coming.

Look, bosses are only human. They have their biases, their flaws and their insecurities. Some bosses prefer to hire and promote pretty young things in skirts. Some bosses have hare-brained ideas that they will defend even in the face of all evidence to the contrary. Some bosses, plainly speaking, need to grow the hell up. But generally, even the most mature, understanding and enlightened boss will not take kindly to being ticked off in public for the world to see, especially when he has control over the employment status of the one doing the ticking off. What, you think that sounds unfair? Spoiler: No one claimed life was fair.

What she did wrong

Other than piss off someone who had the power to fire her?

Here goes - she added the wrong people to her Friends List. That was HR, for crying out loud. My ex-colleague complained bitterly that HR had backstabbed her in the entire debacle.

Wait, what?

As far as I'm concerned, HR did more or less what one should expect of HR. Between the company and you, whose side does one realistically expect HR to take? Here's a clue - not yours. Not unless it's a legal matter - in which case HR, while not on the company's side, is still not on your side. She's on her own side, in military lingo, covering her own ass. And if you believe otherwise, if you harbor any hope of surviving in the corporate world at all, you need to have that oh-so-endearing naivete slapped out of your head ASAP. You are a cog in a machine, no more. Does a mechanic concern himself with a cog, or the machine?

Repeat after me - HR is not your friend. In fact, this applies to your colleagues as well. They are not your friends. Sure, HR is supposed to be personable and friendly. HR is supposed to make you feel that you can confide your problems at work, in her. HR is supposed to act like she is your best buddy in the company. But if you believe her, how do I put this delicately - nah, screw it - you're a fucking idiot.

But HR is really my friend. We've known each other since kindergarten...

In that case, as a friend, you should jolly well not put HR in the position where she has to choose between friendship and professional duty. Rant on Facebook if you must, but filter her from the post. She can't possibly be expected to report what she doesn't see, right?

Didn't see
a thing!

My colleague put HR in a position where it was clear some action had to be taken. Sure, HR could have taken her aside and advised her to take the post down, without escalating it. But the only thing that is clear is that HR had to do something. It's unfortunate that the route most ruinous to my ex-colleague was taken, but here's the thing - what in the blue hell was HR doing on her Friends List anyway?

Honestly, had I been the CEO, I would have gotten rid of that ex-colleague too. Not because I can't man up and take criticism. But because anyone who is stupid enough to add HR to their Friends List and then bitch about the company on Facebook, can't be trusted to work for me. I mean, if you can't even exercise that little bit of common sense, what can you do?

Get fired up, but don't get fired.
T___T

Friday 2 September 2016

WhatsApp and the Great Privacy Controversy

There are many, many users upset with WhatsApp right now. And that's being generous. As the weeks go by, some of these users have started moving over to rival messaging services. The noise on Twitter has been deafening.
Et tu, WhatsApp?

And it's all down to WhatsApp's latest controversial decision, announced on 25th August - to share collected user phone numbers with its parent company, Facebook.

Back when Facebook acquired WhatsApp, founder Jan Koum reassured the current user base that WhatsApp was as committed to data privacy as ever. The users, rightly or wrongly, see this move as betrayal. Even users who don't have a Facebook account (and therefore aren't affected) don't seem to approve much of this.

Maybe it's the principle of the thing, eh?

WhatsApp has mitigated the blow by offering an opt-out to users who wish to keep their WhatsApp and Facebook accounts separate, though if you want to do so, you'd better hustle. There's a 30-day window to do it, and the window's closing by the day. Not that I think it'll make an ounce of difference. According to some news sources, WhatsApp will still be sharing information with Facebook, for, y'know, better integration.

What's with all the angst?

I'm looking upon all this outrage with bemusement. Sure, I get it. Privacy is important. Sure, this could be considered a dick move. And yes, I'm not exactly thrilled about the turn of events. And I'm aware that Facebook and WhatsApp face some kind of legal inquiry from the Federal Trade Commission over this very issue.

But can anyone honestly tell me this wasn't expected? Come on.

From the day WhatsApp gave up its autonomy to Facebook, this was always par for the course. I've said this before here, and I'll say it again: Facebook is not a charity. It is a business entity. The purpose of its existence is not to provide us with free apps for life. There's a catch. There's always a catch.

Know how much Facebook paid to acquire WhatsApp back then? A whopping 22 billion USD.

How much did we pay for our Facebook accounts? How about our WhatsApp accounts? I don't know about you, but to date, I've paid a big fat zero. And you know what they say about free lunches. (Hint: They hail from the same hometown as Santa Claus) Facebook doesn't charge us to have an account, or to use WhatsApp. But it does have to make some kind of profit, and in this case, it will probably come in the form of advertising dollars as the data is shared with marketers who wish to push their products.

But Jan Koum said...

Yes, I'm aware of what he said. In fact, I'll reproduce it below.

"If partnering with Facebook meant that we had to change our values, we wouldn’t have done it. Instead, we are forming a partnership that would allow us to continue operating independently and autonomously. Our fundamental values and beliefs will not change. Our principles will not change."

This was said two years ago. What's happened since then? JavaScript came up with several exciting new frameworks. Tech companies rose and fell. Yahoo and LinkedIn are being sold. Windows 10 emerged on the market. Should I go on? The thing is, in the tech business, change happens all the damn time, and happens at a scary rate. You adapt or die. Do we really want to hold Koum to something he said two entire years ago?

Other messager apps

Don't like it? Still miffed? Want to stick to those principles? There are always other messaging services. Or you could simply delete your Facebook account to make a point. You'll live.

Good chat, folks. Ping you again sometime.
T___T