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

Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Monday, February 10, 2025

JHipster vs Vaadin vs Spring Boot - Choosing your framework

 



Java frameworks provide pre-written code and tools that simplify the development of Java applications. They handle common tasks like database interaction, web request handling, and user interface creation, allowing developers to focus on the unique logic of their applications. Frameworks promote code reusability, consistency, and best practices, ultimately speeding up development and improving application quality. They range from lightweight libraries to full-fledged platforms that dictate the structure of your application.


Which ones are suitable for you?

Okay, let’s start with a brief overview of the frameworks.

1. Spring Boot

Spring Boot is not strictly a full-stack framework in the same way as the others. It’s more accurately described as a microframework or a toolkit built on top of the larger Spring Framework. Its primary goal is to drastically simplify the setup and configuration of Spring applications. Think of Spring Boot as the express lane for Spring development.

Key Features:

  • Auto-configuration: Spring Boot automatically configures many beans (objects managed by Spring) based on dependencies in your project. This reduces the amount of manual configuration you have to do.
  • Embedded Servers: Easily embed Tomcat, Jetty, or Undertow directly into your application, making deployment simpler.
  • Spring Boot CLI: A command-line interface that further simplifies development tasks.
  • Spring Initializr: A web-based tool for quickly bootstrapping new Spring Boot projects.
  • Use Cases: Spring Boot is ideal for building REST APIs, microservices, and any backend component where you need the power and flexibility of the Spring ecosystem.

2. JHipster

JHipster takes Spring Boot and combines it with powerful code generation capabilities. It’s a full-stack application generator that helps you create modern web applications with Spring Boot on the backend and popular JavaScript frameworks (Angular, React, or Vue.js) on the front end.

Key Features:

  • Full-stack code generation: Generates both backend and frontend code, including authentication, database integration, and basic CRUD (Create, Read, Update, Delete) operations.
  • Microservices support: Can generate applications designed for a microservices architecture.
  • Blueprint architecture: Allows for customization and extension of the generated code.
  • Use Cases: JHipster is perfect for rapidly prototyping full-stack applications, especially when you want to use Spring Boot and a modern JavaScript framework. It’s less ideal for very small, simple projects where the overhead of JHipster might be too much.

3. Vaadin

Vaadin is a full-stack Java web framework focused on building rich and interactive web UIs. It offers two main approaches:

  • Vaadin Flow: Allows you to build UIs entirely in Java, without writing HTML or JavaScript directly. Vaadin handles the rendering on the client-side.
  • Hilla: A newer approach that combines a Spring Boot backend with a reactive TypeScript frontend.

Key Features:

  • Component-based architecture: UI elements are represented as reusable Java components.
  • Server-side rendering (Vaadin Flow): UI logic is executed on the server, which can simplify development for Java developers. Hilla uses client-side rendering.
  • Rich set of UI components: Vaadin provides a wide range of pre-built UI components, from simple buttons to complex grids and charts.
  • Use Cases: Vaadin is well-suited for building complex, data-driven web applications where a rich user interface is essential. It’s a good choice for Java developers who prefer a Java-centric approach to UI development.

Core Focus, Strength and Weaknesses

1. Spring Boot

  • Core Focus: This is the foundation. Spring Boot simplifies building standalone, production-ready Spring applications. It handles a lot of the boilerplate configuration, making it easier to get a Spring project up and running quickly. Think of it as the engine of your application.

Strengths:

  • Speed: Rapid development with auto-configuration and embedded servers.
  • Flexibility: Works well with various databases, cloud platforms, and other technologies.
  • Mature and Widely Used: Huge community support, extensive documentation, and a vast ecosystem of libraries.

Weaknesses:

  • Not a Full-Stack Solution: You’ll need to choose and integrate your own frontend technologies (like React, Angular, or Vue.js).
  • Learning Curve: While Spring Boot simplifies things, understanding the underlying Spring framework can still take time.

2. JHipster

  • Core Focus: A code generator that helps you quickly create full-stack web applications with Spring Boot on the backend and popular JavaScript frameworks (Angular, React, Vue.js) on the frontend.

