diff --git a/examples/pdulog/Pdusave.dislog b/examples/pdulog/Pdusave.dislog
new file mode 100644
index 0000000000000000000000000000000000000000..32a2b909bb0a59a4dd63be1ea31cce149a43fea6
--- /dev/null
+++ b/examples/pdulog/Pdusave.dislog
@@ -0,0 +1,74 @@
+!Begin!Beginning of DIS capture file, Pdusave.dislog.
+AAAAAAAAAAA=,BwABAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAaSaoc=,BwACAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAyzBH0=,BwADAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAABLY4b4=,BwAEAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAABknSYI=,BwAFAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAB9er5A=,BwAGAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAACVjpaU=,BwAHAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAACuqwAg=,BwAIAwAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAADHlCnY=,BwAJAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAADgj7lw=,BwAKAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAD46vQs=,BwALBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAESF2Js=,BwAMBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAEqxZF4=,BwANBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAFDhQYo=,BwAOBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAFbxtHk=,BwAPBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAA=
+AAAAAF0W+sk=,BwAQBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAGNbAcA=,BwARBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAGmXZkE=,BwASBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAG/OokM=,BwATBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAHXXdnI=,BwAUBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAHvqk8M=,BwAVBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAIIudKs=,BwAWBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAIh7oTM=,BwAXBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAI7ZGfE=,BwAYBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAJVInFQ=,BwAZBAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAJu9JdY=,BwAaBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAKHtbpI=,BwAbBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAKhvG4U=,BwAcBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAK6G2FE=,BwAdBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAALTHS8I=,BwAeBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAALsLY+4=,BwAfBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAME9sU8=,BwAgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAMe0PcY=,BwAhBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAM3w04o=,BwAiBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAANQ8dj8=,BwAjBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAANrdh+E=,BwAkBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAOEZFAA=,BwAlCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAOdXmhk=,BwAmCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAO1k/J0=,BwAnCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAPOtVVA=,BwAoCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAPnWtjc=,BwApCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAP/rrrc=,BwAqCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAQY1GOo=,BwArCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAQw9AnM=,BwAsCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAARKAvOE=,BwAtCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAARjQH+Y=,BwAuCwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAR8NsWE=,BwAvCwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAASVZGO8=,BwAwCwAAAAAAAAAAAAAAAAAAAA==
+AAAAAStulpU=,BwAxCwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAATF84xs=,BwAyCwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAATeY2/k=,BwAzCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAT3c/x8=,BwA0CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAUP1bWE=,BwA1CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAUorAp8=,BwA2CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAVBKYv4=,BwA3CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAA=
+AAAAAVaEExg=,BwA4CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAVypDeE=,BwA5CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAWLnpkU=,BwA6CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAWkCn00=,BwA7CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAW8VawE=,BwA8CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAXUlBBI=,BwA9CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAXtGMCw=,BwA+CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAYFzEIE=,BwA/CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAYevDfM=,BwBACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAY3fbUI=,BwBBCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAZQJ51s=,BwBCAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAZpYq/A=,BwBDAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAaC9mCc=,BwBEAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAabatTU=,BwBFAgAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAa04ynI=,BwBGDQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAbOCOLU=,BwBHDQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAb0Al58=,BwBIAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD6QAAAAA=
+!End!End of DIS capture file, Pdusave.dislog.
diff --git a/examples/pdulog/Pdusave1.dislog b/examples/pdulog/Pdusave1.dislog
new file mode 100644
index 0000000000000000000000000000000000000000..04c5f89154f9d0f8f361e6e4df7831c15e536c5e
--- /dev/null
+++ b/examples/pdulog/Pdusave1.dislog
@@ -0,0 +1,74 @@
+!Begin!Beginning of DIS capture file, Pdusave1.dislog.
+AAAAAAAAAAA=,BwABAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAaPljg=,BwACAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAzecm4=,BwADAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAABMcvao=,BwAEAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAABk4PJg=,BwAFAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAB9xd+I=,BwAGAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAACW8yzk=,BwAHAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAACvQ2c0=,BwAIAwAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAADIxHMc=,BwAJAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAADhy62Y=,BwAKAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAD61l5c=,BwALBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAETzALU=,BwAMBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAEr9gC4=,BwANBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAFElcL4=,BwAOBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAFc2EL0=,BwAPBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAA=
+AAAAAF1n2O0=,BwAQBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAGOJb8E=,BwARBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAGmUqiE=,BwASBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAG+cSio=,BwATBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAHXbXGo=,BwAUBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAHwsW+I=,BwAVBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAIJ19OI=,BwAWBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAIifsIQ=,BwAXBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAI72SUQ=,BwAYBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAJVeZtk=,BwAZBAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAJvPySQ=,BwAaBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAKIk4ag=,BwAbBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAKiDwR0=,BwAcBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAK7QL5k=,BwAdBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAALTXZr4=,BwAeBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAALsVCH4=,BwAfBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAMF3b0k=,BwAgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAMfWTlE=,BwAhBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAM38ZBQ=,BwAiBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAANRJPKg=,BwAjBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAANreDOs=,BwAkBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAOEalRA=,BwAlCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAOdOmFE=,BwAmCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAO2Z0Vk=,BwAnCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAPOoUJM=,BwAoCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAPn1wjU=,BwApCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAQBV/wE=,BwAqCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAQaDqBE=,BwArCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAQyZUBs=,BwAsCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAARLCe2U=,BwAtCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAARju6o4=,BwAuCwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAR8o85E=,BwAvCwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAASU4N74=,BwAwCwAAAAAAAAAAAAAAAAAAAA==
+AAAAAStZ5zQ=,BwAxCwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAATF45Ew=,BwAyCwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAATfIo+Q=,BwAzCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAT4BgQM=,BwA0CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAUQnB5Q=,BwA1CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAUo9ZDs=,BwA2CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAVCNwu8=,BwA3CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAA=
+AAAAAVa0lKs=,BwA4CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAVzhrI8=,BwA5CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAWMEDfM=,BwA6CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAWkdWnQ=,BwA7CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAW9tBgA=,BwA8CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAXWBe8g=,BwA9CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAXuwG2o=,BwA+CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAYG9HIw=,BwA/CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAYgAcd8=,BwBACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAY5NZeQ=,BwBBCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAZSFQpg=,BwBCAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAZq50II=,BwBDAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAaDUpWA=,BwBEAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAacVDlI=,BwBFAgAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAa1OAm4=,BwBGDQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AAAAAbOUILc=,BwBHDQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
+AAAAAb0udwI=,BwBIAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD6QAAAAA=
+!End!End of DIS capture file, Pdusave1.dislog.
diff --git a/examples/runPduRecorder.sh b/examples/runPduRecorder.sh
new file mode 100755
index 0000000000000000000000000000000000000000..484c3298561bcc48228930a6204c96f4ecc51dbe
--- /dev/null
+++ b/examples/runPduRecorder.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+java -cp ../dist/open-dis7-java.jar:../optionallibs/commons-io-2.6.jar:../optionallibs/guava-28.0-jre.jar edu.nps.moves.dis.util.playerrecorder.Recorder
diff --git a/nbproject/project.properties b/nbproject/project.properties
index 01fb788d159585133594d55f84fab12d30cae6ab..9b25dec28198593aae46337879a87cfe87ed3532 100644
--- a/nbproject/project.properties
+++ b/nbproject/project.properties
@@ -35,11 +35,15 @@ dist.jlink.dir=${dist.dir}/jlink
 dist.jlink.output=${dist.jlink.dir}/open-dis7-java
 endorsed.classpath=
 excludes=
