Server Browsing SDK

From GameSpy SDK

Server Browsing SDK

Overview

The GameSpy Server Browsing SDK is a portable LAN and Internet server browser engine. It allows developers to quickly and easily add a list-based matchmaking interface to the game, with powerful features such as server-side filtering, sorting, country-filtering, and ping (latency) measurement.

The concept of Server Browsing was popularized by our original GameSpy3D product, and is used as a matchmaking paradigm by GameSpy Arcade and many other online services today. The system functions as follows:

  1. A game server (or person hosting a game) starts, and reports its presence to our Master Server. This server reporting is done using the Query & Reporting SDK.
  2. Our Master Server aggregates a list of all available game servers, as well as all of the data known about the servers.
  3. Game Clients query the Master Server for a list of available game servers. This query can contain a filter to narrow down the list of servers returned.
  4. Once the list is obtained, the Game Client queries each server to obtain the latest information about the game (the name of the game, map being played, number of players, or any other relevant information). It also measures latency to the server at this time, since latency can be an important factor in the quality of the game play experience.
  5. This collection of servers is then displayed to the user, and they are able to browse the list and select a server to play on, at which point they connect directly to the server.

The Server Browsing SDK manages the entire client-side portion of this process - server list retrieval, server querying, etc. The SDK is a data engine only. You will be responsible for creating all the GUI elements that are required for a server browser in your game. These typically include buttons, long multi-column lists, scrollbars, and edit controls.

Server Browsing is typically used for matchmaking of "dedicated server" games. Dedicated server games are those in which a stand-alone server is run, and outside clients connect to the server. The server continues running even when no players are connected to it, and typically does not have a local client itself. For games that require a group of people to all join together at once, and that do not have persistent servers running (i.e. they use Peer to Peer networking, or require one of the players to "host" the game) the GameSpy Matchmaking Toolkit - which includes the Peer SDK - may be a better choice.

The Peer SDK extends the features of Server Browsing to include a dynamic list of available games, integrated chat lobbies and staging rooms, and more. The Peer SDK can be used for dedicated-server games as well, but using the Server Browsing SDK is quicker and easier to implement if you are simply looking to provide a list-based matchmaking experience.

Two examples are included for your review.

sbctest is a simple C based server list program that demonstrates how to easily receive and display a server list.

sbmfcsample is a C++ / MFC based server list with a full GUI. Your in-game server browser will most likely looking something like this (with the MFC code replaced by your custom GUI code).

This document provides a simple, pseudo-code based set of instructions for implementing an in-game server browser using the Server Browser. Your code will vary based on your specific GUI interfaces.

See the reference documentation for detailed descriptions of each function.

File Manifest

The following files should be included with this package. If any of the files are missing, please contact devsupport@gamespy.com.

File
Description
sb_serverbrowsing.h
Main header file for the Server Browsing SDK - includes all public functions
sb_serverbrowsing.c
Code for primary server browsing functionality
sb_serverlist.c
Server list / master server communication code
sb_queryengine.c
Server query engine code
sb_server.c
Functions for manipulating individual server objects
sb_internal.h
Header files for private functions
sb_crypt.c,h
Encryption code used for master server communication
../qr2/qr2regkeys.c,h
Defines for pre-defined key names

In addition, to build the SDK and samples, you will need to separately download the GameSpy "common code" package, which includes the shared SDK code used by this SDK and others.

When extracting this package, make sure you preserve the directory tree in order to assure that the code builds correctly.

Implementation

Step 0: Implement the Query and Reporting 2 SDK

If you haven't already done so, you need to implement the Query and Reporting 2 SDK in your game. The Query and Reporting 2 SDK allows your game server to report to our master server and be listed for clients to query. Although you can test the Server Browsing SDK by querying other games, typically you'll want to do most of your testing with your own game.

Once you have implemented and tested the Query and Reporting 2 SDK, you can continue with the server list implementation.

Step 1: Create A Server Browser

Your first step should be to create a server browser object (not a true C++ object, just in the sense of an abstract type).

