String.prototype.startsWith = 
    function(candidate) 
    {
        var expressionToMatch = new RegExp("^" + candidate);
        return this.match(expressionToMatch);
    };
String.prototype.trim = 
    function() 
    {
        var trimmed = this.replace(/^\s+/, '');
        return trimmed.replace(/\s+$/, '');
    };

// If this function changes, make the same changes to:
// //desert/usr/local/apache/php/include/common.php
function getPhoneNumberAndName(candidate)
{
    if (looksLikeATextablePhoneNumber(candidate))
    {
        var numberAndName = new Array();
        numberAndName[0] = candidate;
        numberAndName[1] = null;
        return numberAndName;
    }

    // Bear in mind that a phone number may have space or dash separators.

    // Common cases that must be handled correctly:
    // 1. Valid phone number, space, name.
    // 2. Name, space, valid phone number.

    candidate = candidate.trim();
    if (candidate.match(/^[0-9+\(]/))
    {
        return parsePhoneNumberAndNameFromRight(candidate);
    }
    else
    {
        return parsePhoneNumberAndNameFromLeft(candidate);
    }
}

// If this function changes, make the same changes to:
// //desert/usr/local/apache/php/include/common.php
function looksLikeATextablePhoneNumber(candidate)
{
    if (candidate == null) { return false; }

    candidate = candidate.trim();

    var isInternational = false;
    if (candidate.indexOf('+') == 0)
    {
        candidate = candidate.substr('+'.length);
        isInternational = true;
    }
    else
    {
        var internationalAccessCodesInAustralia = new Array();
        internationalAccessCodesInAustralia[0] = '0011';
        internationalAccessCodesInAustralia[1] = '0012';
        for (var codeIndex=0; codeIndex < internationalAccessCodesInAustralia.length; codeIndex++)
        {
            var code = internationalAccessCodesInAustralia[codeIndex];
            if (candidate.startsWith(code))
            {
                candidate = candidate.substring(code.length);
                isInternational = true;
                break;
            }
        }
    }
    if (isInternational)
    {
        var countryCodeForAustralia = '61';
        if (!candidate.startsWith(countryCodeForAustralia)) { return false; }
        candidate = candidate.substring(countryCodeForAustralia.length);
    }
    if (candidate.indexOf('+') > -1) { return false; }
    
    // One set of parentheses is allowed.
    var indexOfOpenParenthesis = candidate.indexOf('(');
    if (indexOfOpenParenthesis > -1 && (candidate.lastIndexOf('(') != indexOfOpenParenthesis)) { return false; }
    var indexOfCloseParenthesis = candidate.indexOf(')');
    if (indexOfCloseParenthesis > -1 && (candidate.lastIndexOf(')') != indexOfCloseParenthesis)) { return false; }
    if (indexOfOpenParenthesis > -1 && indexOfCloseParenthesis <= -1) { return false; }
    if (indexOfOpenParenthesis > -1)
    {
        // Normalise parenthesis group to have a zero prefix.
        candidate = candidate.replace(/\(([1-9])/g, '(0$1');
        candidate = candidate.replace(/\((.*)\)/g, '$1');
    }

    var digitsOnlyCandidate = candidate.replace(/[ -.]/g, '');
    if (digitsOnlyCandidate.match(/[^0-9]/)) { return false; }
    if (digitsOnlyCandidate.length > 15) { return false; }

    var nonTextablePrefixes = new Array();
    nonTextablePrefixes[0] = '000';
    nonTextablePrefixes[1] = '015';
    nonTextablePrefixes[2] = '018';
    nonTextablePrefixes[3] = '12';
    nonTextablePrefixes[4] = '13';
    nonTextablePrefixes[5] = '106';
    nonTextablePrefixes[6] = '112';
    nonTextablePrefixes[7] = '1300';
    nonTextablePrefixes[8] = '180';
    nonTextablePrefixes[9] = '190';
    for (var prefixIndex=0; prefixIndex < nonTextablePrefixes.length; prefixIndex++)
    {
        var prefix = nonTextablePrefixes[prefixIndex];
        if (digitsOnlyCandidate.startsWith(prefix))
        {
            return false;
        }
    }

    var textablePrefixes = new Array();
    textablePrefixes[0] = '02';
    textablePrefixes[1] = '03';
    textablePrefixes[2] = '07';
    textablePrefixes[3] = '08';
    textablePrefixes[4] = '04';
    for (var prefixIndex=0; prefixIndex < textablePrefixes.length; prefixIndex++)
    {
        var prefix = textablePrefixes[prefixIndex];
        if (digitsOnlyCandidate.startsWith(prefix))
        {
            digitsOnlyCandidate = digitsOnlyCandidate.substring(prefix.length);
            break;
        }
    }
    if (digitsOnlyCandidate.length < 8) { return false; }

    return true;
}

// If this function changes, make the same changes to:
// //desert/usr/local/apache/php/include/common.php
function parsePhoneNumberAndNameFromLeft(candidate)
{
    var number = null;
    var name = null;
    var left = '';
    var right = candidate;
    while (right != null && right.length > 0)
    {
        if (looksLikeATextablePhoneNumber(left))
        {
            number = left;
            name = right;
            break;
        }
        else if (looksLikeATextablePhoneNumber(right))
        {
            number = right;
            name = left;
            break;
        }
        left = left + right.substring(0, 1);
        right = right.substring(1);
    }
    if (number == null)
    {
        name = candidate;
    }
    if (number != null)
    {
        number = number.trim();
    }
    if (name != null)
    {
        name = name.trim();
    }
    var numberAndName = new Array();
    numberAndName[0] = number;
    numberAndName[1] = name;
    return numberAndName;
}

// If this function changes, make the same changes to:
// //desert/usr/local/apache/php/include/common.php
function parsePhoneNumberAndNameFromRight(candidate)
{
    var number = null;
    var name = null;
    var left = candidate;
    var right = '';
    while (left != null && left.length > 0)
    {
        if (looksLikeATextablePhoneNumber(left))
        {
            number = left;
            name = right;
            break;
        }
        else if (looksLikeATextablePhoneNumber(right))
        {
            number = right;
            name = left;
            break;
        }
        right = left.substring(left.length - 1) + right;
        if (left.length == 1)
        {
            left = '';
        }
        else
        {
            left = left.substring(0, left.length - 1);
        }
    }
    if (number == null)
    {
        name = candidate;
    }
    if (number != null)
    {
        number = number.trim();
    }
    if (name != null)
    {
        name = name.trim();
    }
    var numberAndName = new Array();
    numberAndName[0] = number;
    numberAndName[1] = name;
    return numberAndName;
}
