// Path: common/src/main/java/eu/mikroskeem/shuriken/common/streams/ByteArrays.java
// public class ByteArrays {
//     /**
//      * Convert an {@link InputStream} to byte array
//      *
//      * @param inputStream Source {@link InputStream}
//      * @return byte array or null, if reading failed
//      */
//     @Nullable
//     @Contract("null -> fail; !null -> !null")
//     public static byte[] fromInputStream(InputStream inputStream) {
//         notNull(inputStream, "Input stream must not be null!");
//         ByteArrayOutputStream output = new ByteArrayOutputStream();
//         try {
//             byte[] buffer = new byte[1024];
//             int length;
//             while ((length =inputStream.read(buffer)) != -1)
//                 output.write(buffer, 0, length);
//             return output.toByteArray();
//         } catch (IOException e){
//             SneakyThrow.throwException(e);
//             return null;
//         } finally {
//             try {
//                 inputStream.close();
//                 output.close();
//             }
//             catch (IOException ignored){}
//         }
//     }
// }
// 
// Path: instrumentation/src/main/java/eu/mikroskeem/shuriken/instrumentation/ClassTools.java
// @NotNull
// public static String getClassResourcePath(@NotNull String className) {
//     return className.replace('.', '/').concat(".class");
// }


import eu.mikroskeem.shuriken.common.streams.ByteArrays;
import org.jetbrains.annotations.NotNull;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Path;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import static eu.mikroskeem.shuriken.instrumentation.ClassTools.getClassResourcePath;
            throw new IOException("Could not open resource: " + clz);
        }
        addEntry(clz, ByteArrays.fromInputStream(classStream));
    }

    /**
     * Merges other jar into this jar.
     *
     * @param otherJar Other jar
     */
    public void mergeJar(@NotNull ZipInputStream otherJar) throws IOException {
        ZipEntry entry;
        while((entry = otherJar.getNextEntry()) != null) {
            byte[] buf = new byte[(int)entry.getSize()];
            while(true)
                if(!(otherJar.read(buf) > 0))
                    break;
            addEntry(entry.getName(), buf);
        }
    }

    /**
     * Merges other jar into this jar.
     *
     * @param otherJar Other jar
     */
    public void mergeJar(@NotNull ZipFile otherJar) throws IOException {
        Enumeration<? extends ZipEntry> entries = otherJar.entries();
        ZipEntry entry;
        while(entries.hasMoreElements() && (entry = entries.nextElement()) != null) { // Last check isn't needed, I'm just lazy
// Path: common/src/main/java/eu/mikroskeem/shuriken/common/streams/ByteArrays.java
// public class ByteArrays {
//     /**
//      * Convert an {@link InputStream} to byte array
//      *
//      * @param inputStream Source {@link InputStream}
//      * @return byte array or null, if reading failed
//      */
//     @Nullable
//     @Contract("null -> fail; !null -> !null")
//     public static byte[] fromInputStream(InputStream inputStream) {
//         notNull(inputStream, "Input stream must not be null!");
//         ByteArrayOutputStream output = new ByteArrayOutputStream();
//         try {
//             byte[] buffer = new byte[1024];
//             int length;
//             while ((length =inputStream.read(buffer)) != -1)
//                 output.write(buffer, 0, length);
//             return output.toByteArray();
//         } catch (IOException e){
//             SneakyThrow.throwException(e);
//             return null;
//         } finally {
//             try {
//                 inputStream.close();
//                 output.close();
//             }
//             catch (IOException ignored){}
//         }
//     }
// }
// 
// Path: instrumentation/src/main/java/eu/mikroskeem/shuriken/instrumentation/ClassTools.java
// @NotNull
// public static String getClassResourcePath(@NotNull String className) {
//     return className.replace('.', '/').concat(".class");
// }


// Path: instrumentation/src/main/java/eu/mikroskeem/shuriken/instrumentation/runtime/AgentJarOutputStream.java
import eu.mikroskeem.shuriken.common.streams.ByteArrays;
import org.jetbrains.annotations.NotNull;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Path;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import static eu.mikroskeem.shuriken.instrumentation.ClassTools.getClassResourcePath;

            throw new IOException("Could not open resource: " + clz);
        }
        addEntry(clz, ByteArrays.fromInputStream(classStream));
    }

    /**
     * Merges other jar into this jar.
     *
     * @param otherJar Other jar
     */
    public void mergeJar(@NotNull ZipInputStream otherJar) throws IOException {
        ZipEntry entry;
        while((entry = otherJar.getNextEntry()) != null) {
            byte[] buf = new byte[(int)entry.getSize()];
            while(true)
                if(!(otherJar.read(buf) > 0))
                    break;
            addEntry(entry.getName(), buf);
        }
    }

    /**
     * Merges other jar into this jar.
     *
     * @param otherJar Other jar
     */
    public void mergeJar(@NotNull ZipFile otherJar) throws IOException {
        Enumeration<? extends ZipEntry> entries = otherJar.entries();
        ZipEntry entry;
        while(entries.hasMoreElements() && (entry = entries.nextElement()) != null) { // Last check isn't needed, I'm just lazy
            addEntry(entry.getName(), ByteArrays.fromInputStream(otherJar.getInputStream(entry)));