Sunday, April 19, 2009

Inputting only numbers using Java Script and HTML

The basic input text field of HTML is very limited when it comes numeric data. There are times in which a better user experience is needed.
In order to generate a better user experience, 2 main features can be easily added to the input text field by using JavaScript:
  • Allow user to input only numeric data. That means that any character other than numbers dots or commas is not allowed. This feature prevents from the user to entering undesired data to the field.
  • Show data in a formatted manner when field is not edited. That means that when field lost focus, its contents are shown with commas or dots. That makes the numeric data on the text field to be more readable.
Note, that we also would like the text to be formatted according to a specific Locale. That means that we want to use decimal separator and grouping separator to be according to our demands. There are countries and cultures in which the decimal separator is comma and some other countries in which decimal separator is dot. The same applies to grouping separator.
In order to achieve our 2 goals we will build 3 java script functions. Each function will be assigned to a specific JavaScript event.
  • onkeypress: This event is activated whenever a key is being pressed when the cursor is in the text field. A function that returns "false" on this event cancels the event and thus prevent from the pressed character to be updated on the text field. We will assign to this even a function named: numbersOnly. This function receives 4 parameters:
    • field: The text field that called the function.
    • e: The onkeypress event.
    • isDec: Indicate that we would like the input to be decimal and not only integer.
    • decimalSeperator: The character used as a decimal separator (probably “.” or “,”).
    In return this function will return true whenever the pressed character is allowed to be inputted by the user or false if character is not allowed to be inputted.
  • onfocus: This event is activated when the text field receives focus. That means, when we are entering to the text field. This event will be assigned with a function named: plainNumber. This function takes the numeric data in the text field and converts it to a plain number, meaning, any numeric formatted data containing dots or command will be converted to a plain number ready to be edited. This function has 2 parameters:
    • field: The text field field that called the function.
    • decimalSeperator: The character used as a decimal separator (probably “.” or “,”).
  • onblur: This event is activated when the field loses focus. That means when we are entering the field by moving to another element on the page. This event will be assinged with a function named: formattedNumber. This function converts the plain numeric data on the text field to a formatted data containing grouping separators. This function has 3 parameters:
    • field: The text field field that called the function.
    • decimalSeperator: The character used as a decimal separator (probably “.” or “,”).
    • groupingSeperator: The character used as a grouping separator (probably “.” or “,”).

I made an example showing a text field utilizing the 3 events to create the described behavior. The example contains a simple HTML page containing the JavaScript methods and a simple text field. The JavaScript code used in this example is not state of the art, but working fine on both FireFox and Explorer. This code can be further refined by encapsulating all the behavior to a single static JavaScript class.

Here is the example code showing input numbers only of an Integer number:

<html>
 <head>
  <title> JavaScript Input Example </title>
 </head>
 <body>
<script>
function numbersOnly(field, e, isDec, decimalSeperator)
{
  var key;
  var keychar;
if (window.event)
   key = window.event.keyCode;
else if (e)
   key = e.which;
else
   return true;
  keychar = String.fromCharCode(key);
// control keys
  if ((key == null) || (key == 0) || (key == 8) ||
      (key == 9) || (key == 13) || (key == 27) || (key == 39) /*|| (key == 37)*/)
  {
    return true;
  }
  else if ((("0123456789").indexOf(keychar) > -1) ||
    (isDec && (keychar == decimalSeperator) && (field.value.indexOf(decimalSeperator) < 0)))
  {
    return true;
  }
 return false;
}
function formattedNumber(field, decimalSeperator, groupingSeperator)
{
    field.value = addGroupingSeperator(field.value, decimalSeperator, groupingSeperator);
}
function plainNumber(field, decimalSeperator)
{
    field.value = field.value.replace(
        new RegExp("[^0123456789" + decimalSeperator + "" + "]", 'g'), "");
}
function addGroupingSeperator(nStr, decimalSeperator, groupingSeperator)
{
    nStr += '';    
    x = nStr.split(decimalSeperator);
    x1 = x[0];
    x2 = x.length > 1 ? decimalSeperator + x[1] : '';
    var rgx = /(\d+)(\d{3})/;
    while (rgx.test(x1)) {
        x1 = x1.replace(rgx, '$1' + groupingSeperator + '$2');
    }
    return x1 + x2;
}
</script>
    <input id="inputInteger" name="inputInteger" maxLength="7"
       onfocus="plainNumber(this, '.');"
       onblur="formattedNumber(this, '.', ',')"
       onkeypress="return numbersOnly(this, event, false, '.')">
 </body>
