<commit_before>var request = require('request'),
    crypto = require('crypto');

exports.defaultRegion = 'us';
exports.privateKey = null;
exports.publicKey = null;


// Makes request
function get(options, callback) {
    // Default values
    options.region = options.region || exports.defaultRegion;
    options.game = options.game || 'wow';
    options.query = options.query ? '?' + options.query : '';

    var path = '/api/' + options.game + options.path,

        uri = encodeURI('http://' + options.region + '.battle.net' +
            path + options.query),

        headers = { 'Connection': 'keep-alive' };

    // Authentication
    if (exports.privateKey && exports.publicKey) {
        var signature = crypto.createHmac('sha1', exports.privateKey);

        signature.update(
            'GET\n' +
            new Date().toUTCString() + '\n' +
            path + '\n'
        );

        headers['Authorization'] = 'BNET ' + exports.publicKey + ':' +
            signature.digest('base64');
    }

    request({ uri: uri, headers: headers }, function(err, res, body) {
        if (err) {
            return callback(err);
        }

        body = JSON.parse(body);

        if (body.status === 'nok') {
            return callback(new Error(body.reason));
        }

        callback(null, body);
    });
}


// Requests one or more API resources
function resource(method, options, callback) {
    var names;

    // If single resource provided
    if (typeof options === 'string') {
        names = options;
        options = {};
    } else if (options.names) {
        names = options.names;
    } else {
        return callback(new Error('No name(s) provided.'));
    }

    if (Array.isArray(options.fields)) {
        options.query = 'fields=' + options.fields.join(',');
    }

    options.path = [method, options.realm, options.size];

    var parse = function(name) {
        var parseOptions = {
            path: options.path.slice(0),
            query: options.query,
            region: options.region
        };

        // If path elements passed with name
        if (name.indexOf('_') !== -1) {
            name = name.split('_').reverse();

            parseOptions.path.push(name.pop());

            if (name[0] && name[0].length > 3) {
                parseOptions.path[1] = name.shift();
            }

            if (name[0] && name[0].length === 3) {
                parseOptions.path[2] = name.shift();
            }
        } else if (options.realm) {
            parseOptions.path.push(name);
        } else {
            return callback(new Error('No realm provided for ' + name + '.'));
        }

        // Remove empty path elements
        parseOptions.path = '/' + parseOptions.path.filter(function(el) {
            return !!el;
        }).join('/');

        get(parseOptions, callback);
    };

    if (Array.isArray(names)) {
        names.forEach(parse);
    } else {
        parse(names);
    }
}


// Realm Status API
exports.realmStatus = function() {
    var args = Array.prototype.slice.call(arguments),
        callback = args.pop(),
        options = { path: '/realm/status' };

    if (Array.isArray(args[0])) {
        args[0] = args[0].join('&realm=');
    }

    if (args[0] && args[0].length > 2) {
        options.query = 'realm=' + args.shift();
    }

    if (args[0] && args[0].length === 2) {
        options.region = args[0];
    }

    get(options, function(err, response) {
        if (err) {
            return callback(err);
        }

        callback(null, response.realms);
    });
};


// Item API
exports.item = function() {
    var args = Array.prototype.slice.call(arguments),
        callback = args.pop(),
        options = { path: '/data/item/' };

    if (args[1] && args[1].length === 2) {
        options.region = args[1];
    }

    var parse = function(id) {
        get({ path: options.path + id, region: options.region }, callback);
    };

    if (Array.isArray(args[0])) {
        args[0].forEach(parse);
    } else {
        parse(args[0]);
    }
};


// Exports resource API using generic function
['character', 'guild', 'arena'].forEach(function(method) {
    exports[method] = function(options, callback) {
        resource(method, options, callback);
    };
});


