// Path: cip-core/src/main/java/com/digitalpetri/enip/cip/CipResponseException.java
// public class CipResponseException extends Exception {
// 
//     private final int generalStatus;
//     private final int[] additionalStatus;
// 
//     public CipResponseException(int generalStatus, int[] additionalStatus) {
//         this.generalStatus = generalStatus;
//         this.additionalStatus = additionalStatus;
//     }
// 
//     public int getGeneralStatus() {
//         return generalStatus;
//     }
// 
//     public int[] getAdditionalStatus() {
//         return additionalStatus;
//     }
// 
//     @Override
//     public String getMessage() {
//         StringBuilder sb = new StringBuilder();
// 
//         sb.append(String.format("status=0x%02X", generalStatus));
// 
//         CipStatusCodes.getName(generalStatus).ifPresent(name -> sb.append(" [").append(name).append("] "));
// 
//         List<String> as = Arrays.stream(additionalStatus)
//             .mapToObj(a -> String.format("0x%04X", a))
//             .collect(Collectors.toList());
// 
//         String additional = "[" + String.join(",", as) + "]";
// 
//         sb.append(", additional=").append(additional);
// 
//         return sb.toString();
//     }
// 
//     /**
//      * If {@code ex} is a {@link CipResponseException}, or if a {@link CipResponseException} can be found by walking
//      * the exception cause chain, return it.
//      *
//      * @param ex the {@link Throwable} to extract from.
//      * @return a {@link CipResponseException} if one was present in the exception chain.
//      */
//     public static Optional<CipResponseException> extract(Throwable ex) {
//         if (ex instanceof CipResponseException) {
//             return Optional.of((CipResponseException) ex);
//         } else {
//             Throwable cause = ex.getCause();
//             return cause != null ?
//                 extract(cause) : Optional.empty();
//         }
//     }
// 
// }
// 
// Path: cip-core/src/main/java/com/digitalpetri/enip/cip/epath/EPath.java
// public static final class PaddedEPath extends EPath {
// 
//     public PaddedEPath(List<EPathSegment> segments) {
//         this(segments.toArray(new EPathSegment[segments.size()]));
//     }
// 
//     public PaddedEPath(EPathSegment... segments) {
//         super(segments);
//     }
// 
//     @Override
//     public boolean isPadded() {
//         return true;
//     }
// 
//     public PaddedEPath append(PaddedEPath other) {
//         int aLen = getSegments().length;
//         int bLen = other.getSegments().length;
// 
//         EPathSegment[] newSegments = new EPathSegment[aLen + bLen];
// 
//         System.arraycopy(getSegments(), 0, newSegments, 0, aLen);
//         System.arraycopy(other.getSegments(), 0, newSegments, aLen, bLen);
// 
//         return new PaddedEPath(newSegments);
//     }
// 
// }
// 
// Path: cip-core/src/main/java/com/digitalpetri/enip/cip/structs/MessageRouterRequest.java
// public class MessageRouterRequest {
// 
//     private final int serviceCode;
//     private final EPath.PaddedEPath requestPath;
//     private final Consumer<ByteBuf> dataEncoder;
// 
//     public MessageRouterRequest(int serviceCode, EPath.PaddedEPath requestPath, ByteBuf requestData) {
//         this.serviceCode = serviceCode;
//         this.requestPath = requestPath;
//         this.dataEncoder = (buffer) -> buffer.writeBytes(requestData);
//     }
// 
//     public MessageRouterRequest(int serviceCode, EPath.PaddedEPath requestPath, Consumer<ByteBuf> dataEncoder) {
//         this.serviceCode = serviceCode;
//         this.requestPath = requestPath;
//         this.dataEncoder = dataEncoder;
//     }
// 
//     public static void encode(MessageRouterRequest request, ByteBuf buffer) {
//         buffer.writeByte(request.serviceCode);
//         EPath.encode(request.requestPath, buffer);
//         request.dataEncoder.accept(buffer);
//     }
// 
// }
// 
// Path: cip-core/src/main/java/com/digitalpetri/enip/cip/structs/MessageRouterResponse.java
// public class MessageRouterResponse {
// 
//     private final int serviceCode;
//     private final int generalStatus;
//     private final int[] additionalStatus;
// 
//     private final ByteBuf data;
// 
//     public MessageRouterResponse(int serviceCode,
//                                  int generalStatus,
//                                  int[] additionalStatus,
//                                  @Nonnull ByteBuf data) {
// 
//         this.serviceCode = serviceCode;
//         this.generalStatus = generalStatus;
//         this.additionalStatus = additionalStatus;
//         this.data = data;
//     }
// 
//     public int getServiceCode() {
//         return serviceCode;
//     }
// 
//     public int getGeneralStatus() {
//         return generalStatus;
//     }
// 
//     public int[] getAdditionalStatus() {
//         return additionalStatus;
//     }
// 
//     @Nonnull
//     public ByteBuf getData() {
//         return data;
//     }
// 
//     public static MessageRouterResponse decode(ByteBuf buffer) {
//         int serviceCode = buffer.readUnsignedByte();
//         buffer.skipBytes(1); // reserved
//         int generalStatus = buffer.readUnsignedByte();
// 
//         int count = buffer.readUnsignedByte();
//         int[] additionalStatus = new int[count];
//         for (int i = 0; i < count; i++) {
//             additionalStatus[i] = buffer.readShort();
//         }
// 
//         ByteBuf data = buffer.isReadable() ?
//             buffer.readSlice(buffer.readableBytes()).retain() : Unpooled.EMPTY_BUFFER;
// 
//         return new MessageRouterResponse(serviceCode, generalStatus, additionalStatus, data);
//     }
// 
// }


