Dec 22, 2014

CSS specificity rules

If you’re reading this, you’re probably looking for how to know which CSS rules are applied. Rule of thumb:

W3C CSS2 specs : the most specific CSS rule is chosen by UA.

How to know the specificity of a CSS ? Refer to the table below
Excerpts from MDN

The specificity is calculated on the concatenation of the count of each selectors type. It is a weight that is applied to the corresponding matching expression.

Ascending order of specificity





Universal selectors



Type selectors



Class selectors

· li.descriptor-link


Attributes selectors






ID selectors



Inline style



  • In case of specificity equality, the latest declaration found in the CSS is applied to the element.
  • Proximity of elements in the document tree has no effect on the specificity.

Nov 18, 2014

How to setup a Load Balancer via Application Request Routing (ARR) extension on IIS

This is the walk through on how to set up an Load Balancer on IIS 7.5 using Application Request Routing extension.


Steps to create Load Balancer

1. Create a dummy web application to receive incoming requests.
this web app is just a dummy web on port 80, which will acts as request router to our back-end web farm.

2. Configure the dummy web app
In the Create Web Site dialog, use port 80 and the host name as of your domain.

The website physical path can just contains a very simple web.config as following:

    <?xml version="1.0" encoding="utf-8" ?>

3. Create the actual web application that serve your request:
In my example, I used port 8080.

Important notes: this port will be the server port while creating server farm.


4.Create the server farm
Next step is to create the server farms which will handle the request load balancing. You can choose any name for your server farm.

4. Adding servers to server farm
While adding servers to the farm, take note of the httpPort – this MUST be your web application port which you chose in step 3)
Once you add the server farm, IIS will ask you to add rules. If you have existing rules, it may popup this message. Just go ahead and click Yes to create the rules. We’ll configure it later.


5. Configure the Request Routing rules
Highlight your server farm, then choose Routing Rules

Select URL Rewrite under Advance Routing


6. Configure Inbound Rule Routing Request:
- Logical Grouping
: Match All

- Conditions:

  • {HTTP_POST} : Matches The Pattern : *localhost* (or your domain name in step 2)
  • {SERVER_PORT}: Does Not Match The Pattern: *8080* (or your chosen port in step 3)

- Action Type: Route to Server Farm (choose the server farms where you added the web servers in step 4)


7. Configure your Load Balance algorithm
Similar to step 5, highlight your server farm and choose Load Balance


You will have a list of Load Balance Algorithm to choose from. Depends on your need, you can pick the corresponding algorithm



Use the list to select the algorithm to use to load balance your server. The available options are: (From MSDN):

  • Weighted round robin – Distributes traffic based on the number of incoming requests and their normalized weight. Each server can receive the same distribution of requests or a custom distribution.
  • Weighted total traffic – Distributes traffic based on the size of the requests and responses in bytes. Requests are routed so that the amount of data is load balanced. In an even distribution, the server with the least amount of data will receive the next request.
  • Least current request – Distributes traffic based on the current number of HTTP requests between ARR and each of the application servers. Requests are routed to the server with the least number of current HTTP requests.
  • Least response time – Distributes traffic based on the fastest response time from the servers, which enables the server to respond most quickly.
  • Server variable hash – Distributes traffic based on a hashed value of a server variable.
  • Query string hash – Distributes traffic based on the hashed value of the query string value. When more than one query string name is specified, the concatenated string of the corresponding query string value is used for the hash.
  • Request hash – Distributes traffic based on the hashed value of the configured server variable or URL. For example, if the server variable is QUERY_STRING, the hashed value is based on the names in the request query string.

8. Test your server farms to confirm it works
If your configurations are right, you should start to see your web applications running. You can also explore more on configure distributed disk-cache, changing server affinity (how server associate with user sessions) and so on.


The key concept is to create a dummy web application, then use ARR and Load Balance to route request to your server farms (based on the Inbound Rules).

ARR is a very good features which make IIS more useable and become more ready for production sites. Try it yourself and have fun Smile !

Oct 8, 2014

Useful services and resources for web developer & webmaster

Here is the list I came across inside a survey of MDN, which I think would be useful to know for every web developer and web master out there.
The list is definitely not complete and there will be more and more useful services. Stay tuned !
  • Docs on GitHub
  • MDN
  • MSDN
  • ReadTheDocs
  • Stack Overflow
  • w3schools
  • GitHub
  • Basecamp
  • JIRA
  • Trello