// Static data pages
['perks', 'rewards', 'classes', 'races'].forEach(function(method) {
    var path;

    // Add appropriate prefix
    switch (method) {
        case 'perks':
        case 'rewards':
            path = 'guild/' + method;
            break;
        case 'classes':
        case 'races':
            path = 'character/' + method;
            break;
    }

    path = '/data/' + path;

    exports[method] = function() {
        var args = Array.prototype.slice.call(arguments),
            callback = args.pop(),
            options = { path: path };

        if (args[0]) {
            options.region = args[0];
        }

        get(options, function(err, res) {
            if (err) {
                return callback(err);
            }

            callback(null, res[method]);
        });
    };<commit_msg>Adding locale parameter, comments.<commit_after>var request = require('request'),
    crypto = require('crypto');

exports.defaultRegion = 'us';
exports.privateKey = null;
exports.publicKey = null;


// Makes request
function get(options, callback) {
    // Default values
    options.region = options.region || exports.defaultRegion;
    options.game = options.game || 'wow';
    options.query = options.query.length ? '?' + options.query.join('&') : '';


    var path = '/api/' + options.game + options.path,

        uri = encodeURI('http://' + options.region + '.battle.net' +
            path + options.query),

        headers = { 'Connection': 'keep-alive' };


    // Authentication
    if (exports.privateKey && exports.publicKey) {
        var signature = crypto.createHmac('sha1', exports.privateKey);

        signature.update(
            'GET\n' +
            new Date().toUTCString() + '\n' +
            path + '\n'
        );

        headers['Authorization'] = 'BNET ' + exports.publicKey + ':' +
            signature.digest('base64');
    }


    request({ uri: uri, headers: headers }, function(err, res, body) {
        if (err) {
            return callback(err);
        }

        body = JSON.parse(body);

        if (body.status === 'nok') {
            return callback(new Error(body.reason));
        }

        callback(null, body);
    });
}


// Requests one or more API resources
function resource(method, options, callback) {
    var names;

    // If single resource provided
    if (typeof options === 'string') {
        names = options;
        options = {};
    } else if (options.names) {
        names = options.names;
    } else {
        return callback(new Error('No name(s) provided.'));
    }

    options.query = [];


    if (Array.isArray(options.fields)) {
        options.query.push('fields=' + options.fields.join(','));
    }

    if (options.locale) {
        options.query.push('locale=' + options.locale);
    }

    options.path = [method, options.realm, options.size];


    var parse = function(name) {
        var parseOptions = {
            path: options.path.slice(0),
            query: options.query.slice(0),
            region: options.region
        };

        // If path elements passed with name
        if (name.indexOf('_') !== -1) {
            name = name.split('_').reverse();

            // Name
            parseOptions.path.push(name.pop());

            // Realm
            if (name[0] && name[0].length > 3) {
                parseOptions.path[1] = name.shift();
            }

            // Team size
            if (name[0] && name[0].length === 3) {
                parseOptions.path[2] = name.shift();
            }

        } else if (options.realm) {
            parseOptions.path.push(name);
        } else {
            return callback(new Error('No realm provided for ' + name + '.'));
        }

        // Remove empty path elements
        parseOptions.path = '/' + parseOptions.path.filter(function(el) {
            return !!el;
        }).join('/');

        get(parseOptions, callback);
    };

    if (Array.isArray(names)) {
        names.forEach(parse);
    } else {
        parse(names);
    }
}


// Realm Status API
exports.realmStatus = function() {
    var args = Array.prototype.slice.call(arguments),
        callback = args.pop(),
        options = { path: '/realm/status', query: [] };

    // Multiple realms
    if (Array.isArray(args[0])) {
        args[0] = args[0].join('&realm=');
    }

    // Single realm or joined multiple realms
    if (args[0] && args[0].length > 2) {
        options.query.push('realm=' + args.shift());
    }

    // Region
    if (args[0] && args[0].length === 2) {
        options.region = args[0];
    }

    if (options.locale) {
        options.query.push('locale=' + options.locale);
    }

    get(options, function(err, response) {
        if (err) {
            return callback(err);
        }

        callback(null, response.realms);
    });
};


// Item API
exports.item = function() {
    var args = Array.prototype.slice.call(arguments),
        callback = args.pop(),
        options = { path: '/data/item/', query: [] };

    // Region
    if (args[1] && args[1].length === 2) {
        options.region = args[1];
    }

    if (options.locale) {
        options.query.push('locale=' + options.locale);
    }

    var parse = function(id) {
        get({
            path: options.path + id,
            region: options.region,
            query: options.query.slice(0)
        }, callback);
    };

    if (Array.isArray(args[0])) {
        args[0].forEach(parse);
    } else {
        parse(args[0]);
    }
};


// Exports resource API using generic function
['character', 'guild', 'arena'].forEach(function(method) {
    exports[method] = function(options, callback) {
        resource(method, options, callback);
    };
});


// Static data pages
['perks', 'rewards', 'classes', 'races'].forEach(function(method) {
    var path;

    // Add appropriate prefix
    switch (method) {
        case 'perks':
        case 'rewards':
            path = 'guild/' + method;
            break;
        case 'classes':
        case 'races':
            path = 'character/' + method;
            break;
    }

    path = '/data/' + path;

    exports[method] = function() {
        var args = Array.prototype.slice.call(arguments),
            callback = args.pop(),
            options = { path: path, query: [] };

        // Region
        if (args[0] && args[0].length === 2) {
            options.region = args.shift();
        }

        // Locale
        if (args[0]) {
            options.query.push('locale=' + args[0]);
        }

        get(options, function(err, res) {
            if (err) {
                return callback(err);
            }

            callback(null, res[method]);
        });
    };
{'fraction_non_alphanumeric': 0.15924844947099598, 'fraction_numerical': 0.006293323604523896, 'mean_word_length': 1.8644200626959249, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '173905', 'n_tokens_mistral': 3275, 'n_tokens_neox': 3164, 'n_words': 703}