class SerialVersionUIDAdder extends ClassVisitor {

  protected long computeSVUID() throws IOException {
    long svuid = 0;

    try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream)) {

      // 1. The class name written using UTF encoding.
      dataOutputStream.writeUTF(name.replace('/', '.'));

      // 2. The class modifiers written as a 32-bit integer.
      int mods = access;
      if ((mods & Opcodes.ACC_INTERFACE) != 0) {
        mods =
            svuidMethods.isEmpty() ? (mods & ~Opcodes.ACC_ABSTRACT) : (mods | Opcodes.ACC_ABSTRACT);
      }
      dataOutputStream.writeInt(
          mods
              & (Opcodes.ACC_PUBLIC
                  | Opcodes.ACC_FINAL
                  | Opcodes.ACC_INTERFACE
                  | Opcodes.ACC_ABSTRACT));

      // 3. The name of each interface sorted by name written using UTF encoding.
      Arrays.sort(interfaces);
      for (String interfaceName : interfaces) {
        dataOutputStream.writeUTF(interfaceName.replace('/', '.'));
      }

      // 4. For each field of the class sorted by field name (except private static and private
      // transient fields):
      //   1. The name of the field in UTF encoding.
      //   2. The modifiers of the field written as a 32-bit integer.
      //   3. The descriptor of the field in UTF encoding.
      // Note that field signatures are not dot separated. Method and constructor signatures are dot
      // separated. Go figure...
      writeItems(svuidFields, dataOutputStream, false);

      // 5. If a class initializer exists, write out the following:
      //   1. The name of the method, <clinit>, in UTF encoding.
      //   2. The modifier of the method, ACC_STATIC, written as a 32-bit integer.
      //   3. The descriptor of the method, ()V, in UTF encoding.
      if (hasStaticInitializer) {
        dataOutputStream.writeUTF(CLINIT);
        dataOutputStream.writeInt(Opcodes.ACC_STATIC);
        dataOutputStream.writeUTF("()V");
      }

      // 6. For each non-private constructor sorted by method name and signature:
      //   1. The name of the method, <init>, in UTF encoding.
      //   2. The modifiers of the method written as a 32-bit integer.
      //   3. The descriptor of the method in UTF encoding.
      writeItems(svuidConstructors, dataOutputStream, true);

      // 7. For each non-private method sorted by method name and signature:
      //   1. The name of the method in UTF encoding.
      //   2. The modifiers of the method written as a 32-bit integer.
      //   3. The descriptor of the method in UTF encoding.
      writeItems(svuidMethods, dataOutputStream, true);

      dataOutputStream.flush();

      // 8. The SHA-1 algorithm is executed on the stream of bytes produced by DataOutputStream and
      // produces five 32-bit values sha[0..4].
      byte[] hashBytes = computeSHAdigest(byteArrayOutputStream.toByteArray());

      // 9. The hash value is assembled from the first and second 32-bit values of the SHA-1 message
      // digest. If the result of the message digest, the five 32-bit words H0 H1 H2 H3 H4, is in an
      // array of five int values named sha, the hash value would be computed as follows:
      for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
        svuid = (svuid << 8) | (hashBytes[i] & 0xFF);
      }
    }

    return svuid;
  }

  public  SerialVersionUIDAdder(final ClassVisitor classVisitor);
  protected  SerialVersionUIDAdder(final int api, final ClassVisitor classVisitor);

}