You can create the server browser when your game first starts, or right before you update the list. You can update a single server browser as many times as you want, so you probably won't need to create it more than once (although you can).

To create a server browser, call:

ServerBrowser ServerBrowserNew(const gsi_char *queryForGamename, 
	const gsi_char *queryFromGamename, const gsi_char *queryFromKey, 
	int queryFromVersion, int maxConcUpdates, int queryVersion, 
	SBBool lanBrowse, ServerBrowserCallback callback, void *instance);
queryForGamename
The name of the game you want to browse for. gamenames are issued by our developer relations team. If you do not have one already, contact devsupport@gamespy.com to request a gamename for your game. For testing purposes, you may wish to query for a gamename other than your game - for example, to test how well your list works with several thousand servers listed. Contact devsupport@gamespy.com for a list of alternative gamenames you can use for testing.
queryFromGamename
Your gamename that you were issued with your secret key. If you don't have a gamename or secret key, please contact devsupport@gamespy.com. This will typically be the same as queryForGamename, unless you are querying for a different game list during testing.
queryFromKey
The secret key you were issued that corresponds to your queryFromGamename
queryFromVersion
A version identifier for your game - this is optional and should be set to 0 unless you are told otherwise by developer support
maxConcUpdates
The maximum number of concurrent updates (queries) that will be made. 10 is appropriate for modem users, broadband users can generally accommodate 20-30. You can either present this as an option to your users, or leave it at 10 for everyone. Higher numbers lead to faster refreshes of the server list, but if the refresh speed exceeds the user's capacity, ping times will be measured inaccurately and some servers will time out and not show up on the list.
queryVersion
Determines the protocol used for server queries. If your game implements the Query and Reporting 2 SDK (as most new games will), simply pass QVERSION_QR2. If you are updating a legacy game to support the Server Browsing SDK, but the game still uses the original Query and Reporting SDK, then you should pass QVERSION_GOA.
lanBrowse
The switch to turn on only LAN browsing - use SBTrue if you want only LAN browsing.
callback
The server browser callback function described in Step 3. For now you can just create a stub function with a prototype like:
void SBCallback(ServerBrowser sb, SBCallbackReason reason, SBServer server, 
void *instance) 
{ } // todo
instance
Any game-specific data you want passed to the callback function. For example, you can pass a structure pointer or object pointer for use within the CallBack. If you can access any needed data within the CallBack already, then you can just pass NULL for instance.

This step should look something like:

int CMyGame::OnMultiplayerButtonClicked(...)
{
m_ServerBrowser = ServerBrowserNew("mygame", "mygame", "123456", 0, 10, QVERSION_QR2, SBFalse, SBCallBack, this);
}

Step 2: Update The Server Browser

When you are ready to populate the Server Browser with data, you need to call one of the update functions. There are two update functions available:

ServerBrowserUpdate
Obtains a list of servers from the master server, and then queries the individual servers for information.
ServerListLANUpdate
Scans the local LAN for games and updates the list with them.