+file.reference.commons-io-2.6.jar=optionallibs/commons-io-2.6.jar
+file.reference.guava-28.0-jre.jar=optionallibs/guava-28.0-jre.jar
 file.reference.open-dis7-entities-usa-surface.jar=examplelibs/open-dis7-entities-usa-surface.jar
 includes=**
 jar.compress=false
 javac.classpath=\
-    ${file.reference.open-dis7-entities-usa-surface.jar}
+    ${file.reference.open-dis7-entities-usa-surface.jar}:\
+    ${file.reference.guava-28.0-jre.jar}:\
+    ${file.reference.commons-io-2.6.jar}
 # Space-separated list of extra javac options
 javac.compilerargs=
 javac.deprecation=false
@@ -75,6 +79,7 @@ jlink.additionalmodules=
 jlink.additionalparam=
 jlink.launcher=true
 jlink.launcher.name=open-dis7-java
+main.class=edu.nps.moves.dis.util.playerrecorder.Player
 meta.inf.dir=${src.dir}/META-INF
 mkdist.disabled=true
 platform.active=JDK_1.8
diff --git a/optionallibs/README.md b/optionallibs/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..fbb1b7e6594337191759fae5a3de430d913467ea
--- /dev/null
+++ b/optionallibs/README.md
@@ -0,0 +1,6 @@
+This directory contains libraries which are required at runtime to use the following classes:
+
+1.  <pre>edu.nps.moves.dis.utils.playerRecorder.Recorder</pre>
+2.  <pre>edu.nps.moves.dis.utils.playerRecorder.Player</pre>
+
+
diff --git a/optionallibs/commons-io-2.6.jar b/optionallibs/commons-io-2.6.jar
new file mode 100644
index 0000000000000000000000000000000000000000..00556b119d45dd85a3c3073b1826916c3c60b9c4
Binary files /dev/null and b/optionallibs/commons-io-2.6.jar differ
diff --git a/optionallibs/guava-28.0-jre.jar b/optionallibs/guava-28.0-jre.jar
new file mode 100644
index 0000000000000000000000000000000000000000..f254aae7680a1a64f886b826a7e1fc25ebdaef1f
Binary files /dev/null and b/optionallibs/guava-28.0-jre.jar differ
diff --git a/src/edu/nps/moves/dis/util/DisNetworking.java b/src/edu/nps/moves/dis/util/DisNetworking.java
index 6447ee57da33fe96cbd8d12b75fec3fbe2b4e3eb..3e94ef667ca33915d95b33fde618f135374c07f4 100644
--- a/src/edu/nps/moves/dis/util/DisNetworking.java
+++ b/src/edu/nps/moves/dis/util/DisNetworking.java
@@ -18,6 +18,12 @@ import java.util.Enumeration;
  */
 public class DisNetworking
 {
+  public class BuffAndLength {
+    public byte[] buff; public int length;
+    public BuffAndLength(byte[]buff,int length)
+    {this.buff=buff;this.length=length;}
+  }
+  
   private int DIS_PORT = 3000;
   private String MCAST_GROUP = "230.0.0.0";
   private static final int MAX_DIS_PDU_SIZE = 8192;
@@ -32,8 +38,25 @@ public class DisNetworking
     DIS_PORT = port;
     MCAST_GROUP = mcastgroup;
   }
