My experience on my daily works... helping others ease each other

Saturday, June 13, 2020

Caching an Inverse of a Matrix Using R



Caching an Inverse of a Matrix Using R 

Matrix inversion is usually a costly computation and there may be some benefit to caching the inverse of a matrix rather than computing it repeatedly.

This is an example code to cache an inverse of a matrix which then called if:

1. The new matrix computation similar to the previous matrix
2. Matrix is invertible — Read Invertible Matrix
3. The structure and content of the new matrix is equal to previous

The program consists of two functions

  1. A function to cache the matrix and the inverse. It is similar to getter and setter in many programming languages like Java and C.
  2. A function which will be call for the computational process of the matrix

Here are parts of the code:

Setting the matrix
Setting the inverse matrix
Verification on the matrix
Setting the new inverse

Complete source code is reachable at https://github.com/masteramuk/ProgrammingAssignment2

If you like the post, do buy me a coffee please :)

Buy Me A Coffee
Share:

Monday, June 1, 2020

Reading entire URL content is really easy using R

In my good old days, reading the entire content of a website is not easy. The process of web scraping and getting the required data requires lots of programming and a few tools. A friend of mine even developed and sold the tool which he called it (during the development) as myrobot. He developed using PHP.

Now, it is much easier and one of the many ways is using R.

Here are the steps (which requires you to write ONLY two lines of code)

  1. Connect to the website using URL command
    con <- url ([the website url], “r”)
  2. Then, read the website
    x <- readLines(con)
  3. Do whatever you wish with the data. In this example, I print out the head of the website and also copy the whole content to a file.
    head(x)
    dput(x, “readFromUrlExample.html”)

There you go.

Result of the head(x) function
Snapshot of the content of the file copied into readFromUrlExamplehtml

The sample source code can be retrieved at 

https://github.com/masteramuk/LearnR-Coursera/blob/master/sample-ReadFromUrl.R

Share:

Friday, May 29, 2020

Solving Committing Issue between R Studio and Github


Solving Committing Issue between R Studio and Github

In the normal development process, you will create a repo (the repo in this article is located at Github), followed by the cloning process or download as full directory into your localhost. It is much easier and straightforward. There won’t be any issues especially if your scrum master or release manager is a well trained person in handling branching, merging, and releasing code using git.


However, in most cases, especially for a full-stack developer who did everything on its own, you may encounter an issue if:

  1. You created a project in your localhost first using R Studio and set Git as your SVN through your project setting
  2. Then you created the repo at the GitHub
  3. Finally, upon ready, you run command to sync with your GitHub

The following is the command that you use/execute and the result of running the command:

% git remote add origin [your GitHub report url]
% git pull origin master
warning: no common commits
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
From [your GitHub report url]
* branch master -> FETCH_HEAD
* [new branch] master -> origin/master
fatal: refusing to merge unrelated histories

and you see the last sentence .. ERROR


Then, based on google, you followed with the following command

% git push -u origin master

and you get the following response (or similar)

To [your GitHub report url]
! [rejected] master -> master (non-fast-forward)
error: failed to push some refs to ‘
[your GitHub report url]'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: ‘git pull …’) before pushing again.
hint: See the ‘Note about fast-forwards’ in ‘git push — help’ for details.

Next, you try to pull again to get the latest branch based on the previous error by running the command to pull again

% git pull origin master

And the result is still not promising 
From [your GitHub report url]
* branch master -> FETCH_HEAD
fatal: refusing to merge unrelated histories

What are you missing or wrongly done? I won’t be able to tell you the missing or wrong steps, but I’m sharing your step to overcoming the problem.


STEPS

  1. Go to you localhost directory where you created the project
  2. In that directory, you should find a file name .gitignore & folder .git
  3. Delete both by running rm -fr (if you are using windows, the command might be different)
  4. Next, init your project file again by running the command git init. You shall see the following message appear after executing the command — Initialized empty Git repository in [your project path]
  5. Followed by adding the remote repo by running the command git remote add origin [your GitHub repo url]
  6. The followed by git add . (make sure there is ‘.’ at the end of the command). It tells the git to add all directories in the remote repo to your local.
  7. Followed by git pull origin master. If succeed, you shall be able to see the following result:
    remote: Enumerating objects: 3, done.
    remote: Counting objects: 100% (3/3), done.
    remote: Compressing objects: 100% (2/2), done.
    remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
    Unpacking objects: 100% (3/3), done.
    From [your GitHub repo url]
    * branch master -> FETCH_HEAD
    * [new branch] master -> origin/master
  8. Finally, run git push -u origin master to verify again. You shall see the following result to indicate it is successfully integrated between your local repo and your Github repo and R Studio shall be able to interact perfectly with GitHub.
    Branch ‘master’ set up to track remote branch ‘master’ from ‘origin’. Everything up-to-date