</html>
Note that the data of the decimal and grouping separator can be taken from your programming language and assigned dynamically according to the specific user Locale information.

Tuesday, April 14, 2009

Hibernate Bi-Directional One to One mapping using Annotations

It took me more than few minutes to find how to do one to one mapping using Hibernate Annotations, so I though I will share it.

I think Hibernate Annotations is best explained by example. Actually, I am not sure I have ever read anything about Hibernate Annotation mappings beside looking at examples…

This example is built from 2 classes: Person and PersonDetails, corresponding to 2 database tables: person and person_details. The 2 classes will demonstrate the usage of one to one mapping from both directions.

I am not sure this example is so close to the real world, but I believe it is enough to get the idea.

The person table contains the following columns:

  • person_id – used as primary key with auto increment
  • first_name
  • last_name
  • birth_date

The person_details table contains the following columns:

  • person_id – used as primary key and foreign key to person table (person_id column)
  • weight
  • height
  • hair_color
  • eyes_color

Note that there may be persons with no person details. That means that having a row in person table, but no row in person_details table is a trivial case. Of course that there may be at the most one person details row for each person.

This is how the Person class looks like using Hibernate Annotations:

package com.bashan.hibernate;
import org.hibernate.validator.Length;
import org.hibernate.validator.NotNull;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
@Entity
@Table(name="person")
public class Person implements Serializable {
  @Id
  @GeneratedValue(strategy= GenerationType.AUTO)
  @Column(name="person_id")
  private Integer personId;
  @Column(name="first_name")
  @NotNull
  @Length(max = 50)
  private String firstName;
  @Column(name="last_name")
  @NotNull
  @Length(max = 50)
  private String lastName;
  @Column(name="birth_date")
  private Date birthDate;
  @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "person")
  @JoinColumn(name="person_id")
  private PersonDetails personDetails;
  public Integer getPersonId() {
    return personId;
  }
  public void setPersonId(Integer personId) {
    this.personId = personId;
  }
  public String getFirstName() {
    return firstName;
  }
  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }
  public String getLastName() {
    return lastName;
  }
  public void setLastName(String lastName) {
    this.lastName = lastName;
  }
  public Date getBirthDate() {
    return birthDate;
  }
  public void setBirthDate(Date birthDate) {
    this.birthDate = birthDate;
  }
  public PersonDetails getPersonDetails() {
    return personDetails;
  }
  public void setPersonDetails(PersonDetails personDetails) {
    this.personDetails = personDetails;
  }
}

And the PersonDetails class:
package com.bashan.hibernate;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
import javax.persistence.*;
@Entity
@Table(name="person_details")
public class PersonDetails {
  @Id
  @GeneratedValue(generator="foreign")
    @GenericGenerator(name="foreign", strategy = "foreign", parameters={
      @Parameter(name="property", value="person")
    })
  @Column(name="person_id")
  private Integer personId;
  @OneToOne(fetch = FetchType.LAZY, optional=true)
  @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})
  @PrimaryKeyJoinColumn
  private Person person;
  @Column(name="weight")
  private Integer weight;
  @Column(name="height")
  private Integer height;
  @Column(name="hair_color")
  private Integer hardColor;
  @Column(name="eyes_color")
  private Integer eyesColor;
  public Integer getPersonId() {
    return personId;
  }
  public void setPersonId(Integer personId) {
    this.personId = personId;
  }
  public Person getPerson() {
    return person;
  }
  public void setPerson(Person person) {
    this.person = person;
  }
  public Integer getWeight() {
    return weight;
  }
  public void setWeight(Integer weight) {
    this.weight = weight;
  }
  public Integer getHeight() {
    return height;
  }
  public void setHeight(Integer height) {
    this.height = height;
  }
  public Integer getHardColor() {
    return hardColor;
  }
  public void setHardColor(Integer hardColor) {
    this.hardColor = hardColor;
  }
  public Integer getEyesColor() {
    return eyesColor;
  }
  public void setEyesColor(Integer eyesColor) {
    this.eyesColor = eyesColor;
  }
}

That’s pretty much it… I hope it will save you time…

Monday, April 6, 2009

Adding TLS support to Log4j SMTP Appender