Strengths:

  • Rapid Prototyping: Generates a complete application with authentication, database integration, and basic CRUD operations in minutes.
  • Best Practices: Uses well-established technologies and patterns.
  • Microservices Support: Can generate applications designed for a microservices architecture.

Weaknesses:

  • Complexity: Can generate a lot of code, which might be overwhelming for smaller projects or developers new to the technologies.
  • Less Control: You have less control over the initial setup compared to building everything from scratch.
  • Maintenance: Upgrading generated applications can be challenging.

3. Vaadin

  • Core Focus: A full-stack Java web framework that lets you build rich, interactive web UIs with Java. It offers two main approaches:
  • Vaadin Flow: Build UIs entirely in Java, without writing HTML or JavaScript.
  • Hilla: Combines a Spring Boot backend with a reactive TypeScript frontend.

Strengths:

  • Productivity: Vaadin Flow’s Java-centric approach can be very efficient for Java developers.
  • Type Safety: Strong type safety throughout the development process.
  • Excellent UI Components: Provides a wide range of pre-built UI components.

Weaknesses:

  • Steeper Learning Curve: Vaadin has its own way of doing things, so there’s a learning curve.
  • Less Flexibility: Compared to Spring Boot, Vaadin is more opinionated about how you structure your application.
  • Performance: Vaadin Flow’s server-side rendering can sometimes lead to performance issues in complex applications.

Share:

Saturday, December 14, 2024

Troubleshooting JEnv problem

It has been a while since I managed my development environment and as I wish to get my hands dirty again, I started to cleanup my java environment, and it turn out a mess or simply saying a mistake I did.

If your Jenv suddenly fail to work and your java environment did not change as you intended, follow the link below

1. https://github.com/jenv/jenv


Do follow steps shown and don't skip.

2. https://www.jenv.be/


Finally, I manage to get the right Java version that I need for the development.

openjdk version "23.0.1" 2024-10-15

OpenJDK Runtime Environment Homebrew (build 23.0.1)

OpenJDK 64-Bit Server VM Homebrew (build 23.0.1, mixed mode, sharing)



Share:

Monday, January 13, 2020

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:

Sunday, January 12, 2020

Codility - TapeEquilibirium (Finding the lowest difference in an array)


Given an array of int (ranging from -ve to +ve value) with the minimum number of an element is 2 and the maximum element is 100,000, you need to find the lowest difference between two sets of value (of the total sum of the array).