Once you have done all the steps, go ahead to your R Studio and perform Stage -> Commit -> Commit Message -> Push to complete the process. Refresh your Github page and you shall see all of your local files at your GitHub repo.

If you find this useful, you can buy me a coffee :) @ https://www.buymeacoffee.com/masteramuk

Share:

Monday, May 25, 2020

Solving Internet Router Problem - TM Unifi NETIS DL4480V

TM Unifi NETIS DL4480V Connectivity Problem

After a while, the NETIS DL4480V router provided by TM upon subscribed to TM Streamyx (or TM Unifi lite) will fail to work properly. Your internet connection may be up and down or worst the router itself will frequently disconnected or restart.

Before that happen, in case you need to reset your router, Please DO NOT go to https://easyfix.unifi.com.my/ or https://easyfix.unifi.com.my/reconfigure_wifi_netis

It is useless (worth to try but it won’t be helpful enough).

You can even call their call-center line at 100 and the best guidance you can get is just to confirm your username and password again and resetting your port. It may work or may not work at all. If it works, you still need to tweak on your own (or worst, wait for their technician to drop by, which may take 1, 2, 3 days or even week after you file your report unless you keep bugging them via SOCMED or phone call if you are in dire need of internet connectivity).

Why I stated that you need to tweak on your own. This is because the technician will only install and use the basic setting to set up your router. They won’t do extra miles to ensure that your internet connection is superb. There are a few things you can do to improve your internet connection. Before that, let us do simple tweaking and have a stable connection first.

There are few links here that might help you in tweaking it (IF it still able to connect to TM Switches PERMANENTLY, but failed to connect to any website).

1. https://www.youtube.com/watch?v=CX0PXujZbAs
2. https://www.youtube.com/watch?v=Awf4RK5z-V4&app=desktop
3. http://hotspotsystem.com.my/index.php?route=pavblog/blog&blog_id=209

Well, that shall do it. If the problem persists, just get them to send the technician ASAP and request to change the router. This might be the core problem of failure like mines. That’s it… or you can buy your own router and make sure it is VDSL2 (for unifi/fiber) ya.

The final step is to tweak a little bit more to have a better connection. You may not be needed if you think yours is working fine.

1. Disable some of the security features. Please, do this IF you are using it for your OWN purpose and not to setup for openly accessible wifi. You may disable firewall, IDS, IPS setting or tweak it to your own need. To do this, you need to login to your router page at 192.168.1.1 and go to security section (normally at Advance tab)
2. Change the DNS (from automatic to manual) and follow the following few links

Adios

TM Unifi NETIS DL4480V Connectivity Problem

Share:

Sunday, April 26, 2020

Improving your Telegram Security


Telegram’s user continues to increase and recently it reaches 400 million user per month
Since its birth, there are many features added plus friendly API allowing various innovative ideas add-in to its base. 



But, having lots of features may also result in lots of possibilities for hacking. One of the many features that may be wrongly used is the Automatic Media Download. 

As noob @ beginner, many do not realize it until their phone or PC slow due to disk space has shrunk as telegram keeps on automatically download all files. 

The most scarier is that the auto-play anything including GIF, video, and audio. All this can be used by hackers to insert a code and inject it upon executed/run by telegram.

However, luckily telegram allow us to modify the setting. Here are the steps to change it:
  1. Go to your telegram setting and choose Advance
Telegram setting window
2. At the Advance screen, go to Automatic media download section
In the Advance setting
3. Click In private chats
In automatic media download setting
4. In the setting, click all the slide-tick to disable it (or you can choose whichever you want to enable or disable). You can even reduce the size to increase the protection rate.

