class RobotsDirectives implements Serializable {
    private static final long serialVersionUID = 5386542759286155383L;
    
    protected ConcurrentSkipListSet<String> disallows = new ConcurrentSkipListSet<String>();
    protected ConcurrentSkipListSet<String> allows = new ConcurrentSkipListSet<String>();
    protected float crawlDelay = -1; 
    public transient boolean hasDirectives = false;

    public boolean allows(String path) {
        return !(longestPrefixLength(disallows, path) > longestPrefixLength(allows, path));
    }

    /**
     * @param prefixSet
     * @param str
     * @return length of longest entry in {@code prefixSet} that prefixes {@code str}, or zero
     *         if no entry prefixes {@code str}
     */
    protected int longestPrefixLength(ConcurrentSkipListSet<String> prefixSet,
            String str) {<FILL_FUNCTION_BODY>}

    public void addDisallow(String path) {
        hasDirectives = true;
        if(path.length()==0) {
            // ignore empty-string disallows 
            // (they really mean allow, when alone)
            return;
        }
        disallows.add(path);
    }

    public void addAllow(String path) {
        hasDirectives = true;
        allows.add(path);
    }

    public void setCrawlDelay(float i) {
        hasDirectives = true;
        crawlDelay=i;
    }

    public float getCrawlDelay() {
        return crawlDelay;
    }
    
    // Kryo support
    public static void autoregisterTo(AutoKryo kryo) {
        kryo.register(RobotsDirectives.class, new ReferenceFieldSerializer(kryo, RobotsDirectives.class));
        kryo.autoregister(ConcurrentSkipListSet.class); // now used instead of PrefixSet in RobotsDirectives
        kryo.setRegistrationOptional(true); 
    }

}

        String possiblePrefix = prefixSet.floor(str);
        if (possiblePrefix != null && str.startsWith(possiblePrefix)) {
            return possiblePrefix.length();
        } else {
            return 0;
        }
    
<no_super_class>