import com.digitalpetri.enip.cip.CipResponseException;
import com.digitalpetri.enip.cip.epath.EPath.PaddedEPath;
import com.digitalpetri.enip.cip.structs.MessageRouterRequest;
import com.digitalpetri.enip.cip.structs.MessageRouterResponse;
import io.netty.buffer.ByteBuf;
import io.netty.util.ReferenceCountUtil;
package com.digitalpetri.enip.cip.services;


public class GetAttributeSingleService implements CipService<ByteBuf> {

    public static final int SERVICE_CODE = 0x0E;

// Path: cip-core/src/main/java/com/digitalpetri/enip/cip/CipResponseException.java
// public class CipResponseException extends Exception {
// 
//     private final int generalStatus;
//     private final int[] additionalStatus;
// 
//     public CipResponseException(int generalStatus, int[] additionalStatus) {
//         this.generalStatus = generalStatus;
//         this.additionalStatus = additionalStatus;
//     }
// 
//     public int getGeneralStatus() {
//         return generalStatus;
//     }
// 
//     public int[] getAdditionalStatus() {
//         return additionalStatus;
//     }
// 
//     @Override
//     public String getMessage() {
//         StringBuilder sb = new StringBuilder();
// 
//         sb.append(String.format("status=0x%02X", generalStatus));
// 
//         CipStatusCodes.getName(generalStatus).ifPresent(name -> sb.append(" [").append(name).append("] "));
// 
//         List<String> as = Arrays.stream(additionalStatus)
//             .mapToObj(a -> String.format("0x%04X", a))
//             .collect(Collectors.toList());
// 
//         String additional = "[" + String.join(",", as) + "]";
// 
//         sb.append(", additional=").append(additional);
// 
//         return sb.toString();
//     }
// 
//     /**
//      * If {@code ex} is a {@link CipResponseException}, or if a {@link CipResponseException} can be found by walking
//      * the exception cause chain, return it.
//      *
//      * @param ex the {@link Throwable} to extract from.
//      * @return a {@link CipResponseException} if one was present in the exception chain.
//      */
//     public static Optional<CipResponseException> extract(Throwable ex) {
//         if (ex instanceof CipResponseException) {
//             return Optional.of((CipResponseException) ex);
//         } else {
//             Throwable cause = ex.getCause();
//             return cause != null ?
//                 extract(cause) : Optional.empty();
//         }
//     }
// 
// }
// 
// Path: cip-core/src/main/java/com/digitalpetri/enip/cip/epath/EPath.java
// public static final class PaddedEPath extends EPath {
// 
//     public PaddedEPath(List<EPathSegment> segments) {
//         this(segments.toArray(new EPathSegment[segments.size()]));
//     }
// 
//     public PaddedEPath(EPathSegment... segments) {
//         super(segments);
//     }
// 
//     @Override
//     public boolean isPadded() {
//         return true;
//     }
// 
//     public PaddedEPath append(PaddedEPath other) {
//         int aLen = getSegments().length;
//         int bLen = other.getSegments().length;
// 
//         EPathSegment[] newSegments = new EPathSegment[aLen + bLen];
// 
//         System.arraycopy(getSegments(), 0, newSegments, 0, aLen);
//         System.arraycopy(other.getSegments(), 0, newSegments, aLen, bLen);
// 
//         return new PaddedEPath(newSegments);
//     }
// 
// }
// 
// Path: cip-core/src/main/java/com/digitalpetri/enip/cip/structs/MessageRouterRequest.java
// public class MessageRouterRequest {
// 
//     private final int serviceCode;
//     private final EPath.PaddedEPath requestPath;
//     private final Consumer<ByteBuf> dataEncoder;
// 
//     public MessageRouterRequest(int serviceCode, EPath.PaddedEPath requestPath, ByteBuf requestData) {
//         this.serviceCode = serviceCode;
//         this.requestPath = requestPath;
//         this.dataEncoder = (buffer) -> buffer.writeBytes(requestData);
//     }
// 
//     public MessageRouterRequest(int serviceCode, EPath.PaddedEPath requestPath, Consumer<ByteBuf> dataEncoder) {
//         this.serviceCode = serviceCode;
//         this.requestPath = requestPath;
//         this.dataEncoder = dataEncoder;
//     }
// 
//     public static void encode(MessageRouterRequest request, ByteBuf buffer) {
//         buffer.writeByte(request.serviceCode);
//         EPath.encode(request.requestPath, buffer);
//         request.dataEncoder.accept(buffer);
//     }
// 
// }
// 
// Path: cip-core/src/main/java/com/digitalpetri/enip/cip/structs/MessageRouterResponse.java
// public class MessageRouterResponse {
// 
//     private final int serviceCode;
//     private final int generalStatus;
//     private final int[] additionalStatus;
// 
//     private final ByteBuf data;
// 
//     public MessageRouterResponse(int serviceCode,
//                                  int generalStatus,
//                                  int[] additionalStatus,
//                                  @Nonnull ByteBuf data) {
// 
//         this.serviceCode = serviceCode;
//         this.generalStatus = generalStatus;
//         this.additionalStatus = additionalStatus;
//         this.data = data;
//     }
// 
//     public int getServiceCode() {
//         return serviceCode;
//     }
// 
//     public int getGeneralStatus() {
//         return generalStatus;
//     }
// 
//     public int[] getAdditionalStatus() {
//         return additionalStatus;
//     }
// 
//     @Nonnull
//     public ByteBuf getData() {
//         return data;
//     }
// 
//     public static MessageRouterResponse decode(ByteBuf buffer) {
//         int serviceCode = buffer.readUnsignedByte();
//         buffer.skipBytes(1); // reserved
//         int generalStatus = buffer.readUnsignedByte();
// 
//         int count = buffer.readUnsignedByte();
//         int[] additionalStatus = new int[count];
//         for (int i = 0; i < count; i++) {
//             additionalStatus[i] = buffer.readShort();
//         }
// 
//         ByteBuf data = buffer.isReadable() ?
//             buffer.readSlice(buffer.readableBytes()).retain() : Unpooled.EMPTY_BUFFER;
// 
//         return new MessageRouterResponse(serviceCode, generalStatus, additionalStatus, data);
//     }
// 
// }


// Path: cip-core/src/main/java/com/digitalpetri/enip/cip/services/GetAttributeSingleService.java
import com.digitalpetri.enip.cip.CipResponseException;
import com.digitalpetri.enip.cip.epath.EPath.PaddedEPath;
import com.digitalpetri.enip.cip.structs.MessageRouterRequest;
import com.digitalpetri.enip.cip.structs.MessageRouterResponse;
import io.netty.buffer.ByteBuf;
import io.netty.util.ReferenceCountUtil;

package com.digitalpetri.enip.cip.services;


public class GetAttributeSingleService implements CipService<ByteBuf> {

    public static final int SERVICE_CODE = 0x0E;

    private final PaddedEPath requestPath;