class HotSwapAgent {
    private static Instrumentation instrumentation = null;

    /**
     * Obtains the {@code Instrumentation} object.
     *
     * @return null             when it is not available. 
     */
    public Instrumentation instrumentation() { return instrumentation; }

    /**
     * The entry point invoked when this agent is started by {@code -javaagent}. 
     */
    public static void premain(String agentArgs, Instrumentation inst) throws Throwable {
        agentmain(agentArgs, inst);
    }

    /**
     * The entry point invoked when this agent is started after the JVM starts.
     */
    public static void agentmain(String agentArgs, Instrumentation inst) throws Throwable {
        if (!inst.isRedefineClassesSupported())
            throw new RuntimeException("this JVM does not support redefinition of classes");

        instrumentation = inst;
    }

    /**
     * Redefines a class.
     */
    public static void redefine(Class<?> oldClass, CtClass newClass)
        throws NotFoundException, IOException, CannotCompileException
    {
        Class<?>[] old = { oldClass };
        CtClass[] newClasses = { newClass };
        redefine(old, newClasses);
    }

    /**
     * Redefines classes.
     */
    public static void redefine(Class<?>[] oldClasses, CtClass[] newClasses)
        throws NotFoundException, IOException, CannotCompileException
    {
        startAgent();
        ClassDefinition[] defs = new ClassDefinition[oldClasses.length];
        for (int i = 0; i < oldClasses.length; i++)
            defs[i] = new ClassDefinition(oldClasses[i], newClasses[i].toBytecode());

        try {
            instrumentation.redefineClasses(defs);
        }
        catch (ClassNotFoundException e) {
            throw new NotFoundException(e.getMessage(), e);
        }
        catch (UnmodifiableClassException e) {
            throw new CannotCompileException(e.getMessage(), e);
        }
    }

    /**
     * Ensures that the agent is ready.
     * It attempts to dynamically start the agent if necessary.
     */
    private static void startAgent() throws NotFoundException {
        if (instrumentation != null)
            return;

        try {
            File agentJar = createJarFile();

            String nameOfRunningVM = ManagementFactory.getRuntimeMXBean().getName();
            String pid = nameOfRunningVM.substring(0, nameOfRunningVM.indexOf('@'));
            VirtualMachine vm = VirtualMachine.attach(pid);
            vm.loadAgent(agentJar.getAbsolutePath(), null);
            vm.detach();
        }
        catch (Exception e) {
            throw new NotFoundException("hotswap agent", e);
        }

        for (int sec = 0; sec < 10 /* sec */; sec++) {
            if (instrumentation != null)
                return;

            try {
                Thread.sleep(1000);
            }
            catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }

        throw new NotFoundException("hotswap agent (timeout)");
    }

    /**
     * Creates an agent file for using {@code HotSwapAgent}. 
     */
    public static File createAgentJarFile(String fileName)
        throws IOException, CannotCompileException, NotFoundException
    {
        return createJarFile(new File(fileName));
    }

    private static File createJarFile()
        throws IOException, CannotCompileException, NotFoundException
    {
        File jar = File.createTempFile("agent", ".jar");
        jar.deleteOnExit();
        return createJarFile(jar);
    }

    private static File createJarFile(File jar)
        throws IOException, CannotCompileException, NotFoundException
    {<FILL_FUNCTION_BODY>}
}

        Manifest manifest = new Manifest();
        Attributes attrs = manifest.getMainAttributes();
        attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0");
        attrs.put(new Attributes.Name("Premain-Class"), HotSwapAgent.class.getName());
        attrs.put(new Attributes.Name("Agent-Class"), HotSwapAgent.class.getName());
        attrs.put(new Attributes.Name("Can-Retransform-Classes"), "true");
        attrs.put(new Attributes.Name("Can-Redefine-Classes"), "true");

        JarOutputStream jos = null;
        try {
            jos = new JarOutputStream(new FileOutputStream(jar), manifest);
            String cname = HotSwapAgent.class.getName();
            JarEntry e = new JarEntry(cname.replace('.', '/') + ".class");
            jos.putNextEntry(e);
            ClassPool pool = ClassPool.getDefault();
            CtClass clazz = pool.get(cname);
            jos.write(clazz.toBytecode());
            jos.closeEntry();
        }
        finally {
            if (jos != null)
                jos.close();
        }

        return jar;
    
<no_super_class>