megacolorboy

Abdush Shakoor's Weblog

Writings, experiments & ideas.

Optimize your website performance

Sharing my experiences on website optimization.

This article is directed towards audiences who are keen on making their websites and web applications load faster and perform better.

I won't be focusing on the SEO (Search Engine Optimization) part of it but rather, I'll be covering on how to overcome performance bottleneck issues. If you want to know more about SEO, you can go here.

Recently, I boosted my company's website from a lagging 10-30 seconds (I know, that's really embarassing!) to a smooth 1.7 to 2.5 seconds load speed, so that's why I thought of sharing my experiences and tips on this article.

Before we get there, let's first understand what could probably make your website perform bad or load slowly. Afterwards, there'll be some strategies on how you could fix those issues and make it optimal.

Why is my website so slow?

You're not a developer if you've never heard this in your day-to-day life. In today's era, the standard average page load time is under 3 seconds, anything more than that, you might lose a visitor and that can affect your website's SEO in the long run.

Here are some of the reasons, in my opinion:

Too many HTTP requests

According to GTMetrix, a web page should have an average of 92 requests but there are websites that have over 100+ requests and that's crazy, especially, if you try to access the website on a slower network.

There can be many factors that contributes to an increase in HTTP requests:

  • Too many images on a page
  • CSS and JS files are not compressed and minified
  • Calling external libaries like jQuery or Bootstrap from a Content-Delivery Network
  • Loading all JS files at one go

Since, each DOM element is generated in a top-down manner, it would display the completed page when all resources are loaded, hence is why you shouldn't have too many server requests.

Inefficient database queries

Let's say, you have a page that displays a list of products from your SQL database and you execute this query:

SELECT * FROM products

Sorry, it's inefficient. Why? In a real-life scenario, a table may contain a lot of columns and multiply that with x number of database calls the server has to make for EVERY request that comes from a visitor. You get it, right?

This could be worse if you have an unorganized database structure. Plan well, my friend.

Images aren't optimized

Images that are uncompressed, have a higher resolution or large file size can be detrimental to the site's performance which creates an unpleasant user experience.

Improper page caching

If you've built a dynamic page that displays a blog article, it probably performs a lot of requests/callbacks to generate a page with necessary information. Multiply that with x number of user sessions and that'll place a huge workload on the server.

Your codebase stinks

This is a very deep problem especially if the code is never refactored in a very long time.

Common causes of code smells are:

  • Duplicate code
  • Large methods or classes
  • Too many parameters
  • Long line of code
  • Unnecessary uses of loops and conditions
  • Unused code

There's much more to this but if you're facing this, it's about time that you start fixing your codebase and keep it mint condition.

Shared Server Hosting

Ah, this is the most common culprit. Many people host their websites on a shared server and guess what? Shared hosting means shared system resources because apart from your website, there could be 5 or more websites hosted on the same server.

How to overcome these issues?

Before we move on, let me just clarify that the techniques I've used below worked out for me but it may or may not work for you.

Here are the following methods that worked out for me:

Compress & Resize Images

I'm sure that there are multiple ways to compress and resize an image like using Adobe Photoshop but what if there are hundreds and thousands of images? It'd be time consuming to do all of that.

I created an ad hoc solution using a PHP-based image extension named ImageMagick. This library is used to create and modify images using the ImageMagick Library.

Since it can be used directly from the terminal, I wrote a small script using PowerShell to compress and resize the images in all folders in one go!

Snippet to resize images:

magick mogrify -resize 256x256 -format *.jpg *.jpeg *.png

Snippet to compress images:

magick mogrify -quality 70% *.jpg *.jpeg *.png

The logic of the code is pretty straightforward. All it has to do is get a list of files with ends with image extensions (.jpg, .jpeg, .png) and modify the resolution to 640x480 and reduce the quality to a 70%.

Previously, all images of the website combined was around 800MB and after executing the script, it went down to a mere 70MB. The quality of the images weren't ruined and the aspect ratio didn't change. That's quite astounding.

Minify Javascript

Ever inspected someone's CSS or JS code on Chrome Debugger and saw something like this:

for(var a=[i=0];i<20;a[i]=i++);

This code above is unreadable but it still retains it's previous functionality:

var array = [];
for (var i = 0; i < 20; i++) {
    array[i] = i;
}

This process is known as minification. It's a way of removing all spaces, unnecessary characters and comments that would help reduce the size of the source code and make it more efficient to be transferred over the network.

Using a module bundler like Webpack, you can minify and merge all of your Javascript files into one sizeable chunk. Webpack's documentation is one of the worst that I have seen and I had to take help from StackOverflow to figure it out but however, it gets the job done.

Want to know to configure it? Check out this thread from StackOverflow for more in detail.

CSS Preprocessors to the rescue!

Trust me, these are life-savers. I used to hate writing a lot of CSS but now, I like writing CSS because of this reason. I chose SASS as my CSS preprocessor and it's basically CSS-on-steroids!

It's got some cool features like reusable CSS code, writing functions a.k.a @mixin and calling them using @include, nested syntaxes and import multiple CSS modules.