Note that if you've already updated the server list once, you need to call ServerBrowserClear to clear the list of servers (otherwise you will end up with duplicates). You can call ServerBrowserClear even if the list hasn't been updated yet (it won't break anything).

When calling either of the update functions, you need to decide whether you want to do updates Synchronously or Asynchronously.

With a Synchronous update, the Update function does not return until the entire list is finished updating. Your callback function will still be called during the update (so you can add servers to your list or repaint the window) but there is no guarantee as to how often the callback will be called. If you choose to use Synchronous updates, it is important that you display status messages to the user as the list state changes, otherwise they may think the game has locked up.

With Asynchronous updates, the Update function returns immediately, but you are responsible for calling the ServerBrowserThink function every 10-100 ms while the list is being updated. If you do not call the function, the update will not occur. If you do not call it often enough, the ping times for servers will be inaccurate.

The sbctest sample uses Synchronous updates, while the Sample1 sample uses Asynchronous updates (and a Windows timer to trigger the ServerBrowserThink function).

You may find it easier to implement the browser with Synchronous updates at first, then switch to Asynchronous updates once it has been fully tested.

The following additional parameters are used with the ServerBrowserUpdate function:

disconnectOnComplete
Determines whether the Server Browser disconnects from the master server after obtaining the server list, or stays connected. The only reason to stay connected is if you expect to be querying the master server for full details on individual servers (using ServerBrowserAuxUpdateServer) in a game that supports NAT Negotiation (and thus may have servers hosted behind firewalls). In most cases you should pass SBTrue here. Even if you need to contact the master server to obtain information with ServerBrowserAuxUpdateServer, that function will automatically reconnect as-needed.
basicFields
An array of information keys that you want to retrieve from each server in the list.
unsigned char basicFields[] = {HOSTNAME_KEY, GAMETYPE_KEY,  MAPNAME_KEY, NUMPLAYERS_KEY, MAXPLAYERS_KEY};
int numFields = sizeof(basicFields) / sizeof(basicFields[0]);
This means that the hostname, gametype, mapname, numplayers, and maxplayers keys will be retrieved for each server in your list. The key indexes are the same as those used in the QR2 SDK. If you've defined custom key indexes for custom keys in your game, you can include those as well. Note that you MUST register all custom keys with qr2_register_key before using their indexes in this function. Once you have the basic keys for servers, you can go back and query for the "full" list of keys your game reports - including player and team keys. Details on re-querying servers for additional information is contained in Step 5.
Note that when using the LAN Update function, you do not need to specify a list of keys - LAN updates automatically retrieve all keys and values from the server.
numBasicFields
The number of basic fields passed in your array.
serverFilter
A filter that will be applied on the master server, prior to sending the list of servers to the client. When applied correctly, filtering can dramatically increase the speed of server list updates by reducing the number of servers to query, and can make it easier for players to find the types of game they are looking for.
All of your server keys are available for filtering, as well as two special keys that are added by the master server:
country
the two-letter ISO country code where a server is located - as-determined by the IP address of the server
region
a numeric bitmask that identifies the region a server is located in (based on the country). See the region list appendix at the end of this document for all available regions.

Note that filtering by "ping" is not possible, since ping is determined by the client - not the master server.

Filter strings are written using SQL-like syntax. Most standard SQL operators are available. Wildcard string comparisions can be made using the "like" operator, with % as the wildcard character.

Here are some examples of useful filter strings:

  • gametype = 'ctf' Only returns games whose gametype key matches 'ctf'
  • numplayers > 0 and numplayers != maxplayers
    Only returns servers who have players on them, but are not full
  • password = 0
    Only returns servers that are not passworded (assuming you use a "password" key to indicate password protected servers)
  • hostname like '%[gsf]%'
    Only returns servers that have the string '[gsf]' somewhere in their name. Could be used, for example, to allow a player to find just the servers their clan runs.
  • (country = 'DE' or country = 'FR') and maxplayers >= 8
    Only returns servers located in Germany or France that support 8 or more players.

Pass NULL or an empty string if no filtering is required.

For LAN Updates you will also need to specify the ports to check for servers on. The Server Browsing SDK will scan a range of ports by sending a query packet to the broadcast address for each one. startSearchport is usually your standard query port (e.g. the UDP port number you pass to qr2_init in the Query and Reporting SDK).

endSearchPort is the highest port to scan. When multiple servers are run on the same machine, the QR2 SDK allocates incrementally higher ports from the starting port for each server. In general, it is not recommended to use an end port more than 100 higher than the start port. A packet must be sent out to all ports between start and end, and higher numbers can lead to broadcast storms.

This step should look like:

int CMyGame::OnRefreshInternetButtonClicked(...)
{
	ServerBrowserUpdate(m_ServerBrowser, SBFalse, SBTrue, basicFields,numBasicFields, NULL);
	...
}
int CMyGame::OnRefreshLANButtonClicked(...)
{
	ServerBrowserLANUpdate(m_ServerBrowser,SBFalse,START_PORT,START_PORT+100);
	...
}

Step 3: Create The List Callback

As the Server Browser updates the server list, it calls back to the function you passed in ServerBrowserNew to give status and progress updates.

The sb parameter is the ServerBrowser object the callback is referring to.

The reason parameter is one of the following values:

sbc_serveradded
A server was added to the list. Note that you may just have an IP and port at this point - all servers are added before they are queried. You can choose to add the server to your UI at this point, or wait until you get a serverupdated callback for the server and have more information to display about it.
sbc_serverupdated
The information for a server has been updated. Either basic or full information is now available about this server.
sbc_serverupdatefailed
An attempt to retrieve information about this server, either directly or from the master server, failed. The server is down or unreachable.
sbc_serverdeleted
A server was removed from the list. This only occurs when using push updates, which are not generally used in the Server Browsing SDK (only the Peer SDK).
sbc_updatecomplete
All queued updates have been completed and the query engine is now idle.
sbc_queryerror
The master returned an error string for the provided query. Typically due to a filter string syntax error. You can obtain the text of the error message from ServerBrowserListQueryError

The server parameter indicates the server that is being referred to, if the message is server-specific.

instance is the instance pointer you passed in when initializing the Server Browser object.

This step should look something like:

void SBCallback(ServerBrowser sb, SBCallbackReason reason, SBServer server, void *instance)
{
	CMyGame *g = (CMyGame *)instance;
	switch (reason)
	{
	case sbc_serveradded :
	      g->ServerView->AddServerToList(server);
	      break;
	case sbc_serverupdated : 
	      g->ServerView->UpdateServerInList(server);
	break;
	case sbc_updatecomplete:
	      g->ServerView->SetStatus("Update Complete");
	      break;
	case sbc_queryerror:
	g->ServerView->SetStatus("Query Error Occurred:", 
	ServerBrowserListQueryError(sb));
	      break;
	}
}

Step 4: Extracting and Displaying Server Information

Somewhere along the line (either in your Callback or a helper function) you will need to actually get the data out of the SBServer object to display it on your list.

The Server Browsing SDK provides 10 functions to help you get the data you need from the SBServer object:

const char *SBServerGetStringValue(SBServer server, char *keyname, char *def);
int SBServerGetIntValue(SBServer server, char *key, int idefault);
double SBServerGetFloatValue(SBServer server, char *key, double fdefault);
SBBool SBServerGetBoolValue(SBServer server, char *key, SBBool bdefault);

The first four functions are used to access the values for server key information. Simply use the key name you registered to access the value for that key on a server. Note that only the basic keys you requested in ServerBrowserUpdate are available after the initial update. See the next step for information on getting the rest of the keys\values from the server.

const char *SBServerGetPlayerStringValue(SBServer server, int playernum, char *key, char *sdefault);
int SBServerGetPlayerIntValue(SBServer server, int playernum, char *key, int idefault);
double SBServerGetPlayerFloatValue(SBServer server, int playernum, char *key, double fdefault);

The second set of functions returns a specific player key. You can get the same result by asking for a server key in the form keyname_N where N is the player number you are interested in. The SBServerGetPlayer functions just provide a shortcut to this. To get the ping for player 0, you would ask for SBServerGetPlayerIntValue(server, 0, "ping", 0).

const char *SBServerGetTeamStringValue(SBServer server, int teamnum, char *key, char *sdefault);
int SBServerGetTeamIntValue(SBServer server, int teamnum, char *key, int idefault);
double SBServerGetTeamFloatValue(SBServer server, int teamnum, char *key, double fdefault);

The final set of functions is similar to the player key lookups, except for team keys. Team keys are reported in the form keyname_tN where N is the team index. To get the score for team 0 (score_t0, you would ask for: SBServerGetTeamIntValue(server, 0, "score", 0).

The sdefault, idefault and fdefault parameters will be used if the server doesn't include the specific key you requested.

Team and player keys are only available for servers with a full set of keys. You can determine whether a particular server in your list has basic or full keys with the SBServerHasBasicKeys / SBServerHasFullKeys functions.

This step should look something like:

//insert a server onto the list
CServerView::Insert(GServer server)
{
	AddItem(SBServerGetStringValue(server, "hostname","(NONE)"),
	SBServerGetPing(server),
	SBServerGetIntValue(server,"numplayers",0), 
	SBServerGetIntValue(server,"maxplayers",0),
	SBServerGetStringValue(server,"mapname","(NO MAP)") 
	SBServerGetStringValue(server,"gametype",""));
}

Step 5: Obtaining Additional Server Information

After your initial server browser update, the servers will only have the "basic" keys available for them. Most in-game server browsers are built so that when you click on a server, you can get additional information about it - such as the full rules for the game, the list players currently in the game, and the team information. To obtain this additional information when someone selects a server, you will need to perform what is known as an "Auxiliary" update of the server. To accomplish this, call:
SBError ServerBrowserAuxUpdateServer(ServerBrowser sb, SBServer server, SBBool async, SBBool fullUpdate);
server
The server you want to get updated information for.
async
Determines whether the function returns immediately, or waits for the update to complete. Note that if you perform the AuxUpdate asynchronously, you must call the ServerBrowserThink function to perform processing.
fullUpdate
Determines whether basic or full keys are retrieved from the server. Generally you will want to pass SBTrue to retrieve all the available keys\values from the server.

You should check to see if the server already has full keys available with SBServerHasFullKeys to avoid updating the server if not needed. Multiple aux updates can be queued at a time if you want to get full keys for a range of servers.

If the server being updated is behind a NAT, and does not support direct-UDP queries (only for games that use the NAT Negotiation SDK), then the full server information is obtained from the master server, instead of the game server directly. This requires a connection to the master server. If you set the disconnectOnComplete option when updating, a connection will be re-established to the master to obtain the information.

You can also use the ServerBrowserAuxUpdateIP function to "add" a server to the list that was not already present. Instead of providing an SBServer object, you will provide the IP and query port of the server. You can use this to allow players to manually add servers to the list, or to store a list of favorites locally and add them to the list directly.

Step 6: Sorting and Other Features

You will probably want to give players the ability to sort the server list on a specific column (for example, the server name to find a specific server, by ping to find the best server, or by players to find the most crowded). If your list control supports sorting, you can do it that way, or, you can resort the actual ServerBrowser object and repopulate your display with the sorted data. Unlike the previous CEngine SDK, list storage is decoupled from updating, so you can use the sorting functions to resort the list while it is being updated (although resorting after every server update arrives may lead to poor performance on large lists).

To resort the internal list, use the ServerBrowserSort function:

void ServerBrowserSort(ServerBrowser sb, SBBool ascending, char *sortkey,SBCompareMode comparemode); 

You should pass in whether you want the list to be sorted in ascending or descending order, what key it should be sorted on (e.g. "ping" or "hostname" or "numplayers") and the value type for that key (e.g. sbcm_int for integer comparison, sbcm_stricase for case-insensitive string comparison).

To sort the list ascending by ping you would call:

ServerBrowserSort(sb, SBTrue, "ping", sbcm_int);

Once you have resorted the list, you will need to clear your display and repopulate it with the sorted list. This is typically done with a FOR loop from 0 to ServerBrowserCount(...)-1 in which you call ServerBrowserGetServer to get each server in the list.

In order to display the progress of the server list update, you can use the ServerBrowserPendingQueryCount to determine the number of servers waiting to be queried. By comparing this to the number of servers on the list, you can determine a completion percentage.

The ServerBrowserHalt function can be used to stop an update in progress, if the user wants to abort the update.

The ServerBrowserState can be used to determine the current state of the Server Browser. Descriptions of the possible state values can be find in the main header file.

Step 7: Free the Server Browser When Done

When you are completely done with the server browser, call the ServerBrowserFree function to free the memory allocated by the list. The Server Browser object is invalid after this call, so do not use it again without calling ServerBrowserNew.

UNICODE Support

The GameSpy SDKs support an optional UNICODE interface for widestring applications. To use this interface, first define the symbol GSI_UNICODE. Then, use widestrings wherever ANSI strings were previously called for. When in doubt, please refer to the header files for specific function declarations.

Although the GameSpy SDK interfaces support UNICODE parameters, some items may be stripped of their extra UNICODE information. These items include: nickname, email address, and URL strings. You may pass in widestring values, but they will first be converted to their ANSI counterparts before transmission.

Appendix: Changes From The CEngine SDK

The Server Browsing SDK replaces the CEngine SDK, and provides a number of changes an enhancements. Migration from the CEngine SDK is fairly straight-forward and can provide a number of benefits.

The changes and improvements in the SDK are listed below to help you with migration:

  • Defaults to a multi-step update process, where only basic keys are obtained from servers initially, and full keys are obtained on-request. This results in a significant bandwidth reduction for both clients and servers (on the order of 5-10X) and leads to faster refreshes with less overhead.
  • Supports the new QR2 querying protocol, which allows for querying of individual keys and optimized encoding of key data (key names are no longer sent if not required).
  • Allows server information to be obtained from the master server for games hosted behind a NAT/Firewall.
  • Supports the new NAT Negotiation SDK for hosting and connecting-to games behind a NAT or Firewall
  • Allows for filtering by any server key, instead of the fixed list of keys available for filtering in the CEngine SDK
  • Allows for filtering of servers by country and region, without requiring server administrators to report that information.
  • Allows for sorting of the server list while updates are still in progress.
  • Faster socket code that uses a single UDP socket for all queries, instead of requiring 1 socket for each simultaneous query.
  • Server lists from the master server use a new format that is compressed even more than before.

Appendix: Region Codes and Usage

The updated Master Server backend that supports the Server Browsing SDK has the ability to identify the country a server is located in based on its IP address, and based on that country, sort it into a specific region. Master regions are make up of smaller regions. You can use filtering to restrict the list of servers returned to a specific country or region, thus giving players a list that better represents their play-able servers.

Regions are identified by a region ID number, however a particular server can be listed in multiple regions since regions are "nested". Because of this, the region number for a server is actually the sum of all the regions the server is in. To filter on a specific region, you should use the bitwise-AND operator to identify servers that are listed in that region.

For example, to identify servers in North America, you would use the filter: (region & 2) = 2 , since 2 is the region code for North America. Normal bitwise math can be used to check for multiple regions. For example, to check for North America or Caribbean, you can add them together: (region & 6) != 0

regionid    regionname     
----------- ----------------
1           Americas
2           North America
4           Caribbean
8           Central America
16          South America

32          Africa
64          Central Africa
128         East Africa
256         Northern Africa
512         Southern Africa
1024        West Africa

2048        Asia
4096        East Asia
8192        Pacific
16384       South Asia
32768       South-East Asia

65536       Europe
131072      Baltic States
262144      Commonwealth of Independent States
524288      Eastern Europe
1048576     Middle East
2097152     South-East Europe
4194304     Western Europe
ccode country                        regionname                                                                                                                                                                                                                                                      
----- ------------------------------ ------------
BI    Burundi                        Central Africa
CM    Cameroon                       Central Africa
CF    Central African Republic       Central Africa
TD    Chad                           Central Africa
CG    Congo                          Central Africa
GQ    Equatorial Guinea              Central Africa
RW    Rwanda                         Central Africa
DJ    Djibouti                       East Africa
ER    Eritrea                        East Africa
ET    Ethiopia                       East Africa
KE    Kenya                          East Africa
SC    Seychelles                     East Africa
SO    Somalia                        East Africa
SH    St. Helena                     East Africa
SD    Sudan                          East Africa
TZ    Tanzania                       East Africa
UG    Uganda                         East Africa
DZ    Algeria                        Northern Africa
EG    Egypt                          Northern Africa
LY    Libya                          Northern Africa
MA    Morocco                        Northern Africa
TN    Tunisia                        Northern Africa
AO    Angola                         Southern Africa
BW    Botswana                       Southern Africa
BV    Bouvet Island                  Southern Africa
KM    Comoros                        Southern Africa
HM    Heard and McDonald Islands     Southern Africa
LS    Lesotho                        Southern Africa
MG    Madagascar                     Southern Africa
MW    Malawi                         Southern Africa
MU    Mauritius                      Southern Africa
YT    Mayotte                        Southern Africa
MZ    Mozambique                     Southern Africa
NA    Namibia                        Southern Africa
RE    Reunion                        Southern Africa
ZA    South Africa                   Southern Africa
SZ    Swaziland                      Southern Africa
ZM    Zambia                         Southern Africa
ZW    Zimbabwe                       Southern Africa
BJ    Benin                          West Africa
BF    Burkina Faso                   West Africa
CV    Cape Verde                     West Africa
CI    Cote D`ivoire                  West Africa
GA    Gabon                          West Africa
GM    Gambia                         West Africa
GH    Ghana                          West Africa
GN    Guinea                         West Africa
GW    Guinea-Bissau                  West Africa
LR    Liberia                        West Africa
ML    Mali                           West Africa
MR    Mauritania                     West Africa
NE    Niger                          West Africa
NG    Nigeria                        West Africa
ST    Sao Tome and Principe          West Africa
SN    Senegal                        West Africa
SL    Sierra Leone                   West Africa
TG    Togo                           West Africa
AI    Anguilla                       Caribbean
AG    Antigua and Barbuda            Caribbean
AW    Aruba                          Caribbean
BS    Bahamas                        Caribbean
BB    Barbados                       Caribbean
BM    Bermuda                        Caribbean
KY    Cayman Islands                 Caribbean
CU    Cuba                           Caribbean
DM    Dominica                       Caribbean
DO    Dominican Republic             Caribbean
GD    Grenada                        Caribbean
GP    Guadeloupe                     Caribbean
HT    Haiti                          Caribbean
JM    Jamaica                        Caribbean
MQ    Martinique                     Caribbean
MS    Montserrat                     Caribbean
AN    Netherlands Antilles           Caribbean
PR    Puerto Rico                    Caribbean
VC    Saint Vincent and The Grenadin Caribbean
KN    St Kitts-Nevis                 Caribbean
LC    St Lucia                       Caribbean
TT    Trinidad & Tobago              Caribbean
TC    Turks & Caicos Islands         Caribbean
VG    Virgin Islands (British)       Caribbean
VI    Virgin Islands (US)            Caribbean
BZ    Belize                         Central America
CR    Costa Rica                     Central America
SV    El Salvador                    Central America
GT    Guatemala                      Central America
HN    Honduras                       Central America
MX    Mexico                         Central America
NI    Nicaragua                      Central America
PA    Panama                         Central America
CA    Canada                         North America
GL    Greenland                      North America
PM    St. Pierre and Miquelon        North America
US    United States                  North America
UM    US Minor Outlying Islands      North America
AR    Argentina                      South America
BO    Bolivia                        South America
BR    Brazil                         South America
CL    Chile                          South America
CO    Colombia                       South America
EC    Ecuador                        South America
FK    Falkland Islands (Malvinas)    South America
GF    French Guiana                  South America
GY    Guyana                         South America
PY    Paraguay                       South America
PE    Peru                           South America
GS    S. Georgia and S. Sandwich Isl South America
SR    Suriname                       South America
UY    Uruguay                        South America
VE    Venezuela                      South America
CN    China                          East Asia
HK    Hong Kong                      East Asia
JP    Japan                          East Asia
MO    Macao                          East Asia
MN    Mongolia                       East Asia
KP    North Korea                    East Asia
KR    South Korea                    East Asia
TW    Taiwan                         East Asia
AS    American Samoa                 Pacific
AU    Australia                      Pacific
CK    Cook Islands                   Pacific
FJ    Fiji                           Pacific
PF    French Polynesia               Pacific
GU    Guam                           Pacific
KI    Kiribati                       Pacific
MH    Marshall Islands               Pacific
FM    Micronesia                     Pacific
NR    Nauru                          Pacific
NC    New Caledonia                  Pacific
NZ    New Zealand                    Pacific
NU    Niue                           Pacific
NF    Norfolk Island                 Pacific
MP    Northern Mariana Islands       Pacific
PG    Papua New Guinea               Pacific
PN    Pitcairn Islands               Pacific
EH    Samoa                          Pacific
SB    Solomon Islands                Pacific
TO    Tonga                          Pacific
TK    Tonga                          Pacific
TV    Tuvalu                         Pacific
VU    Vanuatu                        Pacific
WF    Wallis and Futuna Islands      Pacific
AF    Afghanistan                    South Asia
BD    Bangladesh                     South Asia
BT    Bhutan                         South Asia
IO    British Indian Ocean Territory South Asia
IN    India                          South Asia
MV    Maldives                       South Asia
NP    Nepal                          South Asia
PK    Pakistan                       South Asia
LK    Sri Lanka                      South Asia
BN    Brunei Darussalam              South-East Asia
KH    Cambodia                       South-East Asia
CX    Christmas Island               South-East Asia
CC    Cocos (Keeling Islands)        South-East Asia
TP    East Timor                     South-East Asia
ID    Indonesia                      South-East Asia
LA    Laos                           South-East Asia
MY    Malaysia                       South-East Asia
MM    Myanmar                        South-East Asia
PW    Palau                          South-East Asia
PH    Philippines                    South-East Asia
SG    Singapore                      South-East Asia
TH    Thailand                       South-East Asia
VN    Vietnam                        South-East Asia
EE    Estonia                        Baltic States
LV    Latvia                         Baltic States
LT    Lithuania                      Baltic States
AM    Armenia                        CIS
AZ    Azerbaijan                     CIS
BY    Belarus                        CIS
GE    Georgia                        CIS
KZ    Kazakstan                      CIS
KG    Kyrgyzstan                     CIS
MD    Moldova                        CIS
RU    Russian Federation             CIS
TJ    Tajikistan                     CIS
TM    Turkmenistan                   CIS
UA    Ukraine                        CIS
UZ    Uzbekistan                     CIS
CZ    Czech Republic                 Eastern Europe
HU    Hungary                        Eastern Europe
PL    Poland                         Eastern Europe
RO    Romania                        Eastern Europe
SK    Slovak Republic                Eastern Europe
BH    Bahrain                        Middle East
IR    Iran                           Middle East
IQ    Iraq                           Middle East
IL    Israel/Occupied Territories    Middle East
JO    Jordan                         Middle East
KW    Kuwait                         Middle East
LB    Lebanon                        Middle East
OM    Oman                           Middle East
QA    Qatar                          Middle East
SA    Saudi Arabia                   Middle East
SY    Syria                          Middle East
AE    United Arab Emirates           Middle East
YE    Yemen                          Middle East
AL    Albania                        South-East Europe
BA    Bosnia-Herzegovina             South-East Europe
BG    Bulgaria                       South-East Europe
HR    Croatia                        South-East Europe
CY    Cyprus                         South-East Europe
GR    Greece                         South-East Europe
MK    Macedonia                      South-East Europe
MT    Malta                          South-East Europe
SI    Slovenia                       South-East Europe
TR    Turkey                         South-East Europe
YU    Yugoslavia                     South-East Europe
AD    Andorra                        Western Europe
AT    Austria                        Western Europe
BE    Belgium                        Western Europe
DK    Denmark                        Western Europe
FO    Faroe Islands                  Western Europe
FI    Finland                        Western Europe
FR    France                         Western Europe
DE    Germany                        Western Europe
GI    Gibraltar                      Western Europe
IS    Iceland                        Western Europe
IE    Ireland                        Western Europe
IT    Italy                          Western Europe
LI    Liechtenstein                  Western Europe
LU    Luxembourg                     Western Europe
MC    Monaco                         Western Europe
NL    Netherlands                    Western Europe
NO    Norway                         Western Europe
PT    Portugal                       Western Europe
SM    San Marino                     Western Europe
ES    Spain                          Western Europe
SJ    Svalbard and Jan Mayen Islands Western Europe
SE    Sweden                         Western Europe
CH    Switzerland                    Western Europe
UK    United Kingdom                 Western Europe
VA    Vatican                        Western Europe