public static byte[] compress(String urlString) throws MalformedURLException {
        byte[] compressedBytes = null;
        if (urlString != null) {
            // Figure the compressed bytes can't be longer than the original string.
            byte[] byteBuffer = new byte[urlString.length()];
            int byteBufferIndex = 0;
            Arrays.fill(byteBuffer, (byte) 0x00);

            Pattern urlPattern = Pattern.compile(EDDYSTONE_URL_REGEX);
            Matcher urlMatcher = urlPattern.matcher(urlString);
            if (urlMatcher.matches()) {
                // www.
                String wwwdot = urlMatcher.group(EDDYSTONE_URL_WWW_GROUP);
                boolean haswww = (wwwdot != null);

                // Protocol.
                String rawProtocol = urlMatcher.group(EDDYSTONE_URL_PROTOCOL_GROUP);
                String protocol = rawProtocol.toLowerCase();
                if (protocol.equalsIgnoreCase(URL_PROTOCOL_HTTP)) {
                    byteBuffer[byteBufferIndex] = (haswww ? EDDYSTONE_URL_PROTOCOL_HTTP_WWW : EDDYSTONE_URL_PROTOCOL_HTTP);
                }
                else {
                    byteBuffer[byteBufferIndex] = (haswww ? EDDYSTONE_URL_PROTOCOL_HTTPS_WWW : EDDYSTONE_URL_PROTOCOL_HTTPS);
                }
                byteBufferIndex++;

                // Fully-qualified domain name (FQDN).  This includes the hostname and any other components after the dots
                // but BEFORE the first single slash in the URL.
                byte[] hostnameBytes = urlMatcher.group(EDDYSTONE_URL_FQDN_GROUP).getBytes();
                String rawHostname = new String(hostnameBytes);
                String hostname = rawHostname.toLowerCase();
                String[] domains = hostname.split(Pattern.quote("."));

                boolean consumedSlash = false;
                if (domains != null) {
                    // Write the hostname/subdomains prior to the last one.  If there's only one (e. g. http://localhost)
                    // then that's the only thing to write out.
                    byte[] periodBytes = {'.'};
                    int writableDomainsCount = (domains.length == 1 ? 1 : domains.length - 1);
                    for (int domainIndex = 0; domainIndex < writableDomainsCount; domainIndex++) {
                        // Write out leading period, if necessary.
                        if (domainIndex > 0) {
                            System.arraycopy(periodBytes, 0, byteBuffer, byteBufferIndex, periodBytes.length);
                            byteBufferIndex += periodBytes.length;
                        }

                        byte[] domainBytes = domains[domainIndex].getBytes();
                        int domainLength = domainBytes.length;
                        System.arraycopy(domainBytes, 0, byteBuffer, byteBufferIndex, domainLength);
                        byteBufferIndex += domainLength;
                    }

                    // Is the TLD one that we can encode?
                    if (domains.length > 1) {
                        String tld = "." + domains[domains.length - 1];
                        String slash = urlMatcher.group(EDDYSTONE_URL_SLASH_GROUP);
                        String encodableTLDCandidate = (slash == null ? tld : tld + slash);
                        byte encodedTLDByte = encodedByteForTopLevelDomain(encodableTLDCandidate);
                        if (encodedTLDByte != TLD_NOT_ENCODABLE) {
                            byteBuffer[byteBufferIndex++] = encodedTLDByte;
                            consumedSlash = (slash != null);
                        } else {
                            byte[] tldBytes = tld.getBytes();
                            int tldLength = tldBytes.length;
                            System.arraycopy(tldBytes, 0, byteBuffer, byteBufferIndex, tldLength);
                            byteBufferIndex += tldLength;
                        }
                    }
                }

                // Optional slash.
                if (! consumedSlash) {
                    String slash = urlMatcher.group(EDDYSTONE_URL_SLASH_GROUP);
                    if (slash != null) {
                        int slashLength = slash.length();
                        System.arraycopy(slash.getBytes(), 0, byteBuffer, byteBufferIndex, slashLength);
                        byteBufferIndex += slashLength;
                    }
                }

                // Path.
                String path = urlMatcher.group(EDDYSTONE_URL_PATH_GROUP);
                if (path != null) {
                    int pathLength =  path.length();
                    System.arraycopy(path.getBytes(), 0, byteBuffer, byteBufferIndex, pathLength);
                    byteBufferIndex += pathLength;
                }

                // Copy the result.
                compressedBytes = new byte[byteBufferIndex];
                System.arraycopy(byteBuffer, 0, compressedBytes, 0, compressedBytes.length);
            }
            else {
                throw new MalformedURLException();
            }
        }
        else {
            throw new MalformedURLException();
        }
        return compressedBytes;
    }
@Test
    public void testCompressWithSubdomainsAndSlashesInPath() throws MalformedURLException {
        String testURL = "http://www.forums.google.com/123/456";
        byte[] expectedBytes = {0x00, 'f', 'o', 'r', 'u', 'm', 's', '.', 'g', 'o', 'o', 'g', 'l', 'e', 0x00, '1', '2', '3', '/', '4', '5', '6'};
        assertTrue(Arrays.equals(expectedBytes, UrlBeaconUrlCompressor.compress(testURL)));
    }