-
+  
+  public int getPort()
+  {
+    return DIS_PORT;
+  }
+  
+  public String getIp()
+  {
+    return MCAST_GROUP;
+  }
+  
   public Pdu receivePdu() throws IOException
+  {
+    PduFactory pduFactory = new PduFactory();
+    BuffAndLength blen = receiveRawPdu();
+    return pduFactory.createPdu(blen.buff);
+  }
+  
+  public BuffAndLength receiveRawPdu() throws IOException
   {
     MulticastSocket socket;
     DatagramPacket packet;
@@ -46,13 +69,13 @@ public class DisNetworking
 
     byte buffer[] = new byte[MAX_DIS_PDU_SIZE];
     packet = new DatagramPacket(buffer, buffer.length);
-
+    
+    System.out.println("Listening on "+MCAST_GROUP+":"+DIS_PORT+" if:"+socket.getNetworkInterface().getDisplayName());
     socket.receive(packet);   //blocks here waiting for next DIS pdu to be received on broadcast IP and specified port
 
-    System.out.println("packet received from " + packet.getSocketAddress());
+    //System.out.println("packet received from " + packet.getSocketAddress());
     socket.close();
-    
-    return pduFactory.createPdu(packet.getData());
+    return new BuffAndLength(packet.getData(),packet.getLength());
   }
   
   public void sendPdu(Pdu pdu) throws IOException