5. Continue the process for all settings within the Automatic media download section.



That’s all.. you are ready to go and you shall be safe.
Share:

Saturday, April 18, 2020

Tableau Public - Apple Mobility Data and Dark Mode

I've been working on 2 visualizations. 1 is based on Apply Mobility Data and the other is based on edited Sample Superstore.

Check it out here.

Mobility Data based on Apple's mobility data.



Grid on Dark Mode based on Tableau Sample Superstore (edited version)

All visual is available at https://public.tableau.com/profile/nurul.haszeli.ahmad#!/

All dataset is available at data.world @ https://data.world/haszeliahmad/data-analysis
Share:

Saturday, April 11, 2020

Parameter in Tableau - Using available Dimension with additional 'All' for all data

I am writing (and still writing as of this article) a manual to assist me in teaching Tableau. One of the sections is Parameter. There are many examples and guidance provided by Tableau.

You may read/view the following articles/videos for the guide on parameter.
  1. https://interworks.com/blog/interworks/2012/03/26/how-to-create-and-use-parameters-in-tableau
  2. https://help.tableau.com/current/pro/desktop/en-us/parameters_create.htm
  3. https://help.tableau.com/current/pro/desktop/en-us/changing-views-using-parameters.htm
  4. https://www.youtube.com/watch?v=CrfEJ24FWpQ
  5. https://www.youtube.com/watch?v=rJsaezoTVAE
  6. https://www.youtube.com/watch?v=opfVV1maNVw

The only problem I faced was to have an 'All' data if the user did not select any or wishes to see all data. None of them help. I tried using Action and Filters, yet it only shows based on selection and all show nothing.

That is until I found this solution.

IFNULL([FilterField],’Null’) = IF [Paramter] != ‘All’ THEN [Parameter] ELSE IFNULL([FilterField],’Null’) END
In a more readable, it will be like this

IFNULL([FilterField],’Null’) = (
     IF [Parameter] != ‘All’ THEN 
          [Parameter] 
     ELSE 
          IFNULL([FilterField],’Null’) 
     END
)

Step to:
  1. Create your parameter - In this case, you use any Dimension as the Parameter by choosing a List and choose the list by changing the Fixed section and click on Add Values From.
  2. Don't forget to add 'All' as one additional list
  3. Drag the Dimension that you used as the parameter from the Dimensions Card into Filters Card.
  4. In the Filter option, choose Condition and choose by Formula, and insert the above solution into the formula. 
  5. Don't forget to change the [FilterField] to the Dimension used for the filter and the [Parameter] to your created parameter. 
  6. Do ensure that 'All' is the same as your definition in the parameter (the character case and spelling is equal)
  7. And that shall do it. You are ready to go.


There are also an alternative solution to this and posted here: http://www.vizwiz.com/2012/09/tableau-tip-adding-all-filter-option-to.html
Share:

Thursday, April 2, 2020

Data Analysis - Use it !!

I was reading many developer's site and chat (telegram and whatsapp) when the government stated that they are looking for an app similar to Singapore apps to track the close contact of the Covid-19 positive patient.

In Singapore, they are using a technology which I presume is Bluetooth to ping close contact within the radiant of the tech and capture necessary data which then used to determine the contact and request them to perform screening. Here are some of the news:

  1. https://www.thestar.com.my/tech/tech-news/2020/03/20/covid-19-singapore-launches-contact-tracing-mobile-app-to-track-coronavirus-infections
  2. https://www.pymnts.com/coronavirus/2020/app-lets-singapore-track-virus-patients-movements/
  3. https://www.nst.com.my/news/nation/2020/03/578445/smartphone-app-track-contacts-covid-19-patients
  4. https://asia.nikkei.com/Spotlight/Coronavirus/Singapore-urges-citizens-to-sign-up-for-COVID-19-tracking-app


And the apps is available on Google Play and Apple Store

  1. https://play.google.com/store/apps/details?id=sg.gov.tech.bluetrace&hl=en
  2. https://apps.apple.com/sg/app/tracetogether/id1498276074

And as this article is written, there are many groups including international are coming with various hackathons for apps that can be used to track all COVID-19 patients and their close contact.

In Malaysia, since the announcement, many had gather groups to develop apps.