Writing in SASS is no different than writing in CSS but it allows you to modularize and organize your code in a fashionable manner. This allows you to even split CSS code to different modules, especially, if your HTML component uses a lot of CSS elements.

Oh, you can also create a minified version of your CSS code and push it into production.

Defer Javascript

The defer attribute used in the <script> tag will allow the JS file to be executed after the page has finished parsing all the DOM elements.

When the attribute is used, it'll look like this:

<script type="text/javascript" src="script.js" defer></script>

This could save a lot of time especially if it contains code that is not critical.

If you want to read more about it, click here.

Efficient database queries

As mentioned above, inefficient database queries could be detrimental to your website's performance. You can get rid of it with the following methods:

  • Maintain a good table structure
  • Keep your database architecture organized. Read more about Database Normalization
  • Keep your SQL query as simple as possible

Usage of clauses like WHERE, JOIN and GROUP BY are important but when it comes to performance, use it wisely.

PHP Page Caching

My company's website is mostly dynamic and I realized that all it does is fetch data from the servers to generate static information.

So, I thought of writing a caching module, in which, when any given page is accessed in the website, it would create a fully-generated static page with an expiry time of 5 minutes. So, when another user enters the same page, it will serve the static page, so no more delays for anyone.

This drastically reduced the load on the website's server because as mentioned above, it takes a lot of resources to create a page, dynamically.

You can find the source code of the caching module in my GitHub repository.

Refactor your codebase

Refactoring has a lot of benefits and in fact, it could reduce the size of your website, fix any unfixed bugs and more. All of which can contribute to an improved performance of your website.

So, please do yourself a favor and start cleaning up your codebase. If you don't know where to start, go here.

LazyLoad DOM Elements

Usually, whenever a page is opened by a user, it's contents are downloaded in a single go but this could be annoying if it disrupts the first view of the page.

So, what LazyLoad does is that instead of loading all of the content in a bulk, it only displays part of the content when a part of the page is accessed. The pages are created with a placeholder and will replace it with actual content only when the user needs it.

Examples of this can be seen in the form of:

  • Image galleries
  • Social media posts
  • Infinite scrolling
  • Pagination

This technique helps in performance but might create a negative impact on SEO in terms of webpage rankings.

If you want to give it a shot, try using this jQuery library.

Dedicated Server

Most hosting websites offer this service, you just have to buy a server and it would only host your website.

It's highly configurable and you won't have any issues regarding performance, however, it doesn't come without an expensive price tag on it but if you're willing to pay, it can be a great long-term investment.

Conclusion

If you've reached here, thank you for reading!

Let me know if any of these strategies have helped boost your website's performance and share it with other people too! Got more suggestions? Please send me an email and we can talk more about it.

Hope you liked reading this article!

Stay tuned for more!

Build your own toy spellchecker

Wrote a simple toy spellchecker using C++ by taking inspiration from Peter Norvig's article.

Spellcheckers and autocorrect, aren't they magical? They do feel like magic to me. I mean, how is it able to predict what word do you want to type?

According to Norvig, some of the most talented engineers at Google don't have a complete understanding of how a spellchecker works.

Peter Norvig's solution in Python is so elegant and simple, I don't think anyone can write better than that. However, I wanted to know how it works, so I thought of building it to understand it's functionality. Also, an excuse to exercise my C++ skills.

So, are you as curious as I am? If you are, I think you're in the right spot.

How it works?

Okay, so think about it? What does a spellchecker do? You type in a misspelled word and it returns a word with the highest probability, right?

Well, there's a little bit more to it.

Create a word dictionary

First, we must create a dictionary, in order to do that, you need to extract words from a large piece of text and store it in a Hashmap in which each word will have a word count. In this example, I've used a Sherlock Holmes novel (which is around 6MB). The words are extracted from a novel instead of an actual dictionary because it can be used to create a simple Language Model.

Source code to create a dictionary:

void SpellChecker::extractWords(string &filename)
{
    ifstream infile;
    infile.open(filename);
    string x;
    while(infile >> x)
    {
        x = filterAlpha(x);
        dictionary[x]++;
    }
}

string SpellChecker::filterAlpha(string &word)
{
    for(int i=0; i<word.size(); i++)
    {
        char ch = word[i];

        if(ch < 0)
        {
            word[i] = '-';
        }

        if(isalpha(ch))
        {
            word[i] = tolower(ch);
        }
    }
    return word;
}

Create a list of candidates

Second, we must able to predict/hypothesize the ways of editing text when the user types. It could be one of the following types of editing:

Based on the types of edits a user could make, we can generate a list of possible candidates by creating permutations using these edit methods mentioned above.

Adding a letter

In this method, you generate a list of candidates by inserting a letter in every iteration.

void SpellChecker::inserts(string &word, Vector &result)
{
    for(int i=0; i<word.size()+1; i++)
    {
        for(int j=0; j<alphabets.size(); j++)
        {
            char ch = alphabets[j];
            result.push_back(word.substr(0,i) + ch + word.substr(i));
        }
    }
}

Replacing a letter

In this method, you generate a list of candidates by replacing each character with a letter from a list of alphabets in every iteration.