SMTPAppender that comes with log4j is a pretty useful Appender, allowing easily to start getting email alerts for errors in your application. But, this class is missing one important property (well, maybe more than one...): TLS support. Most modern mail servers use TLS for sending mails. TLS (Transport Layer Security) is a secure way for transfering information between two machines. For example, if you are using Google Apps (or even if you have a regular Gmail account) and you would like to use your account (user name and password of course) to send mail using SMTPAppender you won't be able to do it. That is because, Google allows sending mails only using TLS.

In this post: "Sending Email alerts with Log4j – Controlled Alerts" I showed how log4j SMTPAppender class can be extended to allow email alerts to be more controlled. In this post: "Sending SMS alerts with Log4j using ipipi.com", I showed how log4j SMTPAppender can be extended to send SMS error messages using ipipi.com service.
Both posts use this
class: BaseFilteredSMTPAppender as a basic class for adding more neat capabilities to SMTPAppender.

I will show you how this class (BaseFilteredSMTPAppender) can be easily changed, to add the SMTPAppender TLS capabilities.
Unfortunatly, SMTPAppender class was not designed so well. It does not allow any control over the properties used for the creation of javax.mail.Session instance. In order to add TLS support to mail sending, we simply have to add to the javax.mail.Session class the following property:

props.put("mail.smtp.starttls.enable","true");
Where props is a simple Property instance containing mail properties.
And then we get the session instance, for example, by doing:
Session session = Session.getInstance(props);
But, as was said before, we have no access to the Properties instance, and therefore cannot add the TLS property.

Luckily, SMTPAppender does contain a protected method, for getting the Session instance: createSession. We can override this method and create a Session instance that contains TLS support. I copied the code of this method exactly as it was on the original SMTPAppender, and simply added the TLS property (note that TLS support is added only if user actually use the TLS property in the appender definition). This is how the class BaseFilteredSMTPAppender looks after adding the TLS support:

import org.apache.log4j.net.SMTPAppender;
import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import java.util.*;
public abstract class BaseFilteredSMTPAppender extends SMTPAppender {
  private int timeFrame;
  private int maxEMails;
  protected long timeFrameMillis;
  protected Boolean isTLS;
  protected List<Date> exceptionDates = new ArrayList<Date>();
  public int getTimeFrame() {
    return timeFrame;
  }
  public void setTimeFrame(int timeFrame) {
    this.timeFrame = timeFrame;
  }
  public int getMaxEMails() {
    return maxEMails;
  }
  public void setMaxEMails(int maxEMails) {
    this.maxEMails = maxEMails;
  }
  public void setTLS(boolean isTLS) {
    this.isTLS = isTLS;
  }
  @Override
  public void activateOptions() {
    super.activateOptions();
    timeFrameMillis = timeFrame * 60 * 1000;
  }
  @Override
  protected Session createSession() {
    Properties props = null;
    try {
        props = new Properties (System.getProperties());
    } catch(SecurityException ex) {
        props = new Properties();
    }
    if (getSMTPHost() != null) {
      props.put("mail.smtp.host", getSMTPHost());
    }
    Authenticator auth = null;
    if(getSMTPUsername() != null && getSMTPPassword() != null) {
      props.put("mail.smtp.auth", "true");
      auth = new Authenticator() {
        protected PasswordAuthentication getPasswordAuthentication() {
          return new PasswordAuthentication(getSMTPUsername(), getSMTPPassword());
        }
      };
    }
    if (isTLS != null && isTLS)
    {
      props.put("mail.smtp.starttls.enable","true");
    }
    Session session = Session.getInstance(props, auth);
    if (getSMTPDebug()) {
        session.setDebug(getSMTPDebug());
    }
    return session;
  }
  protected void cleanTimedoutExceptions() {
    Date current = new Date();
    // Remove timedout exceptions
    Iterator<Date> itr = exceptionDates.iterator();
    while (itr.hasNext()) {
      Date exceptionDate = itr.next();
      if (current.getTime() - exceptionDate.getTime() > timeFrameMillis) {
        itr.remove();
      } else {
        break;
      }
    }
  }
  protected void addException() {
    exceptionDates.add(new Date());
  }
  protected boolean isSendMailAllowed() {
    return exceptionDates.size() < maxEMails;
  }
}