The actual description can be seen at Codility website (https://app.codility.com/programmers/lessons/3-time_complexity/tape_equilibrium/)

It took me 1 full day to resolve it despite the time given was only 120 minutes. On the first trial, I got 88% correct. It resolves all but two out of all test was considered as a failure due to time taken was more than expected. Next few trials, I score between 66% and 84%. The only issue was the double element array and small element array.
After a while, I figure out. The line below
int totalSum = Arrays.stream(A).sum();
is causing the time taken more than expected. Although it passed, it was 0.020 seconds more than the limit.

After a few modifications, wallawei, finally, I achieved 100%.

Snapshot of the code

Result

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




Share:

Saturday, January 11, 2020

Codility - PermMissingElem (Find the missing element in a given permutation)

This is a lesson in codility for the Time Complexity algorithm. Given an array of integer, you need to find the lowest missing integer.

I managed to score 100% for it.

Here is the snapshot of the code:
Based on the length, for all value in Array A, start the search and compare the initial value; that is 1 (expectedInt). If the value exists, the expectedInt is added 1 value.
                 if( A.length > 0 ){
           for (int x : A){
             //if found a value based on expected value 
             if (x == expectedInt){ 
                expectedInt++;
             } else { //if found a mising value 
                missingInt = expectedInt;
             }
           }
         }
If the Array is empty, we will just set the missingInt to 1.
        if (A.length == 0) {
          missingInt = 1;
     }
If no missing int found, then we just add additional 1 to the last value found
       if (missingInt == 0){
           missingInt = A[A.length — 1] + 1;
       }

The complete code is shown below
Codility - PermMissingElem sample code
My result is shown below
Result


You can download the code from here:

  1. Bitbucket - git clone https://masteramuk@bitbucket.org/fullstacksdev/codility-permmissingelem.git
  2. Github - git clone https://github.com/masteramuk/codility-lessoncode.git



Share:

Codility - FrogJmp (Count minimal number of jumps from position X to Y)

Codility - FrogJmp

Count the minimal number of jumps from position X to Y

FrogJmp is the third lesson number 1 out of three in the list for Time Complexity algorithm. Basically, it is an algorithm to count the number of the jump from one X location to Y location when the number of the step taken is given as Z for each single jump

public int solution(int X, int Y, int D){
        int a = 0;
        Y = Y - X; //setting the initial value test

        if (Y >= 1){ //evaluating the Y value
            a = Y/D; //setting the initial return value
            if (Y % D > 0){ //evaluating the possible number of jump to add additional value
                a++;
            }
        }
        if ( a == 0 && (Y%D==0) && Y > X ){ //final check
            a = 1;
        }
        return a;
    };

Result of the code

Code is downloadable from
Github - https://github.com/masteramuk/codility-lessoncode.git
Share:

Thursday, January 9, 2020

Codility - OddOccurrencesInArray (Find value that occurs in odd number of elements)

Given an array, find a value that has no duplication or unpaired value. I scored 100%

public int solution (int[] A){
        int a = 0;
        //sort the array
        Arrays.sort(A);
       
        int[] sortA = A;
        int x = 0;
        int cnt = 1;
        int[] oddA = new int[]{};
        //int idxOdd = 0;
       
        while ( x < sortA.length ){
            if ( x != 0 ){
                if (a == sortA[x]){
                    cnt++;
                } else {
                    if (cnt % 2 > 0){
                        oddA = Arrays.copyOf(oddA, oddA.length + 1 ); //sortA[ x - 1];
                        oddA[oddA.length - 1] = sortA [x - 1];
                    }
                    a = sortA[x];
                    cnt = 1;
                }
            } else {
                a = sortA[x];
            }
            x++;
        }
        if ( x == sortA.length && cnt == 1) {
            oddA = Arrays.copyOf(oddA, oddA.length + 1 ); //sortA[ x - 1];
            oddA[oddA.length - 1] = sortA[x - 1];
        }
        System.err.println("sortA: " + Arrays.toString(sortA) + System.lineSeparator() + "Result: " + Arrays.toString(oddA));
        return oddA[0];
    };

The code is downloadable from
Share:

Codility - CyclicRotation (Rotate an array to the right by a given number of steps)

This is the second lesson in Codility; that is to rearrange an array to the right based on the number of steps given. It will be two input and I scored 100% for it.

public int[] solution (int[] A, int K){
        int a = 0;
        int[] sortA = A;
        int x = 0;
     
        while (x < K && x < A.length){
            a = sortA[sortA.length - 1];
         
            Arrays.copyOfRange(sortA, 0, sortA.length);
            sortA = Arrays.copyOf(sortA, sortA.length);
            System.arraycopy(sortA, 0, sortA, 1, sortA.length - 1);
            sortA[0] = a;
         
            System.err.println( x + " : " + Arrays.toString(sortA) + " - " + a);
         
            x++;
        }
        return sortA;
    };


  100% CyclicRotation

You can get the code at
Bitbucket - git clone https://masteramuk@bitbucket.org/fullstacksdev/codility-cyclicrotation.git
Github - git clone https://github.com/masteramuk/codility-lessoncode.git

Share:

Codility - Find longest sequence of zeros in binary representation of an integer.

I'm taking the coding test at Codility for a job offered by a Japanese company (of which I did not get it). For practice, I tried all and this are the code (in Java) for binary gap

public int solution (int N){
//Convert the value to binary and split the value between number 1
        String s2[] = Integer.toBinaryString(N).substring(0, Integer.toBinaryString(N).lastIndexOf('1') ).split("1");
        int x = 0;
        int a = 0;
        
//find and count the longest zeros
        while(x < s2.length){
            a = a > s2[x].length() ? a : s2[x].length();
            x++;
        }
        
        System.out.println("Number: " + N + System.lineSeparator() + "Binary: " + Integer.toBinaryString(N) 
                + System.lineSeparator() + "Zero: " + a);
        return a;
    };

It score 100% for codility test.

You can download the code here
Bitbucket - git clone https://masteramuk@bitbucket.org/fullstacksdev/codility-binarygap.git
Github - git clone https://github.com/masteramuk/codility-lessoncode.git
Share:

Friday, May 26, 2017

Kotlin + Netbeans IDE 8.2 - Don't use yet

I try the new language Kotlin with Netbeans 8.2.
http://plugins.netbeans.org/plugin/68590/kotlin

After download and install the plugin, it cause error on all projects currently on my list of projects and causing my netbeans to behave abnormally.

The error does not stop there. When I uninstall it, which you can't as it only appear in User Plugin and when you uninstall the plugin (just for the sake to remove kotlin), it causes many other problem.

So guys, use with extra careful ya.
Share:

Tuesday, February 28, 2017

Directory Listener (java code) - finally on github

Hi guys.. it has been a while since I last wrote anything here.

Just wanna share with you my latest contribution to community. I've uploaded a simple directory listener code written in java. What it does?
1. Listen to any directory pass as parameter
2. Basically alert you through message prompt on any activity done.

It can be further extended for any process you wish.

Feel free to use the code. It can be downloaded at
https://github.com/masteramuk/Java-Directory-Watcher

Adios..

Share:

Monday, January 5, 2015

JAVA - Connecting to SQL Server database using Windows Authentication or Active Directory

When you are trying to establish connection to SQL Server database using windows authentication or Active Directory (which users were not created in database by DBA via normal/traditional ways), you might get one of these errors:
  • Cannot establish a connection to jdbc:sqlserver://localhost:1433;databaseName=[databaseName] using com.microsoft.sqlserver.jdbc.SQLServerDriver (Login failed for user '[Windows User]'. ClientConnectionId:ae9be66b-830a-45a9-9317-5806e13167ba)
  • Cannot establish a connection to jdbc:sqlserver://localhost:1433;databaseName=[databaseName];integratedSecurity=true using com.microsoft.sqlserver.jdbc.SQLServerDriver (Java Runtime Environment (JRE) version 1.7 is not supported by this driver. Use the sqljdbc4.jar class library, which provides support for JDBC 4.0.)
  • Cannot establish a connection to jdbc:sqlserver://localhost:1433;databaseName=[databaseName] using com.microsoft.sqlserver.jdbc.SQLServerDriver (This driver is not configured for integrated authentication. ClientConnectionId:b595d819-4588-4003-b9bb-34da21984a1b)
  • Cannot establish a connection to jdbc:sqlserver://localhost:1433;databaseName=[databaseName] using com.microsoft.sqlserver.jdbc.SQLServerDriver (Java Runtime Environment (JRE) version 1.7 is not supported by this driver. Use the sqljdbc4.jar class library, which provides support for JDBC 4.0.)
So, how to resolved? There are many solutions/discussion which will drag you to endless issues/discussion.. but there are good site sharing possible solutions too. Here is the steps you need to do/check to avoid lengthy discussion and searching :)