From my perspective, why must we reinvent the wheel? Why we need to develop many apps when we already have few that are potentially be used for it. 

For instance, D'scover by Favioriot was developed for a user to explore whatever the user likes but also close contact that uses the apps. I believed they can just tweak the apps to get close contact for COVID-19 and it is much faster than building and testing new apps. (by the way, this is not promoting them and I don't gain anything from it :))

Not just that apps, people have been using Google Maps, Waze, Grab, etc. All these apps collected millions of data and one of these data is people's location and whereabouts. On top of that, all telcos do have their customer's data location and track their movement. I attended the Big Data conference by Bigit a few years ago where one of the telcos presented their data analysis. They have shown the heatmap of their user and based on the communication tower.

I even had a discussion with a few telcos when they approach us (my previous company) to provide their services and wish for data sharing. I do request to have a set of data of their customer whereabouts too to ensure we can provide efficient services at the moment the customer approaches our station or hub, or at the time they are supposed to do so.

These data can be utilized to find close contact with COVID-19 patients. From these data, we know where they go, their ride and whom the came across with or pass by. Of course, these data are secured by all those companies for customer's safety and PDPA compliance. But, for the sake of government and to combat COVID-19, they can request minimal information limited to the phone number to call the respective COVID-19 contact. 

You just need a group of data scientists and data engineers to focus on the massaging and provide the relevant info to the government fast and secure. That's all :)

Don't REINVENT the wheel. Used It and MAXIMIZE the POTENTIAL.

* My personal opinion based on experience. Agreed to disagree :)


Share:

Ontology Model for C Overflow Vulnerabilities Attack

Prepared the slide and was hoping to present at a conference. Unfortunately, due to Covid-19, it can only be shared online here.

I would like to thank all in the slide for making it through especially Saiful who give it all to complete the paper and published it at IJATCSE.

You may access and view the slide at Slideshare


#covid19 #overflow #softwaresecurity #overflowvulnerabilities #programanalysis #staticanalysis #informationsecurity #security #cybersecurity
Share:

Tuesday, February 25, 2020

List of User-Agent for browser compatibility

There are occasions when you would access some website, it does not support your browser. Either Chrome, Edge, Firefox, etc. This mostly applied to old systems or system that is using old technology, framework or library.
What you can do? You already upgrade your browser and you have installed many browsers and it still does not work properly.
The only solution is to change your user agent setting of the browser.
For instance 
  1. in Safari: On the menu bar, go to Develop -> User Agent and select from the list. If there are none, choose Other and enter the user agent setting.
  2. in chrome: refer https://winaero.com/blog/change-user-agent-chrome/
  3. in firefox: refer https://winaero.com/blog/change-user-agent-firefox/
Here are the list of user-agent code you can use
From https://www.whatismybrowser.com/guides/the-latest-user-agent/internet-explorer
Share:

Running Pentaho Data Integration in Mac OS Catalina version 10.15 and above


If you haven’t download the application, you may access here https://community.hitachivantara.com/s/article/downloads

Running Pentaho Data Integration @ Spoon in Windows or Linux should be straight-forward. Either click on spoon.bat or spoon.sh or the Data Integration app icon.
Running Data Integration from the install folder
However, for Mac OS, especially with the latest version Catalina which only allowed certified and trusted 64-bit application to run, running Data Integration will be troublesome despite the security for the app was disabled and allowed for the application to run. 





Some of the guidance on enable security and allow the untrusted app to run are as follow:
  1. https://edpflager.com/?p=3571
  2. https://andres.jaimes.net/1388/running-pentaho-spoon-on-mac-osx/
I have tried both and after enabling the apps, click on the Data Integration icon still does not work and the application still did not run. 

Lastly, I had to try to run it through the terminal. For OSX Catalina and above, instead of normal bash, Apple brings in zsh and the behavior is totally different. Plus, if you are a developer and install many Java JDK, running the Pentaho Data Integration will not be as running the normal command. Here is the step to run on the terminal and it works for all OSX.

1. Open up your terminal


2. Navigate to your install path (where you install or unzip the data integration file)


3. Run ./spoon.sh (for bash or old scripting, running spoon.sh shall work without ‘./’)

4. If you run into an error such as JDK or java runtime error like below, do not panic. This maybe your current java JDK is set to be higher than supported by the application.

