class ClassPoolTail {
    protected ClassPathList pathList;

    public ClassPoolTail() {
        pathList = null;
    }

    @Override
    public String toString() {
        StringBuffer buf = new StringBuffer();
        buf.append("[class path: ");
        ClassPathList list = pathList;
        while (list != null) {
            buf.append(list.path.toString());
            buf.append(File.pathSeparatorChar);
            list = list.next;
        }

        buf.append(']');
        return buf.toString();
    }

    public synchronized ClassPath insertClassPath(ClassPath cp) {
        pathList = new ClassPathList(cp, pathList);
        return cp;
    }

    public synchronized ClassPath appendClassPath(ClassPath cp) {<FILL_FUNCTION_BODY>}

    public synchronized void removeClassPath(ClassPath cp) {
        ClassPathList list = pathList;
        if (list != null)
            if (list.path == cp)
                pathList = list.next;
            else {
                while (list.next != null)
                    if (list.next.path == cp)
                        list.next = list.next.next;
                    else
                        list = list.next;
            }
    }

    public ClassPath appendSystemPath() {
        if (org.hotswap.agent.javassist.bytecode.ClassFile.MAJOR_VERSION < org.hotswap.agent.javassist.bytecode.ClassFile.JAVA_9)
            return appendClassPath(new ClassClassPath());
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        return appendClassPath(new LoaderClassPath(cl));
    }

    public ClassPath insertClassPath(String pathname)
        throws NotFoundException
    {
        return insertClassPath(makePathObject(pathname));
    }

    public ClassPath appendClassPath(String pathname)
        throws NotFoundException
    {
        return appendClassPath(makePathObject(pathname));
    }

    private static ClassPath makePathObject(String pathname)
        throws NotFoundException
    {
        String lower = pathname.toLowerCase();
        if (lower.endsWith(".jar") || lower.endsWith(".zip"))
            return new JarClassPath(pathname);

        int len = pathname.length();
        if (len > 2 && pathname.charAt(len - 1) == '*'
            && (pathname.charAt(len - 2) == '/'
                || pathname.charAt(len - 2) == File.separatorChar)) {
            String dir = pathname.substring(0, len - 2);
            return new JarDirClassPath(dir);
        }

        return new DirClassPath(pathname);
    }

    /**
     * This method does not close the output stream.
     */
    void writeClassfile(String classname, OutputStream out)
        throws NotFoundException, IOException, CannotCompileException
    {
        InputStream fin = openClassfile(classname);
        if (fin == null)
            throw new NotFoundException(classname);

        try {
            copyStream(fin, out);
        }
        finally {
            fin.close();
        }
    }

    /*
    -- faster version --
    void checkClassName(String classname) throws NotFoundException {
        if (find(classname) == null)
            throw new NotFoundException(classname);
    }

    -- slower version --

    void checkClassName(String classname) throws NotFoundException {
        InputStream fin = openClassfile(classname);
        try {
            fin.close();
        }
        catch (IOException e) {}
    }
    */


    /**
     * Opens the class file for the class specified by
     * <code>classname</code>.
     *
     * @param classname             a fully-qualified class name
     * @return null                 if the file has not been found.
     * @throws NotFoundException    if any error is reported by ClassPath.
     */
    InputStream openClassfile(String classname)
        throws NotFoundException
    {
        ClassPathList list = pathList;
        InputStream ins = null;
        NotFoundException error = null;
        while (list != null) {
            try {
                ins = list.path.openClassfile(classname);
            }
            catch (NotFoundException e) {
                if (error == null)
                    error = e;
            }

            if (ins == null)
                list = list.next;
            else
                return ins;
        }

        if (error != null)
            throw error;
        return null;    // not found
    }

    /**
     * Searches the class path to obtain the URL of the class file
     * specified by classname.  It is also used to determine whether
     * the class file exists.
     *
     * @param classname     a fully-qualified class name.
     * @return null if the class file could not be found.
     */
    public URL find(String classname) {
        ClassPathList list = pathList;
        URL url = null;
        while (list != null) {
            url = list.path.find(classname);
            if (url == null)
                list = list.next;
            else
                return url;
        }

        return null;
    }

    /**
     * Reads from an input stream until it reaches the end.
     *
     * @return          the contents of that input stream
     */
    public static byte[] readStream(InputStream fin) throws IOException {
        byte[][] bufs = new byte[8][];
        int bufsize = 4096;

        for (int i = 0; i < 8; ++i) {
            bufs[i] = new byte[bufsize];
            int size = 0;
            int len = 0;
            do {
                len = fin.read(bufs[i], size, bufsize - size);
                if (len >= 0)
                    size += len;
                else {
                    byte[] result = new byte[bufsize - 4096 + size];
                    int s = 0;
                    for (int j = 0; j < i; ++j) {
                        System.arraycopy(bufs[j], 0, result, s, s + 4096);
                        s = s + s + 4096;
                    }

                    System.arraycopy(bufs[i], 0, result, s, size);
                    return result;
                }
            } while (size < bufsize);
            bufsize *= 2;
        }

        throw new IOException("too much data");
    }

    /**
     * Reads from an input stream and write to an output stream
     * until it reaches the end.  This method does not close the
     * streams.
     */
    public static void copyStream(InputStream fin, OutputStream fout)
        throws IOException
    {
        int bufsize = 4096;
        byte[] buf = null;
        for (int i = 0; i < 64; ++i) {
            if (i < 8) {
                bufsize *= 2;
                buf = new byte[bufsize];
            }
            int size = 0;
            int len = 0;
            do {
                len = fin.read(buf, size, bufsize - size);
                if (len >= 0)
                    size += len;
                else {
                    fout.write(buf, 0, size);
                    return;
                }
            } while (size < bufsize);
            fout.write(buf);
        }

        throw new IOException("too much data");
    }
}

        ClassPathList tail = new ClassPathList(cp, null);
        ClassPathList list = pathList;
        if (list == null)
            pathList = tail;
        else {
            while (list.next != null)
                list = list.next;

            list.next = tail;
        }

        return cp;
    
<no_super_class>