In order to use the Appender, only one additional parameter has to be added to the parameters already used and shown in the previous 2 blogs dealing with log4j SMTPAppender: TLS.

In order to make things a little interesting I will show you log4j configuration example using XML file instead of properties file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">  
   <appender name="console" class="org.apache.log4j.ConsoleAppender">
      <param name="Target" value="System.out"/>
      <layout class="org.apache.log4j.PatternLayout">
         <param name="ConversionPattern" value="%d{HH:mm:ss,SSS} %-5p [%c{1}] %m%n"/>
      </layout>
   </appender>
    <appender name="email" class="com.bashan.log4j.appender.FilteredSMTPAppender">
        <param name="BufferSize" value="10"/>
        <param name="SMTPHost" value="smtp.gmail.com"/>
        <param name="SMTPUsername" value="username@gmail.com"/>
        <param name="SMTPPassword" value="password"/>
        <param name="TLS" value="true"/>
        <param name="TimeFrame" value="10"/>
        <param name="MaxEMails" value="2"/>
        <param name="From" value="username@gmail.com"/>
        <param name="To" value="anotherUsername@gmail.com"/>
        <param name="Subject" value="Server Error"/>
        <layout class="org.apache.log4j.PatternLayout">
          <param name="ConversionPattern" value="%d{HH:mm:ss,SSS} %-5p [%c{1}] %m%n"/>
        </layout>
    </appender>  
    <root>
      <priority value="warn"/>
      <appender-ref ref="console"/>
      <appender-ref ref="email"/>
   </root>
</log4j:configuration>

This file can be dropped on your root src directory and log4j will know to find and load it automatically.

Note that TLS property is not mandatory. If you don't need TLS support, you can simply not add it to the appender properties.

Monday, March 30, 2009

Getting Countries list in Java

Most modern web applications need to show somewhere a dropdown or a list containing all countries. Getting the list of all countries is solved in all sort of ways:

  • Building a database table containing all countries.
  • Storing all list of countries in a file.
  • Build a hard coded list or array of all countries.

One additional way, is using java to get all list of countries. The benefit of using Java to do the Job, is that Java can produce the list of countries in any desired language. This is good for internationalized web applications. Another good reason, is maintenance. On each new release the data is kept updated. Country names and and country codes are not changed and added often, but changes do happen from time to time and it is best to be updated with no effort.

The list of countries can be generated by calling the method of Locale class: getISOCountries(). This method returns string array all all the exiting country codes in ISO 3116-1 alpha-2 (2 letter) standard.

From this list it is very easy to create Locales for all countries. By calling the Locale method: getDisplayCountry(), the name of the country can be retrieved. Calling this method with a given Locale returns the name of the country in the specific language of the locale. By the way, I noted that Java did not implemented completely the getDisplayCountry() for all languages. For example, if you would like to get the list of countries in Hebrew, the only country that is returned actually in Hebrew is Israel. I believe that over time Java will include translations for all languages.

After generating list of countries for a specific language, we will sort the list. Of course that the list will be sorted according to the chosen language.

We will use a basic Country class for representing a single country, this class has only 2 members: country code and name:

public class Country {
    private String countryCode;
    private String name;
    public Country(String countryCode, String name)
    {
        this.countryCode = countryCode;
        this.name = name;
    }
    public String getCountryCode() {
        return countryCode;
    }
    public void setCountryCode(String countryCode) {
        this.countryCode = countryCode;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String toString()
    {
        return countryCode + ", " + name;
    }
}

And the CountryUtil class for generating list of countries for a specifc language.

This class has 2 methods:

  • getCountries: This method returns list of Country objects of all countries in a specific desired language (Locale).
  • getCountriesMap: This method returns a Map of all countries in a specific desired languages (Locale). The key of the map is the countryCode and the values is the name of the country. A map can be useful if you would like to get a country by its code. Note that in order to construct the Map the class: LinkedHashMap is used. This is done in order to preserve the sort order of the list.

This is the CountryUtil class:

package com.bashan.blog;
import java.util.*;
public class CountryUtil {
  public static List<Country> getCountries(final Locale inLocale) {
    String[] countryCodes = Locale.getISOCountries();
    List<Country> countries = new ArrayList<Country>(countryCodes.length);
    for (String countryCode : countryCodes) {
      countries.add(new Country(countryCode, new Locale("", countryCode).getDisplayCountry(inLocale)));
    }
    Collections.sort(countries, new Comparator<Country>() {
      public int compare(Country c1, Country c2) {
        return c1.getName().compareTo(c2.getName());
      }
    });
    return countries;
  }
  public static Map<String, String> getCountriesMap(final Locale inLocale) {
    List<Country> countries = getCountries(inLocale);
    Map<String, String> countriesMap = new LinkedHashMap<String, String>(countries.size());
    for (Country country : countries) {
      countriesMap.put(country.getCountryCode(), country.getName());
    }
    return countriesMap;
  }
  public static void printCounties(List<Country> countries) {
    for (Country country : countries) {
      System.out.println(country);
    }
  }
  public static void main(String[] args) {
    // Get list of countries in US English
    System.out.println("---- List of countries in English ----");
    List<Country> countries = getCountries(Locale.US);
    printCounties(countries);
    System.out.println("---- List of countries in Japanese ----");
    // Get list of countries in Japanese
    countries = getCountries(Locale.JAPANESE);
    printCounties(countries);
  }
}
On the bottom of the class you can notice a small testing program that outputs all countries in English and in Japanese. This is how the output looks like:
---- List of countries in English ----
AF, Afghanistan
AL, Albania
DZ, Algeria
AS, American Samoa
AD, Andorra
AO, Angola
AI, Anguilla
AQ, Antarctica
AG, Antigua and Barbuda
AR, Argentina
AM, Armenia
AW, Aruba
AU, Australia
AT, Austria
AZ, Azerbaijan
BS, Bahamas
BH, Bahrain
BD, Bangladesh
BB, Barbados
BY, Belarus
BE, Belgium
BZ, Belize
BJ, Benin
BM, Bermuda
BT, Bhutan
BO, Bolivia
BA, Bosnia and Herzegovina
BW, Botswana
BV, Bouvet Island
BR, Brazil
IO, British Indian Ocean Territory
VG, British Virgin Islands
BN, Brunei
BG, Bulgaria
BF, Burkina Faso
BI, Burundi
KH, Cambodia
CM, Cameroon
CA, Canada
CV, Cape Verde
KY, Cayman Islands
CF, Central African Republic
TD, Chad
CL, Chile
CN, China
CX, Christmas Island
CC, Cocos Islands
CO, Colombia
KM, Comoros
CG, Congo
CK, Cook Islands
CR, Costa Rica
HR, Croatia
CU, Cuba
CY, Cyprus
CZ, Czech Republic
CI, Côte d'Ivoire
DK, Denmark
DJ, Djibouti
DM, Dominica
DO, Dominican Republic
EC, Ecuador
EG, Egypt
SV, El Salvador
GQ, Equatorial Guinea
ER, Eritrea
EE, Estonia
ET, Ethiopia
FK, Falkland Islands
FO, Faroe Islands
FJ, Fiji
FI, Finland
FR, France
GF, French Guiana
PF, French Polynesia
TF, French Southern Territories
GA, Gabon
GM, Gambia
GE, Georgia
DE, Germany
GH, Ghana
GI, Gibraltar
GR, Greece
GL, Greenland
GD, Grenada
GP, Guadeloupe
GU, Guam
GT, Guatemala
GN, Guinea
GW, Guinea-Bissau
GY, Guyana
HT, Haiti
HM, Heard Island And McDonald Islands
HN, Honduras
HK, Hong Kong
HU, Hungary
IS, Iceland
IN, India
ID, Indonesia
IR, Iran
IQ, Iraq
IE, Ireland
IL, Israel
IT, Italy
JM, Jamaica
JP, Japan
JO, Jordan
KZ, Kazakhstan
KE, Kenya
KI, Kiribati
KW, Kuwait
KG, Kyrgyzstan
LA, Laos
LV, Latvia
LB, Lebanon
LS, Lesotho
LR, Liberia
LY, Libya
LI, Liechtenstein
LT, Lithuania
LU, Luxembourg
MO, Macao
MK, Macedonia
MG, Madagascar
MW, Malawi
MY, Malaysia
MV, Maldives
ML, Mali
MT, Malta
MH, Marshall Islands
MQ, Martinique
MR, Mauritania
MU, Mauritius
YT, Mayotte
MX, Mexico
FM, Micronesia
MD, Moldova
MC, Monaco
MN, Mongolia
ME, Montenegro
MS, Montserrat
MA, Morocco
MZ, Mozambique
MM, Myanmar
NA, Namibia
NR, Nauru
NP, Nepal
NL, Netherlands
AN, Netherlands Antilles
NC, New Caledonia
NZ, New Zealand
NI, Nicaragua
NE, Niger
NG, Nigeria
NU, Niue
NF, Norfolk Island
KP, North Korea
MP, Northern Mariana Islands
NO, Norway
OM, Oman
PK, Pakistan
PW, Palau
PS, Palestine
PA, Panama
PG, Papua New Guinea
PY, Paraguay
PE, Peru
PH, Philippines
PN, Pitcairn
PL, Poland
PT, Portugal
PR, Puerto Rico
QA, Qatar
RE, Reunion
RO, Romania
RU, Russia
RW, Rwanda
SH, Saint Helena
KN, Saint Kitts And Nevis
LC, Saint Lucia
PM, Saint Pierre And Miquelon
VC, Saint Vincent And The Grenadines
WS, Samoa
SM, San Marino
ST, Sao Tome And Principe
SA, Saudi Arabia
SN, Senegal
RS, Serbia
CS, Serbia and Montenegro
SC, Seychelles
SL, Sierra Leone
SG, Singapore
SK, Slovakia
SI, Slovenia
SB, Solomon Islands
SO, Somalia
ZA, South Africa
GS, South Georgia And The South Sandwich Islands
KR, South Korea
ES, Spain
LK, Sri Lanka
SD, Sudan
SR, Suriname
SJ, Svalbard And Jan Mayen
SZ, Swaziland
SE, Sweden
CH, Switzerland
SY, Syria
TW, Taiwan
TJ, Tajikistan
TZ, Tanzania
TH, Thailand
CD, The Democratic Republic Of Congo
TL, Timor-Leste
TG, Togo
TK, Tokelau
TO, Tonga
TT, Trinidad and Tobago
TN, Tunisia
TR, Turkey
TM, Turkmenistan
TC, Turks And Caicos Islands
TV, Tuvalu
VI, U.S. Virgin Islands
UG, Uganda
UA, Ukraine
AE, United Arab Emirates
GB, United Kingdom
US, United States
UM, United States Minor Outlying Islands
UY, Uruguay
UZ, Uzbekistan
VU, Vanuatu
VA, Vatican
VE, Venezuela
VN, Vietnam
WF, Wallis And Futuna
EH, Western Sahara
YE, Yemen
ZM, Zambia
ZW, Zimbabwe
AX, Åland Islands

---- List of countries in Japanese ----

IS, アイスランド
IE, アイルランド
AZ, アゼルバイジャン
AF, アフガニスタン
AS, アメリカンサモア
US, アメリカ合衆国
AE, アラブ首長国連邦
DZ, アルジェリア
AR, アルゼンチン
AL, アルバニア
AW, アルバ島
AM, アルメニア
AI, アンギラ
AO, アンゴラ
AG, アンチグアバーブーダ
AD, アンドラ
YE, イエメン
GB, イギリス
IL, イスラエル
IT, イタリア
IQ, イラク
IR, イラン
IN, インド
ID, インドネシア
UG, ウガンダ
UA, ウクライナ
UZ, ウズベキスタン
UY, ウルグアイ
EC, エクアドル
EG, エジプト
EE, エストニア
ET, エチオピア
ER, エリトリア
SV, エルサルバドル
OM, オマーン
NL, オランダ
AN, オランダ領アンティル諸島
AU, オーストラリア
AT, オーストリア
AX, オーランド諸島
KZ, カザフスタン
QA, カタール
CA, カナダ
CM, カメルーン
KH, カンボジア
CV, カーボベルデ
GY, ガイアナ
GA, ガボン
GM, ガンビア
GH, ガーナ
CY, キプロス
CU, キューバ
KI, キリバス
KG, キルギスタン
GN, ギニア
GW, ギニアビサウ
GR, ギリシア
KW, クウェート
CK, クック諸島
CX, クリスマス島
HR, クロアチア
GT, グアテマラ
GP, グアドループ
GU, グアム
GL, グリーンランド
GE, グルジア
GD, グレナダ
KY, ケイマン諸島
KE, ケニア
CC, ココス諸島
CR, コスタリカ
KM, コモロ
CO, コロンビア
CG, コンゴ
CD, コンゴ民主共和国
CI, コートジボアール
SA, サウジアラビア
GS, サウスジョージア島・サウスサンドウィッチ島
ST, サントメ・プリンシペ
PM, サンピエール島・ミクロン島
SM, サンマリノ
ZM, ザンビア
SL, シエラレオネ
SY, シリア
SG, シンガポール
DJ, ジブチ
GI, ジブラルタル
JM, ジャマイカ
ZW, ジンバブエ
CH, スイス
SE, スウェーデン
SJ, スバールバル諸島・ヤンマイエン島
ES, スペイン
SR, スリナム
LK, スリランカ
SK, スロバキア
SI, スロベニア
SZ, スワジランド
SD, スーダン
SC, セイシェル
SN, セネガル
RS, セルビア
CS, セルビア・モンテネグロ
KN, セントクリストファー・ネイビス
VC, セントビンセントおよびグレナディーン諸島
SH, セントヘレナ島
LC, セントルシア
SO, ソマリア
SB, ソロモン諸島
TH, タイ
TJ, タジキスタン
TZ, タンザニア
TC, タークス諸島・カイコス諸島
CZ, チェコ
TD, チャド
TN, チュニジア
CL, チリ
TV, ツバル
DK, デンマーク
TK, トケラウ諸島
TT, トリニダード・トバゴ
TM, トルクメニスタン
TR, トルコ
TO, トンガ
TG, トーゴ
DE, ドイツ
DO, ドミニカ共和国
DM, ドミニカ国
NG, ナイジェリア
NR, ナウル
NA, ナミビア
NU, ニウエ島
NI, ニカラグア
NE, ニジェール
NC, ニューカレドニア
NZ, ニュージーランド
NP, ネパール
NO, ノルウェー
NF, ノーフォーク島
HT, ハイチ
HU, ハンガリー
HM, ハード・マクドナルド諸島
VA, バチカン
VU, バヌアツ
BS, バハマ
BB, バルバドス
BD, バングラデシュ
BM, バーミューダ諸島
BH, バーレーン
PK, パキスタン
PA, パナマ
PG, パプアニューギニア
PW, パラオ
PY, パラグアイ
PS, パレスチナ
PN, ピトケアン島
FJ, フィジー
PH, フィリピン
FI, フィンランド
FO, フェロー諸島
FK, フォークランド諸島
FR, フランス
TF, フランス領極南諸島
BR, ブラジル
BG, ブルガリア
BF, ブルキナファソ
BN, ブルネイ
BI, ブルンジ
BT, ブータン
BV, ブーベ島
PR, プエルトリコ
VN, ベトナム
BJ, ベニン
VE, ベネズエラ
BY, ベラルーシ
BZ, ベリーズ
BE, ベルギー
PE, ペルー
HN, ホンジュラス
BA, ボスニア・ヘルツェゴビナ
BW, ボツワナ
BO, ボリビア
PT, ポルトガル
PL, ポーランド
MO, マカオ
MK, マケドニア
MG, マダガスカル
YT, マヨット島
MW, マラウイ
ML, マリ
MT, マルタ
MQ, マルティニーク島
MY, マレーシア
MH, マーシャル諸島
FM, ミクロネシア
MM, ミャンマー
MX, メキシコ
MZ, モザンビーク
MC, モナコ
MV, モルディブ
MD, モルドバ
MA, モロッコ
MN, モンゴル
ME, モンテネグロ
MS, モントセラト島
MU, モーリシャス
MR, モーリタニア
JO, ヨルダン
LA, ラオス
LV, ラトビア
LT, リトアニア
LI, リヒテンシュタイン
LY, リビア
LR, リベリア
LU, ルクセンブルク
RW, ルワンダ
RO, ルーマニア
LS, レソト
LB, レバノン
RE, レユニオン
RU, ロシア
WF, ワリス・フテュナ諸島
CF, 中央アフリカ共和国
CN, 中華人民共和国
GF, 仏領ギアナ
PF, 仏領ポリネシア
MP, 北マリアナ諸島
ZA, 南アフリカ
AQ, 南極
TW, 台湾
KR, 大韓民国
JP, 日本
KP, 朝鮮民主主義人民共和国
TL, 東ティモール
VI, 米領バージン諸島
UM, 米領太平洋諸島
IO, 英領インド洋地域
VG, 英領バージン諸島
EH, 西サハラ
WS, 西サモア
GQ, 赤道ギニア
HK, 香港