void SpellChecker::replaces(string &word, Vector &result)
{
    for(int i=0; i<word.size(); i++)
    {
        for(int j=0; j<alphabets.size(); j++)
        {
            char ch = alphabets[j];
            result.push_back(word.substr(0,i) + ch + word.substr(i+1));
        }
    }
}

Switching two adjacent letters

In this method, you generate a list of candidates by switcing two adjacent letters in every iteration. For example: the word "ornage" would look like this: "orange", when the letters "n" and "a" are swapped.

void SpellChecker::transposes(string &word, Vector &result)
{
    for(int i=0; i<word.size()-1; i++)
    {
        result.push_back(word.substr(0,i) + word[i+1] + word[i] + word.substr(i+2));
    }
}

Removing a letter

In this method, you generate a list of candidates by removing a letter in every iteration.

void SpellChecker::deletes(string &word, Vector &result)
{
    for(int i=0; i<word.size(); i++)
    {
        result.push_back(word.substr(0,i) + word.substr(i+1));
    }
}

All of these methods are called in one wrapper method:

void SpellChecker::edits(string &word, Vector &result)
{
    //Deletion
    deletes(word, result);

    //Transposition
    transposes(word, result);

    //Replacement
    replaces(word, result);

    //Insertion
    inserts(word, result);
}

Extract the known words

Third, at this stage, the above step would've generated a huge list of words but 90% of them would be gibberish, so we need to "clean" the list and extract the known words using the dictionary we've created.

void SpellChecker::known_words(Vector& results, Dictionary &candidates)
{
    Dictionary::iterator end = dictionary.end();

    for(int i=0; i<results.size(); i++)
    {
        Dictionary::iterator val = dictionary.find(results[i]);

        if(val != end)
        {
            candidates[val->first] = val->second;
        }
    }
}

The edits() method apply to words that have a edit distance of 1, what if it was 2 or more? Like if the user typed "the", it could've been "then" or "they". So, all you have to do is create a method that generates a new set of permutations based on the already generated list of edited words and extract the known words.

void SpellChecker::edits2(Vector &result, Dictionary &candidates)
{
    for(int i=0; i<result.size(); i++)
    {
        Vector edit2;

        edits(result[i], edit2);
        known_words(edit2, candidates);
    }   
}

Display the correct word

In order to determine the correct word, the following possibilities are considered:

  1. Check if this word is in the dictionary, if it does, display it.
  2. Generate known words that have an edit distance of 1 and check in the dictionary, if it does, display it.
  3. Generate known words that have an edit distance of 2 and check in the dictionary, if it does, display it.
  4. If all else fails, this word is unique or not a known word.

string SpellChecker::correct(string &word)
{
    Vector result;
    Dictionary candidates;

    string file = "big.txt";

    //1. if it's in the dictionary, display it
    if(dictionary.find(word) != dictionary.end())
    {
        return word;
    }

    extractWords(file);

    edits(word, result);
    known_words(result, candidates);

    //2. if it's a known word but one edit away
    if(candidates.size() > 0)
    {
        return max_element(candidates.begin(), candidates.end())->first;
    }

    //3. if it's a known word but two edits away
    edits2(result, candidates);

    if(candidates.size() > 0)
    {
        return max_element(candidates.begin(), candidates.end())->first;
    }

    //4. Display nothing if it doesn't exist
    return "This word doesn't exist!";
}

However, for conditions 2 and 3, the word displayed would most likely have the highest word frequency in the dictionary.

Conclusion

Phew! I hope that wasn't a long read. Although, I've written this on C++, I plan to rewrite this on Javascript for some of my future projects.

To be honest, I don't think it's completely accurate, although, I got most of the words correct when tested.

The source code can be found on my GitHub repository.

Hope you liked reading this article!

Stay tuned for more!

The 15 Puzzle Game

A classical numbered puzzle that requires the player to place all the tiles in an ordered sequence.

Before you read this article, play with the above puzzle. You can move the block around by left-clicking on a numbered tile that's adjacent to the empty tile.

The source code for this puzzle can be found over here.

Background

This is a game that has been on my list of projects for a long time and I've finally decided to work on it last night. Although, this post has nothing to do with Artificial Intelligence, I was inspired to write this game when I studied about Heuristics in the book named Artificial Intelligence: A Modern Approach and on how it was applied to this game.

What are the game mechanics?

This game is played on a four-by-four grid with numbered tiles that are shuffled randomly. As you can see, there are 15 numbered cells and 1 empty cell in the grid, this is to allow movement of the tiles within the grid.

However, the movement is limited to the numbered tiles that are adjacent to the empty tile.

The player wins the game after ordering all the numbered tiles in the grid in an order of ascending sequence.

Source code

Here's the source code of the entire game:

var board = [], rows = 4, cols = 4;
var possibleMoves, zx, zy, oldzx = -1, oldzy = -1;

//Generate 2D Board
function generateBoard()
{
    for(var i=0; i<rows; i++)
    {
        board[i] = [];
    }

    for(var j=0; j<cols; j++)
    {
        for(var i=0; i<rows; i++)
        {
            board[j][i] = (i + j * 4) + 1;
        }
    }

    //position of the empty cell in the grid i.e. 3,3
    zx = zy = 3;
    board[zx][zy] = 16;
}