Steps:

  1. Download SQLJDBC driver from Microsoft.
  2. Install the driver to any locations that you wish to used. Please use the easiest and simplified location/path (if you had it done, just skip this)
  3. Declare your environment variable (click to enlarge)
  4. You need to declare two variable which pointed to installed path of your JDBC. Eg:
    1. Variable Name: SQLJDBC_HOME
      Variable value: D:\lib\JDBC4.1\enu (where your sqljdbc4.jar exist)
    2. Variable Name: SQLJDBC_AUTH_HOME
      Variable value: D\lib\JDBC4.1\enu\auth\x86 (if you are running 32bit OS) or D\lib\JDBC4.1\enu\auth\x64 (if you are running 64bit OS). This is where your sqljdbc_auth.dll located.
  5. Copy sqljdbc_auth.dll to folder where your JDK/JRE is running. You may copy to lib folder, bin folder, etc. I copied to following folder:
    • D:\[JDK_INSTALLED_PATH]\bin
    • D:\[JDK_INSTALLED_PATH]\jre\bin
    • D:\[JDK_INSTALLED_PATH]\jre\lib
    • D:\[JDK_INSTALLED_PATH]\lib
  6. Then, in your source code, you may add integratedSecurity=true as part of the parameter like below:
    • jdbc:sqlserver://[DB_URL]:[DB_PORT];databaseName=[DB_NAME];integratedSecurity=true;
  7. The next steps is to ensure that in your jdbc library folder, you only have SQLJDBC4.jar. Please remove other sqljdbc*.jar file from that folder (or copy to other folder). If you are adding the driver as part of your program, please ensure that you add only SQLJDBC4.jar as driver to use.