@@ -84,7 +107,7 @@ public class DisNetworking
       while (addresses.hasMoreElements()) {
         InetAddress addr = addresses.nextElement();
         if (addr instanceof Inet4Address && !addr.isLoopbackAddress()) {
-          System.out.println("Using network interface " + nif.getDisplayName());
+          //System.out.println("Using network interface " + nif.getDisplayName());
           return nif;
         }
       }
diff --git a/src/edu/nps/moves/dis/util/PduFactory.java b/src/edu/nps/moves/dis/util/PduFactory.java
index a8a074a008c66b47395e3edab3ee67af45083291..4b61a5c44697fba167d2cf0db399c8a39f11fc39 100644
--- a/src/edu/nps/moves/dis/util/PduFactory.java
+++ b/src/edu/nps/moves/dis/util/PduFactory.java
@@ -1044,6 +1044,11 @@ public class PduFactory
     return createPdu(pduType, null);
   }
 
+  public DISPDUType getTypeFromByteArray(byte[] ba)
+  {
+    return DISPDUType.getEnumForValue(Byte.toUnsignedInt(ba[2])); // 3rd byte
+  }
+  
   private Pdu createPdu(DISPDUType pduType, ByteBuffer buff)
   {
     Pdu aPdu = null;
diff --git a/src/edu/nps/moves/dis/util/playerrecorder/LogCompare.java b/src/edu/nps/moves/dis/util/playerrecorder/LogCompare.java
new file mode 100644
index 0000000000000000000000000000000000000000..c01f89b401bf283208c2814985ba4b1cf4d8cf14
--- /dev/null
+++ b/src/edu/nps/moves/dis/util/playerrecorder/LogCompare.java
@@ -0,0 +1,124 @@
+package edu.nps.moves.dis.util.playerrecorder;
+
+import edu.nps.moves.dis.Pdu;
+import edu.nps.moves.dis.util.PduFactory;
+import static edu.nps.moves.dis.util.playerrecorder.Recorder.COMMENT_MARKER;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.util.Base64;
+
+/**
+ * LogCompare.java created on Aug 5, 2019
+ * MOVES Institute Naval Postgraduate School, Monterey, CA, USA www.nps.edu
+ *
+ * @author Mike Bailey, jmbailey@nps.edu
+ * @version $Id$
+ */
+public class LogCompare
+{
+  private static String[] paths = {"/Users/mike/NetbeansProjects/open-dis7-java/examples/pdulog/Pdusave.dislog",
+    "/Users/mike/NetbeansProjects/open-dis7-java/examples/pdulog/Pdusave1.dislog"};
+
+  public static void main(String[] args)
+  {
+    if (args.length > 0)
+      paths[0] = args[0];
+    if (args.length > 1)
+      paths[1] = args[1];
+    main2(paths);
+  }
+
+  // Perfect match
+  // Match except for time stamp
+  // Not same sequence of Pdus
+  // Not same number of Pdus
+  // Pdu content difference
+  public static void main2(String[] args)
+  {
+    if (args.length < 2) {
+      System.out.println("Usage: java LogCompare filepath1 filepath2");
+      System.exit(1);
+    }
+
+    File file1 = new File(args[0]);
+    File file2 = new File(args[1]);
+    if (!file1.exists() || !file2.exists()) {
+      System.out.println("One of " + args[0] + " or " + args[1] + " does not exist.");
+      System.exit(1);
+    }
+
+    Base64.Decoder decdr = Base64.getDecoder();
+    PduFactory factory = new PduFactory();
+    int lineno = 0;
+    boolean goodmatch = true;
+
+    try {
+      BufferedReader reader1 = new BufferedReader(new FileReader(file1));
+      BufferedReader reader2 = new BufferedReader(new FileReader(file2));
+
+      String line1 = reader1.readLine();
+      String line2 = reader2.readLine();
+      lineno++;
+
+      while (line1 != null && line2 != null) {
+        mainblock:
+        {
+          if (line1.equals(line2))
+            break mainblock;
+
+          if (line1.startsWith(COMMENT_MARKER) || line2.startsWith(COMMENT_MARKER))
+            break mainblock;
+
+          String[] sa1 = line1.split(",");
+          String[] sa2 = line2.split(",");
+          if (sa1.length != 2 || sa2.length != 2) {
+            System.err.println("Error: parsing error. ASCII 2-part, comma-separated expected. Lines follow.");
+            System.err.println(line1);
+            System.err.println(line2);
+            System.exit(1);
+          }
+
+          // Forget the time field (first string) -- not part of pdu
+          if (sa1[1].equals(sa2[1]))
+            break mainblock;
+
+          byte[] ba1 = decdr.decode(sa1[1]);
+          byte[] ba2 = decdr.decode(sa2[1]);
+
+          if (ba1.length != ba2.length) {
+            System.out.println("line " + lineno + ": lengths differ. Lines follow.");
+            System.out.println(sa1[1]);
+            System.out.println(sa2[1]);
+            break mainblock;
+          }
+
+          Pdu pdu1 = factory.createPdu(ba1);
+          Pdu pdu2 = factory.createPdu(ba2);
+          if (pdu1.equals(pdu2))  // use generated equals method
+            break mainblock;
+
+          // Try equals ignoring header timestamp
+          pdu1.setTimestamp(pdu2.getTimestamp());
+          if (pdu1.equals(pdu2))
+            break mainblock;
+
+          System.out.println("Pdu inequality:");
+          System.out.println("  Types: " + pdu1.getPduType() + " and " + pdu2.getPduType());
+          System.out.println("");
+          goodmatch = false;
+        } // end mainblock
+
+        line1 = reader1.readLine();
+        line2 = reader2.readLine();
+      }
+
+      System.out.println("End of compare. There were " + (goodmatch ? "no" : "one or more ") + "errors");
+      System.exit(goodmatch ? 0 : 1);
+    }
+    catch (Exception ex) {
+      System.err.println("Exception reading pdu logs: " + ex.getClass().getSimpleName() + ": " + ex.getLocalizedMessage());
+      System.exit(1);
+    }
+  }
+}
diff --git a/src/edu/nps/moves/dis/util/playerrecorder/PduReceiver.java b/src/edu/nps/moves/dis/util/playerrecorder/PduReceiver.java
new file mode 100644
index 0000000000000000000000000000000000000000..9ed8fd8c30fcdba26bd29ff4fc01d2befcaaf836
--- /dev/null
+++ b/src/edu/nps/moves/dis/util/playerrecorder/PduReceiver.java
@@ -0,0 +1,6 @@
+package edu.nps.moves.dis.util.playerrecorder;
+
+public interface PduReceiver
+{
+  void receivePdu(byte[] buff, int len);
+}
diff --git a/src/edu/nps/moves/dis/util/playerrecorder/Player.java b/src/edu/nps/moves/dis/util/playerrecorder/Player.java
new file mode 100644
index 0000000000000000000000000000000000000000..d9d2ec1d73a3d05716b17f95e355a22b6a8d74d2
--- /dev/null
+++ b/src/edu/nps/moves/dis/util/playerrecorder/Player.java
@@ -0,0 +1,181 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package edu.nps.moves.dis.util.playerrecorder;
+
+
+import com.google.common.primitives.Longs;
+
+import java.io.*;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Base64;
+
+import static edu.nps.moves.dis.util.playerrecorder.Recorder.*;
+
+public class Player
+{
+  private Path disLogDirectory;
+  private String ip;
+  private int port;
+
+  public Player(String ip, int port, Path disLogDirectory)
+  {
+    this.disLogDirectory = disLogDirectory;
+    this.ip = ip;
+    this.port = port;
+  }
+
+  private Integer scenarioPduCount = null;
+  private boolean showPduCountsOneTime = false;
+  private int pduCount = 0;
+  private DatagramSocket dsock;
+  private BufferedReader brdr;
+  private Long startNanoTime=null;
+
+  @SuppressWarnings("StatementWithEmptyBody")
+  public void startResume() throws IOException
+  {
+    System.out.println("Replaying DIS logs.");
+    InetAddress addr = InetAddress.getByName(ip);
+
+    FilenameFilter filter = (dir, name) -> name.endsWith(Recorder.DISLOG_FILE_TAIL) && !name.startsWith(".");
+
+    File[] fs = disLogDirectory.toFile().listFiles(filter);
+    if(fs == null)
+      fs = new File[0];
+
+    Arrays.sort(fs,(f1,f2)->{return f1.getName().compareTo(f2.getName());});
+    //Arrays.sort(fs, Comparator.comparing(File::getName));
+
+    dsock = new DatagramSocket();
+    Base64.Decoder decdr = Base64.getDecoder();
+
+    for(File f : fs) {
+      System.out.println("Replaying "+f.getAbsolutePath());
+      brdr = new BufferedReader(new FileReader(f), 1024 * 200); // 200kb buffer
+
+      String line = brdr.readLine();
+      while(line != null) {
+        if(line.length()<=0)
+          ; // blank lines ok
+        else if (line.startsWith(COMMENT_MARKER)) {
+          if(handleComment(line,f)) {
+            // here if we got an end comment
+            break;  // out of read loop
+          }
+        }
+        else {
+
+          String[] sa = line.split(",");
+          if (sa.length != 2) {
+            System.err.println("Error: parsing error.  Line follows.");
+            System.err.println(line);
+            byebye();
+          }
+
+          if (startNanoTime == null)
+            startNanoTime = System.nanoTime();
+
+          byte[] pduTimeBytes = decdr.decode(sa[0]);
+          long pduTimeInterval = Longs.fromByteArray(pduTimeBytes);
+          // This is a relative number in nanoseconds of the time of packet reception minus first packet reception for scenario.
+
+          long targetSimTime = startNanoTime + pduTimeInterval;  // when we should send the packet
+          long now = System.nanoTime();
+          long sleepTime = targetSimTime - now; //System.nanoTime(); // the difference between then and now
+
+          if (sleepTime > 20000000) { // 20 ms //
+            //System.out.println("sim interval = " + pduTimeInterval + ", sleeping for " + sleepTime/1000000l + " ms");
+            sleep(sleepTime/1000000L, (int)(sleepTime % 1000000L));
+          }
+
+          byte[] buffer = decdr.decode(sa[1]);
+          //Pdu pdu = pduFactory.createPdu(buffer);
+          DatagramPacket packet = new DatagramPacket(buffer, buffer.length, addr, port);
+          dsock.send(packet);
+
+          pduCount++;
+          if(scenarioPduCount != null)
+            scenarioPduCount++;
+
+          if(showPduCountsOneTime || pduCount % 5 == 0)
+            showCounts();
+        }
+
+        line = brdr.readLine();
+      }
+      brdr.close();
+    }
+  }
+  private void showCounts()
+  {
+    if(scenarioPduCount != null)
+      System.out.print(pduCount + " " + ++scenarioPduCount+"\r");
+    else
+      System.out.print(pduCount+"\r");
+    showPduCountsOneTime = false;
+  }
+
+  private void byebye() throws IOException
+  {
+    System.out.println("Replay stopped.");
+
+    // @formatter:off
+    try { dsock.close();brdr.close(); } catch (Exception ioex) {System.err.println("IOException closing reader in Player"); }
+    // @formatter:on
+
+    throw new IOException("Dis Replayer parsing error");
+  }
+
+  private boolean handleComment(String s, File f)  //true if we're done
+  {
+    boolean ret=false;
+    if(s.startsWith(START_COMMENT_MARKER)) {
+      //System.out.println();
+      s = s.substring(START_COMMENT_MARKER.length());
+      System.out.println(s+"  ");
+      showPduCountsOneTime = true;  // get the first one in there
+    }
+    else if (s.startsWith(STOP_COMMENT_MARKER)) {
+      showCounts();
+      System.out.println();
+      System.out.println("End of replay from "+f.getName());
+      System.out.println(s.substring(STOP_COMMENT_MARKER.length()));
+
+      scenarioPduCount = 0;
+      startNanoTime=null;
+      ret = true;
+    }
+    return ret;
+  }
+
+  @SuppressWarnings("unused")
+  public void stopPause()
+  {
+
+  }
+  
+  public static void main(String[] args)
+  {
+    try {
+      //new Player("230.0.0.0", 3000, new File("./pdulog").toPath()).startResume();
+      new Player("230.0.0.0", 3000, new File("/Users/mike/NetbeansProjects/open-dis7-java/examples/pdulog").toPath()).startResume();
+    }
+    catch(Exception ex) {
+      ex.printStackTrace();
+    }
+  }
+  private static void sleep(long ms, int ns)
+  {
+    // @formatter:off
+    try { Thread.sleep(ms,ns); } catch (InterruptedException ex) { System.out.println("InterruptedException"); }
+    // @formatter:on
+  }
+}
diff --git a/src/edu/nps/moves/dis/util/playerrecorder/Recorder.java b/src/edu/nps/moves/dis/util/playerrecorder/Recorder.java
new file mode 100644
index 0000000000000000000000000000000000000000..c04862f105ae0a6ddef76d6845fef6db57cd4691
--- /dev/null
+++ b/src/edu/nps/moves/dis/util/playerrecorder/Recorder.java
@@ -0,0 +1,189 @@
+package edu.nps.moves.dis.util.playerrecorder;
+
+import com.google.common.primitives.Longs;
+import edu.nps.moves.dis.Pdu;
+import edu.nps.moves.dis.enumerations.DISPDUType;
+import edu.nps.moves.dis.util.DisNetworking;
+import edu.nps.moves.dis.util.DisNetworking.BuffAndLength;
+import edu.nps.moves.dis.util.PduFactory;
+import org.apache.commons.io.FilenameUtils;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Base64;
+
+public class Recorder implements PduReceiver
+{
+  static String DISLOG_FILE_TAIL = ".dislog";
+
+  public static String COMMENT_MARKER = "!";
+  static String START_COMMENT_MARKER = COMMENT_MARKER + "Begin" + COMMENT_MARKER;
+  static String STOP_COMMENT_MARKER = COMMENT_MARKER + "End" + COMMENT_MARKER;
+
+  private BufferedWriter bwr;
+
+  private File logFile;
+
+  public Recorder(Path outputDir, String filename) throws IOException
+  {
+    logFile = makeFile(outputDir, filename + DISLOG_FILE_TAIL);
+    bwr = new BufferedWriter(new FileWriter(logFile));
+  }
+
+  Long startNanoTime = null;
+  StringBuilder sb = new StringBuilder();
+  Base64.Encoder encdr = Base64.getEncoder();
+  int pduCount = 0;
+  boolean headerWritten = false;
+
+  @Override
+  public void receivePdu(byte[] buff, int len)
+  {
+    //Pdu pdu = makePdu(type,buff,len);
+    long packetRcvNanoTime = System.nanoTime();
+    if (startNanoTime == null)
+      startNanoTime = packetRcvNanoTime;
+
+    byte[] timeAr = Longs.toByteArray(packetRcvNanoTime - startNanoTime);
+    System.out.println("wrote time "+(packetRcvNanoTime - startNanoTime));
+
+    sb.setLength(0);
+    sb.append(encdr.encodeToString(timeAr));
+    sb.append(',');
+    byte[] buffsized = Arrays.copyOf(buff, len);
+    sb.append(encdr.encodeToString(buffsized));
+    try {
+      if (!headerWritten) {
+        writeHeader();
+        headerWritten = true;
+      }
+      bwr.write(sb.toString());
+      bwr.newLine();
+    }
+    catch (IOException ex) {
+      System.err.println("Fatal exception writing DIS log file in Recorder.start()");
+      throw new RuntimeException(ex);
+    }
+    System.out.print(++pduCount + "\r");
+
+    //bwr.flush();
+    sb.setLength(0);
+  }
+
+  public void stopAndClose()
+  {
+    try {
+      writeFooter();
+      bwr.flush();
+      bwr.close();
+      System.out.println("Recorder log file closed");
+    }
+    catch (IOException ex) {
+      System.out.println("IOException closing file: " + ex.getMessage());
+    }
+  }
+
+  private void writeHeader() throws IOException
+  {
+    String template = "Beginning of DIS capture file, %s.";
+    String startComment = String.format(template, logFile.getName());
+    bwr.write(START_COMMENT_MARKER + startComment);
+    bwr.newLine();
+  }
+
+  private void writeFooter() throws IOException
+  {
+    String template = "End of DIS capture file, %s.";
+    String endComment = String.format(template, logFile.getName());
+    bwr.write(STOP_COMMENT_MARKER + endComment);
+    bwr.newLine();
+  }
+
+  private File makeFile(Path outputDir, String filename) throws IOException
+  {
+    String bname = FilenameUtils.getBaseName(filename);
+    String ext = FilenameUtils.getExtension(filename);
+
+    Integer count = null;
+    File f;
+    boolean fileExists;
+    outputDir.toFile().mkdirs();
+    do {
+      String fn = bname + (count == null ? "" : count) + "." + ext;
+      f = new File(outputDir.toFile(), fn);
+      fileExists = f.exists();
+      if (count == null)
+        count = 1;
+      else
+        count++;
+    } while (fileExists);
+    if (!f.createNewFile()) {
+      System.out.println("Cannot create dis log file at " + f.getAbsolutePath());
+      throw new RuntimeException("File creation error");
+    }
+    return f;
+  }
+  
+  /* Example usage */
+  public static void main(String[] args)
+  {
+    PduFactory factory = new PduFactory(); //default appid, country, etc.
+    DisNetworking disnet = new DisNetworking(); // default ip and port
+    
+    Path path = new File("./pdulog").toPath();
+    String filename = "Pdusave";
+    
+    Recorder recorder;
+    try{recorder = new Recorder(path, filename);} catch(IOException ex) {
+      System.err.println("Exception creating recorder: "+ex.getLocalizedMessage());
+      return;
+    }
+    
+    // Start a thread to receive and record pdus
+
+    Thread receiverThrd = new Thread(()->{
+      int count = 1;
+      while(true){
+      try {
+        BuffAndLength blen = disnet.receiveRawPdu();
+        System.out.println(""+ count++ +" Got pdu from DisNetworking");
+        recorder.receivePdu(blen.buff,blen.length);
+      }
+      catch(IOException ex) {
+        System.err.println("Exception receiving Pdu: "+ex.getLocalizedMessage());
+      }
+      }
+    });
+    receiverThrd.setPriority(Thread.NORM_PRIORITY);
+    receiverThrd.setDaemon(true);
+    receiverThrd.start();
+    
+    
+    DISPDUType all[] = DISPDUType.values();
+    Arrays.stream(all).forEach(typ-> {
+      if(typ != DISPDUType.OTHER) {
+        try {
+          Pdu pdu = factory.createPdu(typ);
+          disnet.sendPdu(pdu);
+          sleep(100);
+        }
+        catch(IOException ex) {
+          System.err.println("Exception sending Pdu: "+ex.getLocalizedMessage());
+        }
+      }
+      });
+    sleep(2000);
+    
+    receiverThrd.interrupt();
+    recorder.stopAndClose();
+  }
+  
+  private static void sleep(long ms)
+  {
+    try{Thread.sleep(ms);}catch(InterruptedException ex) {}
+  }
+}