//Generate the cells
function generateCells()
{
    var grid = document.createElement("div");
    grid.className += "board";

    document.body.appendChild(grid);

    for(var j=0; j<4; j++)
    {
        for(var i=0; i<4; i++)
        {
            var cell = document.createElement("div");
            cell.className += "cell";
            cell.id = "cell_" + (i + j * 4);
            cell.row = i;
            cell.col = j;
            cell.addEventListener("click", cellEventHandle, false);
            cell.appendChild(document.createTextNode(""));
            grid.appendChild(cell);
        }
    }
}

/*
    Determine the possible number of moves
    based on the empty cell's coordinates.
*/
function genPossibleMoves()
{
    possibleMoves = [];
    var ii, jj;

    /*
        Just for reference:
        The empty cell can be moved in the following x,y coords:
        -1,0, 0,-1, 1,0, 0,1
    */
    var xCoords = [-1, 0, 1, 0];
    var yCoords = [0, -1, 0, 1];

    for(var i=0; i<4; i++)
    {
        ii = zx + xCoords[i];
        jj = zy + yCoords[i];

        //If it's out of bounds, skip it
        if(ii < 0 || jj < 0 || ii > 3 || jj > 3)
        {
            continue;
        }

        possibleMoves.push({x: ii, y: jj});
    }
}

function updateCells()
{
    for(var j=0; j<cols; j++)
    {
        for(var i=0; i<rows; i++)
        {
            var cell_id = "cell_" + (i + j * 4);
            var cell = document.getElementById(cell_id);
            var val = board[i][j];

            if(val < 16)
            {
                cell.innerHTML = ("" + val);
                if(val % 2 == 0)
                {
                    cell.className = "cell dark";               
                }
                else
                {
                    cell.className = "cell light";
                }
            }
            else
            {
                cell.innerHTML = "";
                cell.className = "empty";
            }
        }
    }
}

//Event handler for each cell
function cellEventHandle(e)
{
    genPossibleMoves();

    //Current coords of the cell
    var r = e.target.row;
    var c = e.target.col;
    var pos = -1;
    var isPossible = false;
    // console.log(r + "," + c);

    /*
        Check if the current cell is 
        one of the possible moves
    */
    for(var i=0; i<possibleMoves.length; i++)
    {
        if(possibleMoves[i].x == r && possibleMoves[i].y == c)
        {
            isPossible = true;
            pos = i;
            break;
        }
    }

    if(isPossible)
    {
        var temp = possibleMoves[pos];

        //Swap position of the empty cell
        board[zx][zy] = board[temp.x][temp.y];
        //Update the coordinates of the empty cell
        zx = temp.x;
        zy = temp.y;
        board[zx][zy] = 16;
        updateCells();

        //Check if the game is over
        if(is_game_over())
        {
            setTimeout(function(){
                alert("Congrats!");
            }, 2);
        }
    }

}

//Check if the game is over
function is_game_over()
{
    var currentVal = 0;
    for(var j=0; j<cols; j++)
    {
        for(var i=0; i<rows; i++)
        {
            if(board[i][j] < currentVal)
            {
                return false;
            }

            currentVal = board[i][j];
        }
    }
    return true;
}

//Shuffle the board
function shuffleBoard()
{
    var shuffleLimit = 0;
    var temp;

    do
    {
        genPossibleMoves();

        while(true)
        {
            // Pick a random cell of possible moves
            temp = possibleMoves[Math.floor(Math.random() * possibleMoves.length)];
            if (temp.x != oldzx || temp.y != oldzy)
            {
                break;
            }
        }

        oldzx = zx;
        oldzy = zy;

        board[zx][zy] = board[temp.x][temp.y];
        zx = temp.x;
        zy = temp.y;
        board[zx][zy] = 16;

    }while(++shuffleLimit < 200);
}

//REstart the game
function restart()
{
    shuffleBoard();
    updateCells();
}

//Start the game
function start()
{
    generateBoard();
    generateCells();
    restart();
}

As I had mentioned above, today's article has nothing to do with Artificial Intelligence but in the future, I plan to write a solver for this game that makes use of Heuristics.

Hope you liked reading this article and have fun playing the game!

Stay tuned for more!

Keep a programming journal using VIM and Bash

Become a better programmer by writing your own programming journal using VIM and Bash.

Back in the days of Polymath scientists, physicists and engineers like Leonardo Da Vinci and Albert Einstein, they usually maintained a sort of journal to record their thoughts, ideas and experiments.

It's been 20 days since I have started maintaining journals, one is for personal stuff and the other is for programming, engineering and math related stuff, I mean, we all need to have some new hobbies to keep ourselves productive, right?

Maintaining a journal helped me create a flow to write down my experiences ofthe day. It also helps me clear my mind and be more emotionally stable (I get moody, sometimes) and record my thoughts and ideas too.

There are so many ways to write a journal like you could sign up on some online platform, install Evernote on your desktop or mobile or traditional pen and paper (which is the best way, honestly).

Requirements