If you use Netbeans.. follow steps below after complete the above steps:
  1. Add new connections
  2. Add new Driver
  3. Then, click on Add button. At pop-up window, find your sqljdbc4.jar, click the file name and click Open button.
  4. You shall get screen as below. Rename the driver as you wish.
  5. Then, at the screen before, choose the newly created driver and click Next button.
  6. Fill in the necessary information: Host, Port, Database, Windows Username, Windows Password.
  7. Don't forget to add integratedSecurity at Connection Properties with value true
Test your connection and you shall have connection success/established.

Have a enjoyable coding :)

Share:

Thursday, January 10, 2013

Java 7: 0-day Actively Exploited In The Wild

Received an email from Beyond Trust about this exploit... the content is as below

January 10, 2013 
There is a 0day vulnerability (identified flaw, with no patch available) being actively exploited across the Internet in Java. This 0day has already been incorporated into Cool Exploit Kit and Blackhole, in addition to Nuclear Pack and Redkit. Proof of concept code is already publicly available and we expect to see fully functioning exploit code incorporated into even more exploit frameworks within the next few days.

What does this mean to you?
  • This vulnerability affects Java 7 versions up to and including the current version of Java, 7u10
  • Even if you're only running Java 6, users will be forced to automatically upgrade to version 7 in February of this year. This means further exposure to this vulnerability.
What you can do now to avoid being exploited
  • Disable Java entirely
  • If you don't need Java, remove it from the system entirely
  • Lower and manage desktop privileges with solutions like PowerBroker for Windows
  • Scan and detect this vulnerability with Retina Network
As always, we want our customers and users to be prepared for these types of exploits. We've posted a comprehensive writeup about this 0day and how to mitigate your risk.


Learn More About the Java 7 0day

Regards,
BeyondTrust Research Team



Looking at the link, I was bit worried since it does not pointed to BeyondTrust website. Google around and found many more discussion about this... (search on Java 7 0day exploit via google)...



Some of the sites talks about it:

  1. http://thenextweb.com/insider/2013/01/10/new-java-vulnerability-is-being-exploited-in-the-wild-disabling-java-is-currently-your-only-option/
  2. http://www.theregister.co.uk/2013/01/10/java_0day/
  3. http://www.networkworld.com/news/2013/011013-java-zero-day-vulnerability-actively-exploited-265723.html
  4. http://www.nsaneforums.com/topic/154515-critical-java-0-day-being-massively-exploited-in-the-wild/
  5. http://blog.beyondtrust.com/java-0day-exploit-oracle-urges-people-to-run-into-burning-building


However, till today (09 January 2013), I've yet to see this appear on OSVDB, OWASP, or any other vulnerabilities databases sites or advisories sites such as Microsoft, Symantec, Karspersky, IBM, and Homeland Security... I wonder why? might be because I miss that or wrongly searched, or somehow it is yet to be available on these sites.

Share:

About Me

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

Labels

Blog Archive

Blogger templates