Code hosting
  • GitHub 
  • Bitbucket
Library monitoring
Continous Integration
  • Travis CI
  • Bamboo
  • Circle CI
  • CodeShip
Report test coverage
  • Code Climate
  • Coveralls
Web hosting
  • Amazon/EC2
  • BlueHost
  • DigitalOcean
  • DreamHost
  • Google/AppEngine
  • Heroku
  • HostGator
  • Linode
  • Microsoft/Azure
  • Rackspace M
Site monitoring
  • AppDynamics
  • New Relic
  • Pingdom
  • Scout
Cross-browser test
  • BrowserStack
  • SauceLabs
Accessibility scan
Traffic monitoring
  • Flurry
  • Google Analytics
  • Piwik
  • MixPanel
  • KISSMetrics
  • Adobe Analytics
Performance monitoring
  • Google Analytics
Content Optimization
  • Google Analytics (+Content Experiment)
  • Optimizely

Jul 14, 2014

How to remove XAMPP from Linux

How to remove XAMPP from Ubuntu (Linux) is simple. Follow the following steps:
1. XAMPP gets itself installed in “opt/lampp” directory by default.
2. Stop the XAMPP server by typing sudo /opt/lampp/lampp stop in the Terminal (you can open the terminal by pressing Ctrl+Alt+t).
3. Now type sudo rm -rf /opt/lampp
4. Check your opt directory. The folder “lampp” would have been removed.
5. You have successfully removed XAMPP from your Ubuntu.


Spinner and how to preload background images

If you want to use background image for your web but it took too long to load, what can you do ?
You probably want to show a preloader (or spinner) while your background image is being loaded, right ?