I thought of keeping it in my laptop and I wanted it to have the following features:

  1. No use of internet required
  2. Must be super fast, simple and precise to the point
  3. Privacy (I mean, you can't trust the internet, sometimes!)
  4. Record thoughts and ideas with a timestamp, similar to a logbook
  5. Yes, it must look cool and nerdy

I looked on some options like Google Docs, Dropbox Paper and Evernote but I just wanted something that matches my requirements. I went on YouTube and I saw a guy named Mike Levin, who made a video named "VIM Journalcasting Experiment" and it inspired me to create something like that too.

Setup

First, you need to create a directory to store your journal notes and create a file to create them:

mkdir journal
cd journal
touch writer.sh
chmod u+rwx writer.sh

Next, you need to write a few lines of code in Bash:

#!/bin/bash

folder=`date +%Y_%m_%d`
mkdir -p $folder
cd $folder

vi +star `date +%Y%m%d`".jrnl"

One more step, create an alias on your bash_profile in order to access it from anywhere:

alias jrnl="cd /journal;./writer.sh"

Alright, that's the basic setup! To test it, just do the following in your Terminal:

journal

VIM Customization

Are you one of those people who gets confused on how to get out of VIM? Don't worry, you'll figure it out over here!

The following setup can be done in your ~/.vimrc file to enhance your journaling experience like adding a spellchecker, word counter, highlight colors and so on.

Below are the configurations:

set spell spelllang=en_gb
cmap <F6> setlocal spell!

function! WordCount()
        let s:old_status = v:statusmsg
        let position = getpos(".")
        exe ":silent normal g\<c-g>"
        let stat = v:statusmsg
        let s:word_count = 0
        if stat != '--No lines in buffer--'
                let s:word_count = str2nr(split(v:statusmsg)[11])
                let v:statusmsg = s:old_status
        end
        call setpos('.', position)
        return s:word_count
endfunction

hi User1 ctermbg=black ctermfg=red cterm=BOLD guibg=black guifg=red gui=BOLD

set laststatus=2
set statusline=
set statusline+=%1*
set statusline+=%<\

Now, you can start writing your own journal whenever and wherever you want using VIM.

Conclusion

I'm not saying that you should write your journal on VIM, I thought it would be fun if I could do it on VIM, so that I get a chance to learn it. However, you can do it on Notepad too!

Apart from that, journaling does have a lot of benefits and can help you become more productive!

Get your ideas floating and start building cool stuff!

Hope you liked reading this article!

Until next time, then!

Stripe's Scrolling Bubble Header

An insight into Stripe's interesting use of animated elements.

Want to know how to make it on your own? Read the article below!

If you're a UI/UX developer, you've probably heard about Stripe.com and their uses of motion and design with their targeted audience in mind.

As I was exploring their website, I discovered their customers page and instantly, I was intrigued by their smooth scrolling bubble header and the concept was interesting enought that it caught my attention.

In this article, I'll explain on how I had attempted to recreate their scrolling bubble header.

Analysis

The mechanics are pretty simple to understand, these are the following:

  • The bubbles are randomly generated and placed on page load
  • Smooth animation of the up and down movements
  • Infinite animation loop

A trivial problem, isn't it? Time to see if we can recreate it!

Step 1: Create the bubble

Let's write the CSS to create a simple bubble with a width and height of 150px and by giving it a border-radius of 50%.

.stripe-bubble {
    width: 150px;
    height: 150px;
    border-radius: 50%;
}

As for the logo, I inspected their code and figured out that Stripe combined all of their customer logos into a single image, also known as, CSS Spritesheet.

Performance-wise, it's a clever technique used to reduce the number of HTTP requests that your internet browser has to make on every page request.

Let's give the CSS spritesheet as a background-image property and adjust it enough to fit the size of one bubble.

.stripe-bubble {
    position: absolute;
    width: 150px;
    height: 150px;
    border-radius: 50%;
    background-image: url('https://www.stripe.com/img/v3/customers/logos/header-logos.png');
    box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1), 0 3px 10px rgba(0, 0, 0, 0.1);
    background-size: 1076px 1076px;
}

There are about 43 logos, which means you'll have to create different logos by adjusting the background position property.

.logo-1 {
    background-position: 0 0;
}

.logo-2 {
    background-position: 0 -154px;
}

.logo-3 {
    background-position: 0 -308px;
}

In the next step, using JavaScript, we'll create the classes for the bubbles and the header.

Step 2: Create a class for Bubble

Before we get in deep, let's create the foundation for our code, so that it'll make things neat and tidy and easier on the go. Below, I have created two classes: one is for the bubble and the other is for the bubble wrapper (no puns):

class Bubble {
    constructor(){}
    update(){}
}

class BubbleMarquee {
    constructor(){}
    update(){}
}

Great, you have created the classes, we can now use these to generate the bubbles dynamically in the next step.

Step 3: Bubble's scale and position

As you see in the image above, the logos are randomly placed and scaled. It's clear that there has to be some sort of a pattern, so I decided to take a look into their code:

Aha! I discovered that the positioning and scaling of the bubbles are hard-coded and then the logos order are randomly shuffled. I won't be adding a randomizer but for now, let's add the bubbles with it's specifications and respective logos.

