(function($) {
    $.fn.usermetrics = function(options) {
        var el=this, o = $.extend(true, {}, defaults, options );

        /*
        main function for account summary. given the timeFrame (past_hour, past_week, 
        past_month) return summary data on clicks, referrers, location
       */

        bind_events();
        load_data(7);
        
        return this;

        function load_data(days) {
            if (days === 1) {
                connector(o.clicks_hourly_endpoint, {}, get_clicks_callback, error);
                connector(o.countries_hourly_endpoint, {}, get_metrics_country_callback, error);
                connector(o.referrers_hourly_endpoint, {}, get_referrers_callback, error);
            } else {
                connector(o.clicks_endpoint, {'days' : days}, get_clicks_callback, error);
                connector(o.countries_endpoint, {'days' : days}, get_metrics_country_callback, error);
                connector(o.referrers_endpoint, {'days' : days}, get_referrers_callback, error);
            }
            toggleTimeFrameButtonClasses(o.timeframe_lookup[days]);
        }
        
        function bind_events(){
            $('#time_frame_PAST_HOUR').bind('click', function(){load_data(1)});
            $('#time_frame_PAST_WEEK').bind('click', function(){load_data(7)});
            $('#time_frame_PAST_MONTH').bind('click', function(){load_data(30)});
        }
        
        function error(e) {
            var errorText = o.api_error_text;
            // we don't want to do this; need to do something better
            $("#user_metrics_referrer_stats").html("<div class='user_metrics_error'>"+errorText+ "</div>");
        }

        function get_referrers_callback(jo) {
            if(!jo || !jo.data || jo.status_code !== 200) {
                error(o.api_error_text);
                return
            }
            var data = jo.data;
            if (data.referrers && data.referrers.length > 0){
                var val_function = function(a) { return a['clicks']; };
                var label_function = function(a) { return getReferrerDomainAndPath(a['referrer'])['domain']; };
                var points = groupTailDataPointsByDomain(data.referrers, val_function, label_function);
                
                var num_referring_domains = points.length;
                val_function = function(a) { return a['data']; };
                label_function = function(a) { return a["label"]; };
                points = groupTailDataPointsIntoOther(points, 6, val_function, label_function);
                $.plot($("#user_metrics_flot_referrer"), points, {
                    series: {
                        pie: { 
                            // gradient: {show:true, colors:["#aaaaaa"]},
                            show: true, showLabel: true, radius: 1, stroke: { width:0 },
                            label: {
                                show: true, radius: 3/4,
                                formatter: function(label, series){
                                    var p = Math.round(series.percent);
                                    if (p > 15) {
                                        return "<div style='font-size:8pt;text-align:center;padding:2px;color:#000;'>" +$.escapeHTML(label)+'<br/>'+p+'%' + "</div>";
                                    } else {
                                        return '';
                                    }
                                }
                            }
                        }
                    },
                    colors: ["#84ba5b", "#afd8f8", "#e1974c", "#7293cb", "#d35e60", "#959799", "#ccc274", "#8965a6"],
                    grid: {hoverable: true, clickable: true},
                    legend: { show: false }
                });
                var ref_text = " Referring Domains";
                if (num_referring_domains == 1) {
                    ref_text = " Referring Domain";
                }
                ref_text = commifyNumber(num_referring_domains) + ref_text;
                var urls_text = " Total Pages";
                if (num_distinct_ref_urls == 1) {
                    urls_text = " Total Page";
                }
                urls_text = "From " + commifyNumber(num_distinct_ref_urls) + urls_text;
                $("#user_metrics_referrer_stats").html("<h3><a href='#referrer_report_detail'>"+ref_text+"</a></h3><p>"+urls_text+"</p>");
                var preproceessed_data = preProcessReferrerData(data.referrers);
                drawReferrersTable('ALL_HASHES', preproceessed_data, 50);
                $("#user_metrics_flot_referrer").bind("plotclick", function (event, pos, item) {
                    document.location.href = "#referrer_report_detail";
                });
            } else {
                var error = "You do not have any click data. Share some of your Bit.ly links with your friends.";
                $("#user_metrics_referrer_stats").html("<div class='user_metrics_error'>"+error+ "</div>"); //+ t_settings.series_label
                $("#referrer_report_detail_h1").css('display', 'none');
                $("#tooltip").remove();
                $("#user_metrics_flot_referrer").html('');
                drawReferrersTable('ALL_HASHES', [], 50);
            }
        };

        function get_clicks_callback(jo) {
            if(!jo || !jo.data || jo.status_code !== 200) {
                error(o.api_error_text);
                return
            }
            var data = jo.data;
            if (data.clicks && data.clicks.length > 0){
                var time_frame_settings = {
                    "PAST_WEEK": { "series_label": "This Week", "bar_width": 1000*60*60*20 },
                    "PAST_MONTH": { "series_label": "This Month", "bar_width": 1000*60*60*15 },
                //    "PAST_DAY": { "series_label": "Today", "bar_width": 1000*60*60*20 },
                    "PAST_HOUR": { "series_label": "Past Hour", "bar_width": 1000*60*.5, "timeformat": "%h:%M:%P" }
                };
                var timeframe = o.timeframe_lookup[data.days];
                var t_settings = time_frame_settings[timeframe], points = [], total_clicks = 0;
                for (var i=0; i < data.clicks.length; i++) {
                    var r = data.clicks[i];
                    points.push([r.ts * 1000, r.clicks]);
                };
                var series = {"data": points, "label": t_settings.series_label, "hoverable": true};
                var tickFormatter = null;
                if (data.days === 1 ) {
                    tickFormatter = function(v, axis) {
                        // format times in local time on the browser
                        var d = new Date(v);
                        var leftPad = function(n) {
                            n = "" + n;
                            return n.length == 1 ? "0" + n : n;
                        };
                        var hours = d.getHours();
                        var isAM = hours < 12;
                        if (hours > 12) {
                            hours = hours - 12;
                        } else if (hours == 0) {
                            hours = 12;
                        }
                        var c = "" + hours + ":" + leftPad(d.getMinutes())
                        c += (isAM) ? ("" + "AM") : ("" + "PM");
                        return c
                    };
                }
                var user_metrics_flot_clicks = $.plot($("#user_metrics_flot_clicks"), [series], {
                    colors: ["#77C8FC"],
                    xaxis: { mode: "time", timeformat: ( t_settings['timeformat'] || "%b %d" ), 'tickFormatter' : tickFormatter },
                    yaxis: { autoscaleMargin: 0.03, min: 0, tickDecimals:0 },
                    bars: { show: true, barWidth: t_settings.bar_width, fill: true, fillColor: "#77C8FC", align: "center" },
                    legend: { show: false, position: "ne", backgroundOpacity: 0, margin: 0 },
                    grid: {hoverable: true, clickable: true, borderWidth:0, tickColor:"#fff" }
                });
                previousPoint = null;
                $("#user_metrics_flot_clicks").bind("plothover", function (event, pos, item) {
                    $("#x").text(pos.x.toFixed(2));
                    $("#y").text(pos.y.toFixed(2));
                    if (item) {
                        if (previousPoint != item.datapoint) {
                            previousPoint = item.datapoint;
                            $("#tooltip").remove();
                            var x = item.datapoint[0], y = item.datapoint[1];
                            var fdate = $.plot.formatDate(new Date(x), user_metrics_flot_clicks.getOptions().xaxis.timeformat);
                            showTooltip(item.pageX, item.pageY, fdate + ": " + y + " clicks");
                        }
                    } else {
                        $("#tooltip").remove();
                        previousPoint = null;      
                    }
                });
                var clicks_text = " Clicks";
                if (data.total_clicks == 1) {
                    clicks_text = " Click";
                }
                clicks_text = commifyNumber(data.total_clicks || 0) + clicks_text;
                $("#user_metrics_clicks_stats").html("<h3>"+clicks_text+" on Your Bit.ly Links " + "</h3>"); //+ t_settings.series_label
            } else {
                if (!data.error) {
                    data.error = "You do not have any click data. Share some of your Bit.ly links with your friends.";
                }
                var error = data.error || "There was an error fetching data.";
                $("#user_metrics_clicks_stats").html("<div class='user_metrics_clicks_error'>"+error+ "</div>"); //+ t_settings.series_label
                $("#tooltip").remove();
                $("#user_metrics_flot_clicks").html('');
            }
        };

        function get_metrics_country_callback(jo) {
            if(!jo || !jo.data || jo.status_code !== 200) {
                error(o.api_error_text);
                return
            }
            var data = jo.data;
            if (data.countries && data.countries.length > 0){
                var val_function = function(a) { return a['clicks']; };
                var label_function = function(a) { return getCountryName(a['country']); };
                var points = groupTailDataPointsIntoOther(data.countries, 8, val_function, label_function);
                var num_countries = data.countries.length;
    
               var user_metrics_flot_country = $.plot($("#user_metrics_flot_country"),
                    points, {
                        colors: ["#84ba5b", "#afd8f8", "#e1974c", "#7293cb", "#d35e60", "#959799", "#ccc274", "#8965a6"],
                        grid: {hoverable: true, clickable: true},
                        series: {
                            pie: { 
                              show: true, 
                              showLabel: true,
                              radius: 1,
                              stroke: { width:0 }, 
                              label: {
                                show: true,
                                radius: 1/2,
                                formatter: function(label, series){
                                    var p = Math.round(series.percent);
                                    if (p > 15) {
                                        return "<div style='font-size:8pt;text-align:center;padding:2px;color:#000;'>" + $.escapeHTML(label)+'<br/>'+p+'%' + "</div>";
                                    } else {
                                        return '';
                                    }
                                }
                            }
                        }
                    },
                    legend: { show: false}
                });  

                // http://code.google.com/p/flot/issues/detail?id=5
                previousPoint = null;

                var countries_text = " Countries";
                if (num_countries == 1) {
                    countries_text = " Country";
                }
                countries_text = commifyNumber(num_countries) + countries_text;
                $("#user_metrics_country_stats").html("<h3><a href='#country_report_detail'>"+countries_text+"</a></h3>");

                var row_type = "row_odd";
                var html = "<table cellspacing='0' cellpadding='0' class='statistics'><tbody><tr style='font-weight:bold;' class='"+row_type+"'><td>Country</td><td class='clicks_l'>Click(s)</td></tr>";
                for (var i=0; i < data.countries.length; i++) {
                    row_type = (row_type == 'row_odd') ? 'row_even' : 'row_odd';
                    var c = data.countries[i];
                    html += "<tr class='"+row_type+"'>";
                    html += "<td>"+getCountryName(c.country)+"</td>";
                    html += "<td class='clicks_l'>"+commifyNumber(c.clicks)+"</td>";
                    html += "</tr>";
                };

                html += "</tbody></table>";
                $("#user_metrics_country_text").html(html);

                $("#user_metrics_flot_country").bind("plotclick", function (event, pos, item) {
                    document.location.href = "#country_report_detail";
                });
            } else {
                var error = "You do not have any click data. Share some of your Bit.ly links with your friends.";
                $("#user_metrics_country_stats").html("<div class='user_metrics_error'>"+error+ "</div>"); //+ t_settings.series_label
                $("#country_report_detail_h1").css('display', 'none');
                $("#tooltip").remove();
                $("#user_metrics_flot_country").html('');
                $("#user_metrics_country_text").html('');
            }
        }

        function showTooltip(x, y, contents) {
            $('<div id="tooltip">' + contents + '</div>').css({position: 'absolute', display: 'none', top: y - 25, left: x + 5, border: '1px solid #fdd', padding: '2px', 'background-color': '#fee', opacity: 0.80}).appendTo("body").fadeIn(100);
        }
        
        function groupTailDataPointsByDomain(data_points, val_function, label_function) {
            var clicks_by_domain = {};
            var distinct_urls = {};
            var new_data_points = [];
            for (var i=0; i < data_points.length; i++) {
                var l = label_function(data_points[i]);
                var v = val_function(data_points[i]);
                if (clicks_by_domain[l] == null) {
                    clicks_by_domain[l] = 0;
                }
                clicks_by_domain[l] += v;
                try {
                    var url = data_points[i].referrer;
                    distinct_urls[url] = true;
                } catch(e){};
            };
            for (var domain in clicks_by_domain) {
                new_data_points.push({"label": domain, "data": clicks_by_domain[domain]});
            };
            num_distinct_ref_urls = 0;
            for (var url in distinct_urls) {
                num_distinct_ref_urls += 1;
            };
            return new_data_points;
        };

        function groupTailDataPointsByUrl(data_points, val_function, label_function) {
            var clicks_by_url = {};
            var new_data_points = [];
            for (var i=0; i < data_points.length; i++) {
                var l = label_function(data_points[i]);
                var v = val_function(data_points[i]);
                if (clicks_by_url[l] == null) {
                    clicks_by_url[l] = 0;
                }
                clicks_by_url[l] += v;
            };
            for (url in clicks_by_url) {
                new_data_points.push({"label": url, "data": clicks_by_url[url]});
            }
            return new_data_points;
        };

        function groupTailDataPointsIntoOther(data_points, num_points_besides_other, val_function, label_function) {
            var sort_function = function(a,b){
                return val_function(b) - val_function(a); 
            };
            data_points = data_points.sort(sort_function);
            var new_data_points = [];
            var sum_other = 0;
            for (var i=0; i < data_points.length; i++) {
                var l = label_function(data_points[i]);
                if (l.toString().match(/other|none|null/i)) {
                    sum_other += val_function(data_points[i]);
                    num_points_besides_other += 1;
                } else if (i <= num_points_besides_other) {
                    new_data_points.push({"label": label_function(data_points[i]), "data": val_function(data_points[i])});
                } else {
                    sum_other += val_function(data_points[i]);
                }
            };
            if (sum_other > 0) {
                new_data_points.push({"label": "Other", "data": sum_other});
            }
            return new_data_points;
        }

        function domainIsDirect(domain) {
            return (domain == '' || domain.match(/direct/i) || domain == 'None');
        };

        function getReferrerDomainAndPath(url) {
            var path = '/';
            var url = unescape(url);
            var m = url.match(/^https{0,1}\:\/\/([^\/]+)(.*)$/i);
            if (m && m[1]) {
                var domain = m[1];
                if (m[2]) {
                    path = m[2];
                }
            } else {
                var domain = url; // if we got here, we couldn't match domain and we need to improve regexp.
            }
            if (domainIsDirect(domain)) {
                domain = 'Direct';
            }
            if (isPartnerDomain(domain)) {
                domain = getPartnerInfo(path);
                if (domain) {
                    domain = domain.display_name || 'Other Partner';
                }
                path = domain;
            }
            return {"domain": domain, "path": path};
        };

        function toggleTimeFrameButtonClasses(time_frame) {
            for (var i=0; i < o.time_frames.length; i++) {
                var tf = o.time_frames[i];
                if (tf == time_frame) {
                    $("#time_frame_" + tf).addClass('selected');
                } else {
                    $("#time_frame_" + tf).removeClass('selected');
                }
            }
        }

        function preProcessReferrerData(ref_data) {
            var domains = {};
            for (var i=0; i < ref_data.length; i++) {
                var encoded_url = ref_data[i].referrer;
                var clicks = ref_data[i].clicks;
                var path = '/';
                var url = unescape(encoded_url);
                var m = url.match(/^https{0,1}\:\/\/([^\/]+)(.*)$/i);
                if (m && m[1]) {
                    var domain = m[1];
                    if (m[2]) {
                        path = m[2];
                    }
                } else {
                    var domain = url; // if we got here, we couldn't match domain and we need to improve regexp.
                }
                if (domainIsDirect(domain)) {
                    domain = 'direct';
                }
                if (domains[domain] == null) {
                    domains[domain] = {'total': 0, 'paths': {}};
                }
                domains[domain]['total'] += clicks;
                if (!domains[domain]['paths'][path]) {
                    domains[domain]['paths'][path] = 0;
                }
                domains[domain]['paths'][path] += clicks;
            };
            return sortReferrersData(domains);
        };

        function getCountryName(countryCode) {
            if (ISO_COUNTRIES[countryCode] == undefined) {
                return 'Other'
            }
            return ISO_COUNTRIES[countryCode]
        }

        function pagePath() {
            var loc = document.location.toString();
            if (loc) {
                var m = loc.match(/https?\:\/\/[^\/]+(\/[^\?]*)/i);
                if (m) {
                    return m[1];
                }
            }
            return '';
        };

        function urlToId(_url) {
            var m = _url.toString().match(/\/([^\/]*)$/);
            return m[1];
        };
        
        function commifyNumber(number, abbreviate) {
            if (typeof(number) == 'undefined') { return '';}
            if (typeof(abbreviate) == 'undefined') { var abbreviate = true; };
            if (abbreviate) {
                var round = function(number, places) {
                    var p = 10;
                    for (var i = 1; i < places; i++) {
                        p = 10 * p;
                    }
                    return Math.round(number*p) / p;
                };
                var num = parseInt(number,10);
                var k = 1000;
                var m = 1000*1000;
                var b = 1000*m;
                var t = 1000*b;
                if (num > t) {
                    num = round(num / t, 1);
                    return num + "T";
                } else if (num > b) {
                    num = round(num / b, 1);
                    return num + "B";
                } else if (num > m) {
                    num = round(num / m, 1);
                    return num + "M";
                }
            }
            var numberOrig = new String(number);
            var numberArr = new String(number).split('.');
            number = numberArr[0];
            number = '' + number;
            if (number.length > 3) {
                var mod = number.length % 3;
                var output = (mod > 0 ? (number.substring(0,mod)) : '');
                for (i=0 ; i < Math.floor(number.length / 3); i++) {
                    if ((mod == 0) && (i == 0)) {
                        output += number.substring(mod+ 3 * i, mod + 3 * i + 3);
                    } else {
                        output+= ',' + number.substring(mod + 3 * i, mod + 3 * i + 3);
                    }
                }
            } else {
                output=number;
            }
            if(numberOrig.match('.') && numberArr[1]) {
                output = output + '.' + numberArr[1];
            }
            return output;
        };

        function sortReferrersData(preprocessed_data) {
            var arr = [];
            var direct = null;
            for (var domain in preprocessed_data) {
                var hsh = preprocessed_data[domain];
                hsh['domain'] = domain;
                arr.push(hsh);
            }
            var sorted = arr.sort(function(a,b){
                return b['total'] - a['total']; 
            });
            return sorted;
        }

        function drawReferrersError() {
            $("#traffic_sources").html("<p>There is no referrer data for this time period.</p>");
        }

        function drawReferrersTable(clicks_type, preproceessed_data, max_referrers) {
            var data = preproceessed_data;
            if (preproceessed_data.length == 0) {
                drawReferrersError();
                return false;
            }
            var _id = (clicks_type == 'GLOBAL_HASH') ? 'global' : 'local';
            var html = '';
            html += '<table cellspacing="0" cellpadding="0" class="statistics" id="'+_id+'_statistics">';
            html += '<thead>';
            html += '<tr>';
            html += '<th class="url">Referring Site</th>';
            html += '<th class="clicks_l">Click(s)</th>';
            html += '</tr>';
            html += '</thead>';
            var row_type = "row_odd";
            var total = 0;
            for (var j=0; j < max_referrers && j < preproceessed_data.length; j++) {
                var domain = preproceessed_data[j]['domain'];
                var domain_total = preproceessed_data[j]['total'];
                var paths = preproceessed_data[j]['paths'];
                var is_partner = null;
                if (domainIsDirect(domain)) {
                    var direct = true;
                    var domain_display = "Email Clients, IM, AIR Apps, and Direct";
                    var fav_image = '';
                } else if (is_partner = isPartnerDomain(domain)) {
                    var direct = false;
                    var domain_display = "Registered Applications";
                    var fav_image = '';
                } else {
                    // encode the domain for entry onto the page
                    var domain_display = $.escapeHTML(domain) ;
                    var direct = false;
                    var fav_image = '<img width="16" height="16" src="http://'+domain+'/favicon.ico" r="'+domain+'" class="fav" />';
                }
                row_id = '10' +j;
                total += domain_total;
                html += '<tr class="row '+row_type+'" id="r_r_'+row_id+'">';
                html += '<td class="url">';
                html += domain_display+' <img src="/static/images/open_button.png" class="r_open" id="r_a_1011"/>'; // fav_image+
                html += '</td>';
                html += '<td class="clicks_l"><span id="r_cl_'+row_id+'">'+commifyNumber(domain_total)+'</span></td>';
                html += '</tr>';
                html += '<tbody class="'+row_type+' sub" id="r_s_'+row_id+'" style="display: none">';
                if (direct) {
                    html += '<tr>';
                    html += '<td class="url">Direct Traffic includes people clicking a bit.ly link from: <br />- Desktop email clients like Microsoft Outlook or Apple Mail<br />- AIR applications like Twhirl<br />- Mobile apps like Twitterific or BlackBerry Mail<br />- Chat apps like AIM<br />- SMS/MMS messages<br />It also includes people who typed a bit.ly link directly into their browser</td>';
                    html += '<td class="clicks_l">&nbsp;</td>';
                    html += '</tr>';
                } else if (is_partner) {
                    for (var path in paths) {
                        var partner_info = null;
                        if (partner_info = getPartnerInfo(path)) {
                            var partner_display = '<a target="_blank" href="'+ partner_info.url + '">' + partner_info.display_name + '</a>';
                        } else {
                            var partner_display = 'Other Partner';
                        }
                        
                        html += '<tr>';
                        html += '<td class="url">'+partner_display+'</td>';
                        html += '<td class="clicks_l">'+commifyNumber(paths[path])+'</td>';
                        html += '</tr>';
                    }
                } else {
                    for (var path in paths) {
                        html += '<tr>';
                        html += '<td class="url">'+$.escapeHTML(path)+'</td>';
                        html += '<td class="clicks_l">'+commifyNumber(paths[path])+'</td>';
                        html += '</tr>';
                    }
                }
                html += '</tbody>   ';
                row_type = (row_type == 'row_odd') ? 'row_even' : 'row_odd';
            }
            html += '</table>';
            $("#traffic_sources").html(html);
            $('#global_statistics .row').click(stattoggle);
            $('#local_statistics .row').click(stattoggle);
        }

        function isPartnerDomain(domain) {
            return (domain == 'partners.bit.ly');
        }
        
        function getPartnerInfo(partner_string) {
            var m = partner_string.toString().match(/^\/?(\w+)\/?$/i);
            if (m && m[1]) {
                return o.partners[m[1]];
            }
        }

        function stattoggle(e) {
            var id = this.id.substring(4);
            $('#r_s_' + id).toggle();
            var t = $("#traffic_pause").text();
            if (t && t != "Resume") {
                InfoPage.pauseButtonClick(document.getElementById('traffic_pause'));
            }
        }

    };
    
    var defaults = { 
        time_frames : ["PAST_HOUR", "PAST_WEEK", "PAST_MONTH"],
        timeframe_lookup : {
            1 : "PAST_HOUR",
            7 : "PAST_WEEK",
            30 : "PAST_MONTH"
        },
        clicks_endpoint : '/data/clicks/summary',
        countries_endpoint : '/data/countries/summary',
        referrers_endpoint : '/data/referrers/summary',
        clicks_hourly_endpoint : '/data/clicks/hourly',
        countries_hourly_endpoint : '/data/countries/hourly',
        referrers_hourly_endpoint : '/data/referrers/hourly',
        api_error_text : 'Unable to Load User Metrics Currently',
        partners : {
            "td": {"display_name": "TweetDeck", "url": "http://www.tweetdeck.com/"},
            "twe": {"display_name": "Tweetie", "url": "http://www.atebits.com/tweetie-mac/"},
            "sd": {"display_name": "Seesmic Desktop", "url": "http://desktop.seesmic.com/"},
            "twh": {"display_name": "Twhirl", "url": "http://twhirl.org/"},
            "ef": {"display_name": "Echofon", "url": "http://www.echofon.com/"},
            "ub": {"display_name": "\xc3\x9cberTwitter", "url": "http://www.ubertwitter.com/"}
        }
    },
    ISO_COUNTRIES = {
            "AF": "Afghanistan","AX": "Åland Islands", "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",
"BN": "Brunei Darussalam",
"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 (Keeling) Islands",
"CO": "Colombia",
"KM": "Comoros",
"CG": "Congo",
"CD": "Congo, The Democratic Republic of the",
"CK": "Cook Islands",
"CR": "Costa Rica",
"CI": "Côte d'Ivoire",
"HR": "Croatia",
"CU": "Cuba",
"CY": "Cyprus",
"CZ": "Czech Republic",
"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 (Malvinas)",
"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",
"GG": "Guernsey",
"GN": "Guinea",
"GW": "Guinea-Bissau",
"GY": "Guyana",
"HT": "Haiti",
"HM": "Heard Island and McDonald Islands",
"VA": "Holy See (Vatican City State)",
"HN": "Honduras",
"HK": "Hong Kong",
"HU": "Hungary",
"IS": "Iceland",
"IN": "India",
"ID": "Indonesia",
"IR": "Iran, Islamic Republic of",
"IQ": "Iraq",
"IE": "Ireland",
"IM": "Isle of Man",
"IL": "Israel",
"IT": "Italy",
"JM": "Jamaica",
"JP": "Japan",
"JE": "Jersey",
"JO": "Jordan",
"KZ": "Kazakhstan",
"KE": "Kenya",
"KI": "Kiribati",
"KP": "Korea, Democratic People's Republic of",
"KR": "Korea, Republic of",
"KW": "Kuwait",
"KG": "Kyrgyzstan",
"LA": "Lao People's Democratic Republic",
"LV": "Latvia",
"LB": "Lebanon",
"LS": "Lesotho",
"LR": "Liberia",
"LY": "Libyan Arab Jamahiriya",
"LI": "Liechtenstein",
"LT": "Lithuania",
"LU": "Luxembourg",
"MO": "Macao",
"MK": "Macedonia, The Former Yugoslav Republic of",
"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, Federated States of",
"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",
"MP": "Northern Mariana Islands",
"NO": "Norway",
"OM": "Oman",
"PK": "Pakistan",
"PW": "Palau",
"PS": "Palestinian Territory, Occupied",
"PA": "Panama",
"PG": "Papua New Guinea",
"PY": "Paraguay",
"PE": "Peru",
"PH": "Philippines",
"PN": "Pitcairn",
"PL": "Poland",
"PT": "Portugal",
"PR": "Puerto Rico",
"QA": "Qatar",
"RE": "Réunion",
"RO": "Romania",
"RU": "Russian Federation",
"RW": "Rwanda",
"BL": "Saint Barthélemy",
"SH": "Saint Helena",
"KN": "Saint Kitts and Nevis",
"LC": "Saint Lucia",
"MF": "Saint Martin",
"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",
"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",
"ES": "Spain",
"LK": "Sri Lanka",
"SD": "Sudan",
"SR": "Suriname",
"SJ": "Svalbard and Jan Mayen",
"SZ": "Swaziland",
"SE": "Sweden",
"CH": "Switzerland",
"SY": "Syrian Arab Republic",
"TW": "Taiwan",
"TJ": "Tajikistan",
"TZ": "Tanzania, United Republic of",
"TH": "Thailand",
"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",
"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",
"VE": "Venezuela","VN": "Viet Nam","VG": "Virgin Islands, British","VI": "Virgin Islands, U.S.","WF": "Wallis and Futuna","EH": "Western Sahara","YE": "Yemen","ZM": "Zambia","ZW": "Zimbabwe"};
    
    function connector(url, params, callback, error) {
        var str = $.param( params );
        $.ajax({
            dataType: 'json',                    
            'url' : url, 
            type : 'POST',
            data : str,
            success : callback,
            'error' : error
        });
    }

})(jQuery);