(base) MyMek @ MyEpal data-integration % ./spoon.sh
OpenJDK 64-Bit Server VM warning: Ignoring option MaxPermSize; support was removed in 8.0
-Djava.endorsed.dirs=/Users/masteramuk/Documents/Apps/data-integration/system/karaf/lib/endorsed is not supported. Endorsed standards and standalone APIs
in modular form will be supported via the concept of upgradeable modules.
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

5. First, check your JDK version. Open a new terminal as the command need to be executed from the base (unless you set the JDK in your profile which may cause problem to run multiple JDK later). Run command java -version. You shall have similar to below. In my laptop, the current JDK version is set to JDK version 10.

(base) MyMek @ MyEpal data-integration % java -version
openjdk version "10.0.2" 2018-07-17
OpenJDK Runtime Environment AdoptOpenJDK (build 10.0.2+13)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 10.0.2+13, mixed mode)

6. Make sure you have multiple java JDK installed if you need to use the existing JDK version for your ‘other’ development. Refer https://www.devdungeon.com/content/install-multiple-jdk-windows-java-development to install multiple JDK. Refer here https://www.jenv.be/ to install jenv command tool.

7. For my laptop, I have a few versions of JDK and using jenv, I can set the selected JDK for global or local (only applied to the folder where we run jenv local command). Run jenv version to check on current JDK and jenv versions to list all JDK install. 

(base) MyMek @ MyEpal data-integration % jenv versions
  system
  1.8
  1.8.0.232
* 10.0 (set by /Users/masteramuk/Documents/Apps/data-integration/.java-version)
  10.0.2
  13.0
  13.0.1
  9
  openjdk64-1.8.0.232
  openjdk64-10.0.2
  openjdk64-13.0.1
  openjdk64-9

As of this manual written, Pentaho Data Integration @ Spoon supports up to JDK 1.8.

8. Use jenv to change the jdk to 1.9. Run command jenv local [JDK number]. In this example, I execute jenv local 1.8.0.232.
9. Finally, run again ./spoon.sh. The application shall run.

Running


Opening the application

The main screen

Share:

Monday, January 13, 2020

Disruptive UI/UX - The new interactive design of a website

The faces of a website have evolved drastically from normal static one page to multiple page interactive and so on. With Big Data and ML, comes chatbot and more interactive website which more customer engaging concept.

It no time, we will definitely view a website through the Augmented Reality concept. Just read the name on a billboard, and then you will get to see the whole company profile in AR mode. Well, while waiting for this to happen, let us take a look at few revolutionize user engaging designs of a website.

As shared by Bruno Simon at https://bruno-simon.com/


Whom also the master of behind many 'abnormal' website like Orano


and Prior Holding



Go ahead browse the website and you will feel different.




Share:

Codility - PermCheck (Check whether array A is a permutation)


This is the second lesson in Codility. Given an array of integer N, you need to find if the given array is a permutation array or perfect array in sequence (if all numbers are sorted accordingly). The full explanation of the lesson is here.

It does not take me long compared to the previous lesson. I scored 100% on the first trial and here is the explanation of my code.

Since it already stated that the array starts from a positive number, I just set the expected int is 1 and missing to 0
int expectedInt = 1;
int missingInt = 0;
Then, the array is sorted accordingly. I’m using java.util.Arrays library
 Arrays.sort(A);
To find the missing int, just loop the sorted array and find the first occurrence of the missing int.
for (int x : A){ //loop to find the missing int
     if (x == expectedInt){
          expectedInt++;
     } else {
         missingInt = expectedInt;
     }
 }

This code is not perfected yet as it will continue to search despite it found the missing int. I should further improve it later. However, for codility purposes, it stops here. You can further enhance the code by implementing the break clause once found the first missing int.
The code
And here is the result. Ya, it shows 2 minutes; that is because I test it again to snapshot the result :). In actual, for a few trials, it took me around 2 hours to perfect it and scored 100%
Result

You can download the full code at
  1. Bitbucket — git clone https://masteramuk@bitbucket.org/fullstacksdev/codility-permcheck.git
  2. Github — git clone https://github.com/masteramuk/codility-lessoncode.git





Share:

Codility - FrogRiverOne (Find the earliest time when a frog can jump to the other side of a river)

This is the fourth lesson in Codility. You need to find the fastest (earliest) time possible for a frog to start jumping towards the other side of the river. You will be given an array that reflecting the position of jumping/landing point for the frog. 

The frog will start to jump when all landing point is in the right position. Two input is given; X as the final jumping position and Y array of integer. For each element in the array, every index is considered as seconds. You need to arrange the number in the array and trigger when all are in sequence with X as the last element.


It took me another 1 full day and many try-n-error to get it perfect 100%

In the beginning, I’m using 2 Array of Integer as shown below. There are few test cases that failed because the time taken to process is more than the limit given.
100% accuracy but the overall score is 18%
With an improvement in the code, I managed to improve the overall score to 54%. I managed to reduce some of the performance issues.
100% accuracy but overall score is 54%
It looks like Array.copyOf and Arrays.stream do take a longer time to process.

Another improvement has lessened the length of the code and improve the overall score to 63%
63% overall score
The code above simply set the C array to value one of the position indexes of A. Here are the list of test that it fails
▶medium_range
 arithmetic sequences, X = 5,000✘TIMEOUT ERROR
 running time: 0.112 sec., time limit: 0.100 sec.
 1.0.112 sTIMEOUT ERROR, running time: 0.112 sec., time limit: 0.100 sec.
 ▶large_random
 10 and 100 random permutation, X = ~10,000✘TIMEOUT ERROR
 running time: 1.128 sec., time limit: 0.880 sec.
 1.1.128 sTIMEOUT ERROR, running time: 1.128 sec., time limit: 0.880 sec.
 2.0.200 sOK
 ▶large_permutation
 permutation tests✘TIMEOUT ERROR
 running time: 1.716 sec., time limit: 0.880 sec.
 1.1.716 sTIMEOUT ERROR, running time: 1.716 sec., time limit: 0.880 sec.
 2.6.000 sTIMEOUT ERROR, Killed. Hard limit reached: 6.000 sec.
 ▶large_range
 arithmetic sequences, X = 30,000✘TIMEOUT ERROR
 Killed. Hard limit reached: 6.000 sec.
 1.6.000 sTIMEOUT ERROR, Killed. Hard limit reached: 6.000 sec.
I changed my strategy. Instead of using a normal Array of integer, I implement List & ArrayList.

Bad improvement - 54% overall
Instead of getting better, it is getting worse. I google on it and found that List do have performance issues and found few suggestions on it. Either use Hashmap, HashSet, TreeSet or GapList. 


I do improve the process on my laptop and surprisingly, it was way faster than List or ArrayList. Unfortunately, Codility does not support the library. Hence, I need to look for another alternative.

Based on the performance comparison between Hashmap, HashSet, and TreeSet, HashSet seems promising. And so it did. My final code is using HashSet and finally, the result shown is 100%. Here is part of the code:
1. Definition
HashSet list= new HashSet();

2. Used
           for(int idx = 0; idx < A.length; idx++){
         if ( !list.contains(A[idx]) ){
            list.add(A[idx]);
         }
         if ( list.size() == X ){
            return idx;
         }
      }

I also found a few solutions which score 100%
    This solution was shared by someone and it claims score 100/100
    public int solution(int X, int[] A) {
        int[] B = A.Distinct().ToArray();
        return (B.Length != X) ? -1 : Array.IndexOf(A, B[B.Length - 1]);
    }
    
    This solution was shared too and score 100/100 for correctness, task, and performance
    public int solution(int X, int[] A) {
        HashSet unique= new HashSet();
        for (int i = 1; i<= X; i++){
            unique.add(i);
        }
        for(int j = 0; j< A.length; j++){
            if(unique.contains(A[j])){
                unique.remove(A[j]);
                   if(unique.isEmpty()){
                         return j;
                    }
            }
        }
        return -1;
    }


Full source code is accessible at
  1. Bitbucket — git clone https://masteramuk@bitbucket.org/fullstacksdev/codility-frogriverone.git
  2. Github — git clone https://github.com/masteramuk/codility-lessoncode.git


Share:

About Me

Somewhere, Selangor, Malaysia
An IT by profession, a beginner in photography

Blog Archive

Blogger templates