const bubbleSettings = [
    {cssClass:'logo-imgAffirm', s: .6, x: 77, y: 1134 }, 
    {cssClass:'logo-imgAllianz', s: .6, x: 271, y: 1620 }, 
    {cssClass:'logo-imgAmazon ', s: .6, x: 372, y: 1761 }, 
    {cssClass:'logo-imgBookingCom', s: .6, x: 79, y: 2499 }, 
    {cssClass:'logo-imgCatawiki', s: .6, x: 334, y: 2704 }, 
    {cssClass:'logo-imgCityofBoston', s: .6, x: 356, y: 2271 }, 
    {cssClass:'logo-imgDeliveroo', s: .6, x: 226, y: 795 }, 
    {cssClass:'logo-imgDoordash', s: .6, x: 256, y: 276 }, 
    {cssClass:'logo-imgExpedia', s: .6, x: 365, y: 1210 }, 
    {cssClass:'logo-imgFitbit', s: .6, x: 193, y: 444 }, 
    {cssClass:'logo-imgGoogle', s: .6, x: 387, y: 2545 }, 
    {cssClass:'logo-imgIndiegogo', s: .7, x: 193, y: 1303 }, 
    {cssClass:'logo-imgInstacart', s: .7, x: 88, y: 907 }, 
    {cssClass:'logo-imgKickstarter', s: .7, x: 320, y: 633 }, 
    {cssClass:'logo-imgLyft', s: .7, x: 76, y: 323 }, 
    {cssClass:'logo-imgNasdaq', s: .7, x: 357, y: 129 }, 
    {cssClass:'logo-imgNat-Geo ', s: .7, x: 342, y: 1440 }, 
    {cssClass:'logo-imgRackspace', s: .7, x: 293, y: 1929 }, 
    {cssClass:'logo-imgReddit', s: .7, x: 198, y: 2135 }, 
    {cssClass:'logo-imgSalesforce', s: .7, x: 82, y: 2276 }, 
    {cssClass:'logo-imgShopify', s: .7, x: 182, y: 2654 }, 
    {cssClass:'logo-imgSlack', s: .7, x: 75, y: 2783 }, 
    {cssClass:'logo-imgSpotify', s: .7, x: 118, y: 1519 }, 
    {cssClass:'logo-imgSquarespace', s: .7, x: 233, y: 1071 }, 
    {cssClass:'logo-imgTarget', s: .7, x: 148, y: 1773 }, 
    {cssClass:'logo-imgTed', s: .7, x: 385, y: 2098 }, 
    {cssClass:'logo-imgTheGuardian', s: .7, x: 244, y: 2423 }, 
    {cssClass:'logo-imgTwitch', s: .7, x: 385, y: 901 }, 
    {cssClass:'logo-imgUber', s: .7, x: 111, y: 624 }, 
    {cssClass:'logo-imgWeTransfer', s: .7, x: 103, y: 145 }, 
    {cssClass:'logo-imgWish', s: .7, x: 367, y: 413 }, 
    {cssClass:'logo-imgXero', s: .7, x: 251, y: 2805 }, 
    {cssClass:'logo-imgYelp', s: .7, x: 75, y: 1990 }
];

class Bubble {
    constructor(index, {cssClass, x, y, s=.9}){
        this.index = index;
        this.x = x;
        this.y = y;
        this.scale = s;
        this.cssClass = cssClass;

        this.el = document.createElement("div");
        this.el.className = `stripe-bubble ${this.cssClass}`;

        marqueeEl.appendChild(this.el);
    }

    update(){}
}

class BubbleMarquee{
    constructor(settings){
        this.bubbles = [];

        settings.forEach((setting, index) =>{
            this.bubbles.push(new Bubble(index, setting));
        });
    }
    update(){}
}

Okay, now off to animating the bubbles!

Step 4: Animation

You could use absolute positioning properties like top and left but it'd be really expensive in terms of calculations, instead of that, you could use transform to move the elements.

this.el.style.transform = `translate(${this.x}px, ${this.y}px) scale(${this.scale})`;

As for the animation, you could use setInterval but don't do that, stop here and read about requestAnimationFrame.

constructor(settings){
    this.bubbles = [];

    settings.forEach((setting, index) =>{
        this.bubbles.push(new Bubble(index, setting));
    });

    requestAnimationFrame(this.update.bind(this));
}

update(){
    this.bubbles.forEach(bubble => bubble.update());
    this.raf = requestAnimationFrame(this.update.bind(this));
}

Alright, you've done it! It's animating and looks cool but hey, did you notice that there animation doesn't look stale but is more organic-like? That's because they have added some random movement to each bubble.

I took another peek at their code, I found out that they were using Perlin noise to smoothen the animation movements. Unlike, Math.random(), I got to know that it's an algorithm used to generate a sequence of randomness that has some order, which helps create a smooth, organic movement.

I didn't implement the algorithm instead I made use of an existing implementation written by Seph Gentle found on GitHub.

This is how your update() method should look like after adding the Perlin Noise:

update(){
    this.noiseSeedX += noise_speed;
    this.noiseSeedY += noise_speed;

    var randomXPos = noise.simplex2(this.noiseSeedX, 0);
    var randomYPos = noise.simplex2(this.noiseSeedY, 0);

    this.y -= scrollingSpeed;

    this.xNoisePos = this.x + (randomXPos * noise_amnt); 
    this.yNoisePos = this.y + (randomYPos * noise_amnt); 

    if(this.y < -500)
    {
        this.y = canvas_width;
    }

    this.el.style.transform = `translate(${this.xNoisePos}px, ${this.yNoisePos}px) scale(${this.scale})`;
}

After adding that, you have finally achieved what you wanted! Oh, you can find the source code for this project on my GitHub repository.

Conclusion

I hope you enjoyed reading this blog article and learnt something new. If you have questions, please send me your thoughts and I would be happy to help you out!

Thank you for reading!

Stay tuned for more!

Poker Hand Analyser in Python

An algorithm that parses a five-card poker hand and determines it's rank.

I've never played Poker and don't think I ever will because I'm not a fan of gambling and placing bets. However, I ran into an interesting problem on Project Euler that led me to write a poker hand analyser to determine the rank of each hand.

Before writing this article, I didn't know anything about cards or Poker, I had to do some research on Wikipedia about it. So, forgive me if there's any information that's not accurate in the article.

Poker Hands

From what I had understood, a hand is a set of five cards and each card has a rank, which is in the order shown below:

Cards are valued in the order of lowest to highest (Left to Right):
2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, King, Ace

Based on the card pattern formed in each hand, the ranking category is determined and it's ranked within it's category based on the ranks of it's cards.

Hand Ranking Categories

In Poker, there are about 10 ranking categories from lowest to highest:

Before diving into the code snippets, I wrote a library named poker_lib.py which contains all the methods used in the code snippets.

To make things simple, I created a class named Card that has two attributes, face and suit, with namedtuple() as it's datatype.

High Card

This hand contains no pairs and it doesn't fall into any other category.

def high_card(hand):
    # collect all faces from each card
    allfaces = [f for f,s in hand]

    #sort the faces and show the highest card
    return "high_card", sorted(allfaces, key=lambda f: allfaces.index(f), reverse=True)[0]

One Pair

This hand contains two cards of one rank and three cards of three other ranks.

def one_pair(hand):
    allfaces = [f for f,s in hand]
    allftypes = set(allfaces)

    # collect pairs
    pairs = [f for f in allftypes if allfaces.count(f) == 2]

    # if there's more than one pair
    if len(pairs) != 1:
        return False

    allftypes.remove(pairs[0])
    return 'one-pair', pairs + sorted(allftypes, key=lambda f: face.index(f), reverse=True)

Two Pairs

This hand contains two cards of one rank, two cards of a second rank and one card of a third rank.

def two_pair(hand):
    allfaces = [f for f,s in hand]
    allftypes = set(allfaces)

    # collect pairs
    pairs = [f for f in allftypes if allfaces.count(f) == 2]

    # if there are more than two pairs
    if len(pairs) != 2:
        return False

    p1, p2 = pairs
    # get the difference using sets
    other_cards = [(allftypes - set(pairs)).pop()]
    return 'two-pair', pairs + other_cards if(face.index(p1) > face.index(p2)) else pairs[::-1] + other_cards

Three of a Kind

This hand, also known as trips or a set, contains three cards of one rank and two cards of two other ranks.

def three_of_a_kind(hand):
    allfaces = [f for f,s in hand]

    uniqueRanks = set(allfaces)

    if len(uniqueRanks) != 3:
        return False

    for f in uniqueRanks:
        if allfaces.count(f) == 3:
            uniqueRanks.remove(f)
            return "three-of-a-kind", f

    return False;

Straight

This hand contains five cards arranged in a sequential order but not all of them have same suits.

def straight(hand):
    ordered = sorted(hand, key=lambda card: (faces.index(card.face), card.suit))
    if ''.join(card.face for card in ordered) in ''.join(face):
        return 'straight', ordered[-1].face
    return False;

Flush

This hand contains five cards of the same suit and not necessarily arranged in sequential order.

def flush(hand):
    allfaces = [f for f,s in hand]

    first_card = hand[0]
    other_cards = hand[1:]

    if all(first_card.suit == card.suit for card in other_cards):
        return 'flush', sorted(allfaces, key=lambda f: face.index(f), reverse=True)

    return False

Full House

This hand, also known as full boat or a boat, contains three cards of one rank and two cards of another rank.

def full_house(hand):
    allfaces = [f for f,s in hand]

    rankFrequency = pe_lib.character_frequency(allfaces)

    # if there are 2 types of ranks and there's a card with 1 pair and 3 of a kind
    if len(rankFrequency) == 2 and (rankFrequency.values()[0] == 2 and rankFrequency.values()[1] == 3):
        return 'full-house'

    return False

Four of a Kind

This hand, also known as quads, contains four cards of one rank and one card of another rank.

def four_of_a_kind(hand):
    allfaces = [f for f,s in hand]

    # create a unique set of ranks
    uniqueRanks = set(allfaces)

    # if there are more than 2 ranks, it's not four of a kind
    if len(uniqueRanks) != 2:
        return False

    for f in uniqueRanks:
        # if there are 4 faces, it is four of a kind
        if allfaces.count(f) == 4:
            uniqueRanks.remove(f)
            return "four-of-a-kind", f

    return False