If so, here are the steps (demo:

1. To display the spinner / preloaded: 
<!DOCTYPE html>
 <meta charset="utf-8" />
 <div id="preloader_wrap">
  <div id="spinner_wrap">
   <div class="spinner">
    <div class="rect1"></div> 
    <div class="rect2"></div> 
    <div class="rect3"></div> 
    <div class="rect4"></div> 
    <div class="rect5"></div>
 <div id="content">Your content here</div>

#preloader_wrap {
#spinner_wrap {
 margin-100px 0 0 -100px;
.spinner {
 margin100px auto;
 .spinner > div {
  background-color#2980b9 /*dark blue*/;
  -webkit-animationstretchdelay 1.2s infinite ease-in-out;
  animationstretchdelay 1.2s infinite ease-in-out;
 .spinner .rect2 {
 .spinner .rect3 {
 .spinner .rect4 {
 .spinner .rect5 {
@-webkit-keyframes stretchdelay {
 0%40%100% {
 20% {
@keyframes stretchdelay {
 0%40%100% {
 20% {
 2. To hide the spinner when your image is loaded:
<script src="//"></script>
 <script type="text/javascript">
  var jpgFile = ''//or your own picture
  $("<img/>").attr('src', jpgFile).load(function() {
   $("body").css("background""url('" + jpgFile + "') no-repeat center center fixed"); 

That's it ! You'll have a nice preloader and a nice background

Building my own VPS (part 2 )

Part 1 

  1. Moving to Linode and be aware of unknown VPS providers.

So back to 2013 (about 8 months ago), I decided to go with ReverseHosts but I faced many problems: their servers are slow, downtime was quite often (4-5 times around this year, each time it took several hours), and this thing happened yesterday: their San Diego servers shut down due to business reason ( WTH???), and the only thing I received was an email inform that I will NOT have automatic backup, and I have to request migration to their Las Vegas server.

So I decided to go ahead with - a well-known VPS provider. I chose Linode 1024 since my demand is minimum.

Well, I was blown away by the speed differences:
root@(none):/etc# wget -O - -o /dev/nul|bash
CPU model : Intel(R) Xeon(R) CPU E5-2680 v2 @ 2.80GHz
Number of cores : 1
CPU frequency : 2800.078 MHz
Total amount of ram : 989 MB
Total amount of swap : 255 MB
System uptime : 2:03,
Download speed from CacheFly: 64.8MB/s
Download speed from Coloat, Atlanta GA: 1.07MB/s
Download speed from Softlayer, Dallas, TX: 34.8MB/s
Download speed from Linode, Tokyo, JP: 12.8MB/s
Download speed from, Rotterdam, NL: 3.89MB/s
Download speed from Leaseweb, Haarlem, NL: 9.63MB/s
Download speed from Softlayer, Singapore: 10.2MB/s
Download speed from Softlayer, Seattle, WA: 50.2MB/s
Download speed from Softlayer, San Jose, CA: 59.1MB/s
Download speed from Softlayer, Washington, DC: 24.0MB/s
I/O speed : 770 MB/s
root@(none):/etc# dd if=/dev/zero of=test bs=64k count=16k conv=fdatasync && rm -f test16384+0 records in16384+0 records out1073741824 bytes (1.1 GB) copied, 1.37065 s, 783 MB/s

I/O is superb (as expected on SSD). Cache & network bandwidth are nice, however I notice there are 2 locations with bottleneck : Atlanta GA & Rotterdam, NL.

After 2 hours with Linode, here are some of my comments:

  • Their Linux setup is on-the-fly, you have plenty of options to setup (Debian, Ubuntu, CentOS...etc) You name it they give it. 
  • Awesome I/O : 783 MB/s on average ! I copied and movied GBs of data within the VPS and it take seconds.
  • Network speed: In general much better than ReserveHosts (except for Altanta node?).
    Download speed from Singapore: 10.2MB/s (Softlayer node)
    Upload speed from Singapore: 600KB/s (maybe because of my Starhub ISP? Gotta try again tomorrow with better bandwidth). 
  • More expensive than cheap VPS (well, I guess the stability and speed worth it). 

2. Setting up my LAMP stack:

So now I am on a new Linux box - I'll need a new LAMP setup. My favorite and easiest installation would be XAMPP ( 

root@(none): mkdir /home/download/devroot@(none): cd /home/download/devroot@(none): wget 
root@(none): ./

That's it ! Next step is heading to my account page, and update DNS record, pointing the domain to new IP address.

Good, now I'm back online !!!

May 29, 2014

Use Recycle Bin for network drive (Windows Vista/ 7 / 8)

If you’re working on a network drive and you accidentally delete some files – you’ll realize that this file is not going to the Recycle Bin. NO EASY WAY to recover it!


Yeah it happened, and to prevent this disaster from happening to you, please read this guide (courtesy of Russel Riley):

Method 1:
1. Map a network drive to the network share you want to use. Make sure that the drive is re-connected on logon. If you don't know how to do this, search Google.
2. Browse to C:\users\<user name>.
3. Right-click on one of the folders in this location (I chose saved games) and click properties.
4. Select the Location tab.
5. Click Move, browse to to root of the drive you mapped in step 1, and click Select Folder.
6. Click Ok and click yes in the dialogue box that appears.
7. Repeat these same steps for all users on the computer.

Method 2 : the guide is here: . In summary:

Create a *.reg file with this content:

Windows Registry Editor Version 5.00



A few things of note:

  • The GUID in the above .reg file {9147E464-33A6-48E2-A3C9-361EFD417DEF} came from this PowerShell command: "{"+[guid]::NewGUID().ToString().ToUpper()+"}"
  • Each "known folder"/Recycle Bin combination requires a unique GUID. If you don't want to use PowerShell to generate a GUID, you can use an online GUID generator.
  • I don't know what the "Category" value does, but the key I copied had it set to 4, and that works, so I didn't test any other values.
  • The "Name" value is required, but is not the name that will be shown if you right-click on the Recycle Bin and select properties. (At least not in my environment.) In my environment, the name that is shown is the name of the network drive.
  • Making this change adds a "Location" tab to the properties page of your mapped network drives. I suspect this could be removed by changing the "Category" value, but didn't bother to find out.
  • I only tested with mapped network drives. I suspect this would work with UNC paths as well, but I didn't bother testing.


May 14, 2014

HttpUtility.UrlEncode vs. Uri.EscapeDataString vs. UrlPathEncode

How to proper encode and decode values that were passed from Client to Server and vice versa. Client side is using Javascript methods : encodeURI( ) and encodeURIComponent ( ) ?

This seem to be a very fundamental and popular issues – the real complication is when you’re using MVC routing to pass route-data values between controllers. In our solution, we’re using a proprietary method to perform aliasing-dealiasing, which add up more complexity to perform proper value encode/decode.

I’ll update this blog with the solution I found later.

May 10, 2014

Set your password wisely, to remember them easily, for managing multiple accounts securely?

Most popular (and wrong) passwords

An average Internet citizen will have Facebook, Twitter, probably Pinterest or LinkedIn account – and then your Gmail, Yahoo mail, your Internet banking ID, your favourite forum account and the list goes on.

It turns out that most of us choose a common password for every site – what is the implication ? Well, if somebody gains leverage on one of your account.

It’s true that human brain can only process and memorize certain amount of data – that’s why people tend to choose easy password to remember. And it’s wrong, totally WRONG !

Here are the worst and unfortunately most popular 25 passwords in 2012:

#              Password                Change from 2011
1               password                 Unchanged
2               123456                    Unchanged
3               12345678                Unchanged
4               abc123                     Up 1
5               qwerty                     Down 1
6               monkey                    Unchanged
7               letmein                     Up 1
8               dragon                     Up 2
9               111111                    Up 3
10             baseball                   Up 1
11             iloveyou                   Up 2
12             trustno1                   Down 3
13             1234567                  Down 6
14             sunshine                  Up 1
15             master                      Down 1
16             123123                    Up 4
17             welcome                  New
18             shadow                    Up 1
19             ashley                      Down 3
20             football                     Up 5
21             jesus                        New
22             michael                     Up 2
23             ninja                         New
24             mustang                   New
25             password1               New

Is your password in the list ? Smile If so, read on for my suggestions.

So, how to set password wisely ?

This suggestion below is totally based on my personal experience and I shall not bear any responsibility – OK I am done with disclaimer and if you’re still here, let’s move on:

1.  Separate your important accounts from unimportant ones.
For me, I’ll set a separate password for my junk account (forums, secondary Facebook account, Yahoo mail - sorry Yahoo, your spamming filter doesn’t work !).

For important account such as credit card, Paypal, Amazon or banking-related, I’ll pick a different and much longer password.

That way, at least the chance of getting my credit card hacked reduced by 50%.

2. Set your password long & complex enough for hackers
Every password can be crack given enough time with brute-force.  According to the calculation at this page, at brute-force speed of 1B guesses/ second (cluster servers, super computing node, or a botnet networks) :

  • It’ll be matter of minutes or hours to crack if your password is just pick from alphanumeric values.
  • But it’ll take 83.5 days to crack if your password include all possible characters.
    which are:
    0123456789AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz <SP>!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~


Class of Attack



Class A

Class B

Class C

Class D

Class E

Class F











88½ Secs

9 Secs






85 Million

2¼ Hours

14 Mins

1½ Mins

8½ Secs




8 Billion

9½ Days

22½ Hours

2¼ Hours

13½ Mins

1¼ Mins

8 Secs


782 Billion

2½ Years

90 Days

9 Days

22 Hours

2 Hours

13 Mins


75 Trillion

238 Years

24 Years

2½ Years

87 Days

8½ Days

20 Hours


7.2 Quadrillion

22,875 Years

2,287 Years

229 Years

23 Years

2¼ Years

83½ Days

83.5 days on a super computing node to crack a 8-character password ? So let’s make your password AT LEAST 8-CHARACTER LONG !

3. But how to make it memorable to you ?
”Memorable” is a very subjective term and rely heavily on your personal preferences, so I would introduce only a few techniques from Wikihow – find out which one suit you most  !

How to store my password securely

Most importantly: do NOT write it down and keep it somewhere – you probably spend more time to find where do you store that piece of paper Open-mouthed smile

Instead, with the popularity of today’s smartphone, make use of it:

My personal favourite is LastPassI only wish that them implement finger-print authentication so that I can use it safer on iPhone 5S .

So that’s it – hope you find your own way to create secure and memorable password folks !
Last but not least, even if you come up with the most difficult passwords to crack, you’re still prone “social engineering” !

May 6, 2014

Lucene vs. Solr vs. ElasticSearch vs. Sphinx ? How to do real-time full text search properly ?

Currently I am researching on the solution for a real-time search engine which scourge user submitted contents. The user pool consists of 250+ private institutions which translate into 10K-15K users. I/O will be relatively low, but the data size could be ranging wildly since the users are uploading Microsoft Words, Excel and PDF file.

The index is based on the user uploaded files (mostly are Word/Excel/PDF/PowerPoint, and ASCII files). The I/O is expected at only 10 IOPS -20 IOPS but it can vary depends on the date. Maximum I/O could be 100 IOPS. Current database size is reaching 10GB, it's 4 months old.

For real time search server, I'm considering Solr / Lucene and probably ElasticSearch. But the challenge is how to index these files FAST, so that search server can query the index in real time.

I have found some similar questions on how to index .doc/.xls/.pdf, but they did not mention how to ensure indexing performance:

How to build the index FAST ?

Any suggestion on the architecture ? Should I focus on building fast infrastructure (i.e. RAID, SSD, more CPU, Network bandwidth ?) or focus on the index tools & algorithm?

P/S: this question is asked on Stackoverflow as well

Apr 28, 2014

Finding the best of the breed – or which one to rule them all ?

Disclaimer: this article not intended to ignite flames or cause arguments on the Internet. It is about evaluating the candidate languages or frameworks to use in the N-tier programming model (from presentation tier, logic tier to data tier), and there is no one-size-fits-all. So, please take it with a grain of salt and read on.

Presentation tier (front-end)
For Javascript: My love goes to jQuery: there are many alternatives such as Prototype, MooTools, Scriptaculous but none can beat jQuery in terms of documentation or community support. Moreover, many CDNs support jQuery.

For CSS, jQueryUI or Bootstrap are my favourites. For big project, I’d go with jQueryUI – reason being is jQueryUI offer many features more than Bootstrap (Accordions, Draggable ..etc).  For small projects, I’d go with Bootstrap (very lightweight and quite comprehensive). Of course, I’d write CSS using SASS ! You may ask why not LESS: well, here and here are some supporting evidences.

Logic tier (middleware & API)
This one is tough – every language and framework can be used to produce effective middleware & API code depending on your business requirement and usage scenarios. Therefore, I would not boast about any name. Instead, there are some good principles and practices for writing efficient API code. Of course there are some great books on this matter that I'd wholeheartedly vouch for : Clean Code, The Pragmatic Programmer.

Data tier (storage, database & file server)
In today’s distributed computing world, Hadoop is one of the champions (in IMHO) – I found these tips are pretty useful before you’re going to adopt Hadoop. I also heard about Hive and its usage in Linkedin datacenter but never used Hive in any of my projects. I’d love to have a chance to experience it in production. Nevertheless, here is a fair comparison: Hadoop vs Hive (courtesy of Zheng Shao - Facebook Engineer Manager)

For storage – NoSQL is a rising star vs traditional SQL. Big-data companies (Facebook, Twitter, LinkedIn, Google, Yahoo) adopted NoSQL long ago – so it’s time you learn about it, join me in learning NoSQL and share your experience with me :)

Right now, I am starting with MongoDB with a MEAN stack. Man I’m loving the speed of this stack compared to ASP.NET MVC or even LAMP/XAMPP.

Other notes
Javascript alternative (altJS):
TypeScript, CoffeeScript, Dart.
Once upon a time, writing several hundred lines of Javascript would be a nightmare – no longer the case when there is Typescript. It lets you write classes and declare namespace (for code cohesion), implement inheritance (IMO, one of the most useful O-O features).

So that is a few lines from my thoughts on a bright sunshine Monday –  do you agree, do you not ? Let me know and we can always discuss ;) of course not in this manner ^_^

Apr 22, 2014

Defensive programming – simple method to prevent Object reference not set exception


Just to share a simple way to prevent the ugly “object reference not set” exception: 

public class DefensiveCode
//Non-defensive code (unsafe):
public IList<string> UnsafeProps { get; set; }
public void DoSomething(string input)
//props can be null --> exception
if (UnsafeProps.Contains(input))
// work

//Defensive code #1:
public IList<string> SafeProps { get; set; }
public void DoSomethingSafely(string input)
//a little better, but have to check every time
//and it may depend on how compiler evaluate: L-to-R is OK, but R-to-L will not be OK
if (SafeProps != null && SafeProps.Contains(input))
// work

//Defensive code #2: (preferred)
private IList<string> _SafestProps;
public IList<string> SafestProps
//initialize before accessing it.
if (_SafestProps == null) _SafestProps = new List<string>();
return _SafestProps;
set { _SafestProps = value; }

public void DoSomethingSafestWay(string input)
//it’s always safe
if (SafestProps.Contains(input))
// work
A lesson learnt: do not return NULL , return empty list or empty string instead.

Mar 24, 2014

Fixed: Windows is unable to install to the selected location on SSD drive - 0x80300024


I was trying to have dual boot: Hackintosh and Windows 7, and the Windows installer throw it into my face:

Windows is unable to install to the selected location. Error 0x80300024

My setup is on my SSD – 1 partition as Mac OS X Extended (Journaled) and one as MS-DOS (FAT). The boot is using GUID partition map.

I did a simple Google search and the simplest solution that I found is to just unplug any other hard drive that you may have, and keep only the one that you want to have dual boot.  After that try again with your dual boot process.

It works, voila ! Simple and easy.

Mar 14, 2014

attribute x-webkit-speech deprecated aka the Voice Driven Web Apps saga begins


Today when debugging my web, I saw this messing in the console:

The 'x-webkit-speech' input field attribute is deprecated. Please use the JavaScript API instead.
Ok I used the Chrome feature on one of my textboxes:
<input id="q" x-webkit-speech="" onwebkitspeechchange="transcribe(this.value);" placeholder="Enter search term" name="q" onfocus="if(this.value=='Enter search term') this.value = '';" onblur="if (this.value=='' ) this.value = 'Enter search term';" type="text" maxlength="100" value="" autocomplete="off">
It is to create this effect:


You can try it yourself (if you’re on Chrome):

So, Google is deprecating x-webkit-speech feature on Chrome/Chromium. What’s next ? Using Javascript speech API or HTML5? Welcome to the new saga.

Anyway, if you’re interested, continue to read on at

Mar 13, 2014

How to change country in AppStore on iPhone / iPad/ iTunes


There are chances that the app you are looking for is only available in certain country. So you’ll need to switch the country of your AppStore.
In fact, this question is so popular asked (Let Me Google It For You : , but not many answer with intuitive steps. So I take it for myself.

A. On iPhone / iPad (running iOS 7)

1. Tap on the App Store icon in your Home Screen, open it

2. Tap on Featured on the bottom left corner of screen.

3. Scroll all the way to the bottom where your Apple ID info is. Tap on it.


4. Tap View Apple ID, you may have to enter your password.


5. Once the page loads, tap on Country/Region and change your country/region to the country of your choice.



6. Now you can find the app that is available only in certain country


B. On iTunes  (Mac / PC)

1. Open iTunes


2. Scroll to the bottom right of iTunes, click on the flag icon


3. You’ll be able to change the region/country:


4. Once it’s finished, you can find the app that is available only in certain country:


Mar 11, 2014

Web developer: conform to W3C standards or you’ll shoot yourself (or someone else) in the foot

During debug and bug fixing, I encounter the code written by someone else where they had “<div>  nested inside <span>”.  Sound familiar ?
1. Problem: We are facing  the wrongly rendered webpage (full size screenshot)1
2. Root cause: According to HTML standard:  : Generally, inline elements may contain only data and other inline elements
3. Analysis & solution:
Bad code:  block element (<div>, <li>,  <p>) is inside inline element (<span/>)
   1:  <span>
   2:      <div class="Guideline" id="PG0716A073204">
   3:          <li style="font-weight: bold">Prescribing Guidelines:
   4:          </li>
   5:          <p>Treatment with HMG CoA Reductase Inhibitors.
   6:          </p>
   7:      </div>
   8:  </span>

Fixed code:  convert block element to inline element and use CSS for styling, conform to HTML standards

   1:  <span>
   2:      <span class="Guideline" id="PG0716A073204">
   3:          <span style="font-weight: bold">Prescribing Guidelines:
   4:          </span>
   5:          <span>Treatment with HMG CoA Reductase Inhibitors.
   6:          </span>
   7:      </div>
   8:  </span>

4. Results: the webpage is render properly now (screenshot)

So, lesson learnt. As modern browser tend to enforce W3C standards more strict, web developers MUST understand and learn them.

To ensure your web is conforming to standards, try out :  it