Straight Flush

This hand contains five cards arranged in a sequential order with all cards having the same suit.

def straight_flush(hand):
    # sort the cards based on the face rank of each card
    ordered = sorted(hand, key=lambda card: (faces.index(card.face), card.suit))

    first_card = ordered[0]
    other_cards = ordered[1:]

    # check if all are of the same suit
    if all(first_card.suit == card.suit for card in other_cards):
        # check if they are in sequential order
        # compare the ordered faces substring with the face list (which is converted to string)
        if ''.join(card.face for card in ordered) in ''.join(face):
            return 'straight-flush', ordered[-1].face
    return False

Royal Flush

This hand contains the royal ranks in sequential order in the same suit.

def royal_flush(hand):
    royalface = "TJQKA"
    # sort the cards based on the face rank of each card
    ordered = sorted(hand, key=lambda card: (faces.index(card.face), card.suit))

    first_card = ordered[0]
    other_cards = ordered[1:]

    # check if all are of the same suit
    if all(first_card.suit == card.suit for card in other_cards):
        # check if they are in sequential order
        # compare the ordered faces substring with the face list (which is converted to string)
        if ''.join(card.face for card in ordered) in royalface:
            return 'royal-flush', ordered[-1].face
    return False

Conclusion

It was a fun project to work on and I learnt new styles of array and string manipulation techniques using Python.

Inspired by this, I'm planning to create an interactive version of this project using Javascript and talk about it on another article.

The code for this program can be found in my GitHub repository.

Hope you liked reading this article!

Stay tuned for more!

Project Euler solutions

A collection of Project Euler solutions

In order to get good at anything, not only at programming, it would require a good amount of practice. Three years ago, I started out solving Project Euler problems on C++ and Java for fun, which taught me how to write good code in short of amount of time.

However, you'll notice that I have written the solutions using Python as I wanted to improve my Python coding skills and yes, just to code for fun!

This blog article will have all the links available to everyone to learn from and understand the solutions and you can access it on my GitHub repository.

Solution code

In addition, I have created a math library module named pe_lib.py, which contains all the mathematical functions that are used in every problem. I find it pretty useful as it allows me to re-use some of the functions instead of re-writing it for each solution.

Problem Link Solution Link

Hope you'll find these solutions to be useful!

Stay tuned for more!

The Alchemist by Paulo Coelho

A story about a young shepherd who starts his journey to chase his Personal Legend.

I don't really read fiction books a lot but this is one of my favorites. I finished reading this book last week and it had inspired me and made me feel positive towards the goals that I wanted to chase in my life.

Why did I choose to read it?

On one fine evening, I was going through my endless list of bookmarks and I stumbled upon a link, which had a collection of book recommendations on what are most influencial books for software engineers to read and I found this in the list of recommendations. So, I thought of trying it out on my new Amazon Kindle Paperwhite too.

About the story

The book is written by Paulo Coelho. As mentioned in the description, it's about a young shepherd named Santiago who starts a journey after having dreams about finding treasure in the Pyramids of Egypt. Without spoiling a lot, he meets several people such as an old man who claims to be a king, a woman of the desert that he falls in love with and an alchemist who wants to learn the technique of converting lead to gold.

In the first few pages, the quotes said by the characters really stuck into my head:

Whoever you are, or whatever it is that you do, when you really want something, it's because that desire originated in the soul of the universe. It's your mission on earth.

Funny but when I relate myself to the story, I'm currently on my own Personal Legend. Just like the shepherd himself, I started my journey with a vision and a willingness to pursue it. I didn't have the faintest clue on how to achieve my goals but I knew that I can and had to do it.

Everything is clear and everything is possible!

Santiago learns different lessons throughout his journey. One of the first lessons is when he had a conversation with a mysterious king. The king told the boy that everyone used to tell him, when everyone is young, they know what their Personal Legend is and as he quotes:

At that point in their lives, everything is clear and everything is possible. They are not afraid to dream, and to yearn for everything they would like to see happen to them in their lives. But as time passes, a mysterious force begins to convince them that it will be impossible for them to realize their Personal Legend.

It relates a lot to the real world scenario because I see a lot of people who want to settle in their life. Safe place to live, marriage, kids, comfortable job, $401K plans and then off to retirement. But what happens after that? Settled in life? Yes, but did they achieve their dreams? Now, that's a question not everyone can answer, can they?

Listen to your heart and soul

In some parts of the book it states that once you stop listening to your heart and soul telling you to chase your dreams, it will, spontaneously, appear again for the next year or so and then, your heart and soul will stop talking to you and the dream fades away.

Conclusion

It's a simple story that has got elements of economy, love, war and pursuit of dreams. We all have our own highs and lows in life and I would recommend this book as a must-read for anyone who's currently trying to figure out their actual purpose in life. As you read the book, you'll relate yourself to Santiago and you'll start recommending this book to your friends too!

Hope you liked reading this article!

Stay tuned for more!