diff --git a/.gitignore b/.gitignore index 797bfcc..73cfb57 100644 --- a/.gitignore +++ b/.gitignore @@ -10,15 +10,13 @@ build/ AppleCommander.preferences *.bas -# Ignoring all disk images -*.dsk -*.po -*.hdv -*.do -*.2mg -*.2img -# But allowing disk images from the unit tests -!lib/ac-api/src/test/resources/disks/* +# Ignoring all disk images at root of project +/*.dsk +/*.po +/*.hdv +/*.do +/*.2mg +/*.2img # Eclipse .classpath diff --git a/DEVELOPER.md b/DEVELOPER.md index 8cd095e..dffbe06 100644 --- a/DEVELOPER.md +++ b/DEVELOPER.md @@ -4,20 +4,45 @@ AppleCommander has switched to using [Gradle](https://gradle.org/) for build and There is still a bunch of ANT related build information around. They no longer apply and "should" get cleaned up over time. +## Structure + +The project is structured as a Gradle multi-project. Independent components have been broken out and each of the SWT targets are independent. + +| Path | Note | +| ---- | ---- | +| `lib/ac-api` | The AppleCommander APIs. These are released via Maven and resused in several projects. | +| `lib/ac-swt-common` | The SWT GUI application. Since SWT targets specific environments with native libraries, the actual applications are in the `app` directories. | +| `app/cli-ac` | The `ac` CLI utility. | +| `app/cli-acx` | The `acx` CLI utility. | +| `app/gui-swt--` | The indepent SWT GUI applications; one project per combination. | + +## Requirements + +With the introduction of the Apple Silicon, AppleCommander switched over to the (relatively new) SWT libraries. With that switch, the SWT libraries now require Java 11. + ## Tests ``` -$ ./gradlew test +./gradlew test + +BUILD SUCCESSFUL in 554ms +19 actionable tasks: 19 up-to-date ``` ## Building ``` -$ ./gradlew clean assemble +./gradlew clean build -BUILD SUCCESSFUL in 2s -6 actionable tasks: 6 executed +BUILD SUCCESSFUL in 7s +104 actionable tasks: 104 executed +``` +## Older notes.. + +Just keeping these for the short-term... + +``` $ tools/retrolambda.sh build/libs/AppleCommander-ac-.jar Converting... Retrolambda 2.5.6 diff --git a/app/cli-acx/src/main/java/io/github/applecommander/acx/Main.java b/app/cli-acx/src/main/java/io/github/applecommander/acx/Main.java index b279d6c..0768c7d 100644 --- a/app/cli-acx/src/main/java/io/github/applecommander/acx/Main.java +++ b/app/cli-acx/src/main/java/io/github/applecommander/acx/Main.java @@ -88,6 +88,7 @@ public class Main { public static void main(String[] args) { CommandLine cmd = new CommandLine(new Main()); cmd.setExecutionExceptionHandler(new PrintExceptionMessageHandler()); + cmd.setCaseInsensitiveEnumValuesAllowed(true); if (args.length == 0) { cmd.usage(System.out); System.exit(1); diff --git a/app/cli-acx/src/main/java/io/github/applecommander/acx/OrderType.java b/app/cli-acx/src/main/java/io/github/applecommander/acx/OrderType.java new file mode 100644 index 0000000..9e66915 --- /dev/null +++ b/app/cli-acx/src/main/java/io/github/applecommander/acx/OrderType.java @@ -0,0 +1,83 @@ +package io.github.applecommander.acx; + +import java.util.function.Function; +import java.util.logging.Logger; + +import com.webcodepro.applecommander.storage.Disk; +import com.webcodepro.applecommander.storage.physical.ByteArrayImageLayout; +import com.webcodepro.applecommander.storage.physical.DosOrder; +import com.webcodepro.applecommander.storage.physical.ImageOrder; +import com.webcodepro.applecommander.storage.physical.NibbleOrder; +import com.webcodepro.applecommander.storage.physical.ProdosOrder; + +public enum OrderType { + DOS(OrderType::createDosImageOrder), + NIBBLE(OrderType::create140kNibbleImageOrder), + PRODOS(OrderType::createProdosImageOrder); + + private static Logger LOG = Logger.getLogger(OrderType.class.getName()); + + private Function createImageOrderFn; + + private OrderType(Function createImageOrderFn) { + this.createImageOrderFn = createImageOrderFn; + } + + public ImageOrder createImageOrder(int size) { + return createImageOrderFn.apply(size); + } + + /** + * At this time, the various DOS disks only support 140K or 800K disks and + * we have to rely on the SystemType to actually evaluate the correct size. + */ + static ImageOrder createDosImageOrder(int size) { + if (size < Disk.APPLE_140KB_DISK) { + LOG.warning("Setting image size to 140KB."); + size = Disk.APPLE_140KB_DISK; + } + else if (size == Disk.APPLE_140KB_DISK) { + // Size is valid; don't warn and don't bump to 800K. + } + else if (size != Disk.APPLE_800KB_DISK) { + LOG.warning("Setting image size to 800KB."); + size = Disk.APPLE_800KB_DISK; + } + ByteArrayImageLayout layout = new ByteArrayImageLayout(new byte[size]); + return new DosOrder(layout); + } + /** + * Nibblized disks are always 140K disks (or ~230K on disk). + */ + static ImageOrder create140kNibbleImageOrder(int size) { + if (size != Disk.APPLE_140KB_NIBBLE_DISK && size != Disk.APPLE_140KB_DISK) { + LOG.warning("Setting image size to 140KB"); + } + ByteArrayImageLayout layout = new ByteArrayImageLayout(new byte[Disk.APPLE_140KB_NIBBLE_DISK]); + return new NibbleOrder(layout); + } + /** + * Lock ProDOS into 140K, 800K, or anything between 800K and 32M. + * This means you _could_ setup a 807KB disk if you wanted. + */ + static ImageOrder createProdosImageOrder(int size) { + if (size < Disk.APPLE_140KB_DISK) { + LOG.warning("Setting image size to 140KB."); + size = Disk.APPLE_140KB_DISK; + } + else if (size == Disk.APPLE_140KB_DISK) { + // Size is valid; don't warn and don't bump to 800K. + } + else if (size < Disk.APPLE_800KB_DISK) { + LOG.warning("Setting image size to 800KB."); + size = Disk.APPLE_800KB_DISK; + } + else if (size > Disk.APPLE_32MB_HARDDISK) { + LOG.warning("Setting image size to 32MB."); + size = Disk.APPLE_32MB_HARDDISK; + } + ByteArrayImageLayout layout = new ByteArrayImageLayout(size); + return new ProdosOrder(layout); + } + +} diff --git a/app/cli-acx/src/main/java/io/github/applecommander/acx/PrintExceptionMessageHandler.java b/app/cli-acx/src/main/java/io/github/applecommander/acx/PrintExceptionMessageHandler.java index cbd824d..d23831a 100644 --- a/app/cli-acx/src/main/java/io/github/applecommander/acx/PrintExceptionMessageHandler.java +++ b/app/cli-acx/src/main/java/io/github/applecommander/acx/PrintExceptionMessageHandler.java @@ -14,8 +14,8 @@ public class PrintExceptionMessageHandler implements IExecutionExceptionHandler ex.printStackTrace(System.err); } else { - // bold red error message - cmd.getErr().println(cmd.getColorScheme().errorText(ex.getMessage())); + // bold red error message (+ "" is to handle null messages) + cmd.getErr().println(cmd.getColorScheme().errorText(ex.getMessage() + "")); } return cmd.getExitCodeExceptionMapper() != null diff --git a/app/cli-acx/src/main/java/io/github/applecommander/acx/SystemType.java b/app/cli-acx/src/main/java/io/github/applecommander/acx/SystemType.java index d4a5948..c99b08d 100644 --- a/app/cli-acx/src/main/java/io/github/applecommander/acx/SystemType.java +++ b/app/cli-acx/src/main/java/io/github/applecommander/acx/SystemType.java @@ -5,60 +5,79 @@ import java.util.function.BiConsumer; import java.util.function.Function; import java.util.logging.Logger; +import com.webcodepro.applecommander.storage.Disk; import com.webcodepro.applecommander.storage.DiskException; import com.webcodepro.applecommander.storage.FileEntry; import com.webcodepro.applecommander.storage.FormattedDisk; import com.webcodepro.applecommander.storage.os.dos33.DosFormatDisk; -import com.webcodepro.applecommander.storage.physical.ByteArrayImageLayout; -import com.webcodepro.applecommander.storage.physical.DosOrder; -import com.webcodepro.applecommander.storage.physical.ImageOrder; -import com.webcodepro.applecommander.storage.physical.ProdosOrder; -import io.github.applecommander.acx.converter.DataSizeConverter; import io.github.applecommander.acx.fileutil.FileUtils; public enum SystemType { - DOS(SystemType::createDosImageOrder, SystemType::copyDosSystemTracks), - OZDOS(SystemType::create800kDosImageOrder, SystemType::copyDosSystemTracks), - UNIDOS(SystemType::create800kDosImageOrder, SystemType::copyDosSystemTracks), - PRODOS(SystemType::createProdosImageOrder, SystemType::copyProdosSystemFiles), - PASCAL(SystemType::createProdosImageOrder, SystemType::copyPascalSystemFiles); + DOS(OrderType.DOS, SystemType::enforce140KbDisk, + SystemType::copyDosSystemTracks), + // OzdosFormatDisk is structured on top of ProDOS blocks in the implementation. + OZDOS(OrderType.PRODOS, SystemType::enforce800KbDisk, + SystemType::copyDosSystemTracks), + // UnidosFormatDisk is structured on top of DOS track/sectors in the implementation. + UNIDOS(OrderType.DOS, SystemType::enforce800KbDisk, + SystemType::copyDosSystemTracks), + PRODOS(OrderType.PRODOS, SystemType::enforce140KbOr800KbUpTo32MbDisk, + SystemType::copyProdosSystemFiles), + PASCAL(OrderType.PRODOS, SystemType::enforce140KbDisk, + SystemType::copyPascalSystemFiles); - private static Logger LOG = Logger.getLogger(SystemType.class.getName()); + static Logger LOG = Logger.getLogger(SystemType.class.getName()); - private Function createImageOrderFn; + private OrderType defaultOrderType; + private Function enforceDiskSizeFn; private BiConsumer copySystemFn; - private SystemType(Function createImageOrderFn, - BiConsumer copySystemFn) { - this.createImageOrderFn = createImageOrderFn; + private SystemType(OrderType defaultOrderType, + Function enforceDiskSizeFn, + BiConsumer copySystemFn) { + this.defaultOrderType = defaultOrderType; + this.enforceDiskSizeFn = enforceDiskSizeFn; this.copySystemFn = copySystemFn; } - public ImageOrder createImageOrder(int size) { - return createImageOrderFn.apply(size); + public OrderType defaultOrderType() { + return defaultOrderType; + } + public int validateSize(int size) { + return enforceDiskSizeFn.apply(size); } public void copySystem(FormattedDisk target, FormattedDisk source) { copySystemFn.accept(target, source); } - - private static ImageOrder createDosImageOrder(int size) { - ByteArrayImageLayout layout = new ByteArrayImageLayout(new byte[size]); - return new DosOrder(layout); - } - private static ImageOrder create800kDosImageOrder(int size) { - if (size != 800 * DataSizeConverter.KB) { - LOG.warning("Setting image size to 800KB."); - } - ByteArrayImageLayout layout = new ByteArrayImageLayout(new byte[800 * DataSizeConverter.KB]); - return new DosOrder(layout); - } - private static ImageOrder createProdosImageOrder(int size) { - ByteArrayImageLayout layout = new ByteArrayImageLayout(size); - return new ProdosOrder(layout); - } - private static void copyDosSystemTracks(FormattedDisk targetDisk, FormattedDisk source) { + static int enforce140KbDisk(int size) { + if (size != Disk.APPLE_140KB_DISK) { + LOG.warning("Setting image size to 140KB"); + } + return Disk.APPLE_140KB_DISK; + } + static int enforce800KbDisk(int size) { + if (size != Disk.APPLE_800KB_DISK) { + LOG.warning("Setting image size to 800KB."); + } + return Disk.APPLE_800KB_DISK; + } + static int enforce140KbOr800KbUpTo32MbDisk(int size) { + if (size <= Disk.APPLE_140KB_DISK) { + return enforce140KbDisk(size); + } + if (size <= Disk.APPLE_800KB_DISK) { + return enforce800KbDisk(size); + } + if (size > Disk.APPLE_32MB_HARDDISK) { + LOG.warning("Setting image size to 32MB."); + return Disk.APPLE_32MB_HARDDISK; + } + return size; + } + + static void copyDosSystemTracks(FormattedDisk targetDisk, FormattedDisk source) { DosFormatDisk target = (DosFormatDisk)targetDisk; // FIXME messing with the VTOC should be handled elsewhere byte[] vtoc = source.readSector(DosFormatDisk.CATALOG_TRACK, DosFormatDisk.VTOC_SECTOR); @@ -71,7 +90,7 @@ public enum SystemType { } } } - private static void copyProdosSystemFiles(FormattedDisk target, FormattedDisk source) { + static void copyProdosSystemFiles(FormattedDisk target, FormattedDisk source) { // We need to explicitly fix the boot block target.writeBlock(0, source.readBlock(0)); target.writeBlock(1, source.readBlock(1)); @@ -86,7 +105,7 @@ public enum SystemType { throw new RuntimeException(e); } } - private static void copyPascalSystemFiles(FormattedDisk target, FormattedDisk source) { + static void copyPascalSystemFiles(FormattedDisk target, FormattedDisk source) { // We need to explicitly fix the boot block target.writeBlock(0, source.readBlock(0)); target.writeBlock(1, source.readBlock(1)); diff --git a/app/cli-acx/src/main/java/io/github/applecommander/acx/command/CreateDiskCommand.java b/app/cli-acx/src/main/java/io/github/applecommander/acx/command/CreateDiskCommand.java index a5db4c9..6b5620e 100644 --- a/app/cli-acx/src/main/java/io/github/applecommander/acx/command/CreateDiskCommand.java +++ b/app/cli-acx/src/main/java/io/github/applecommander/acx/command/CreateDiskCommand.java @@ -1,5 +1,6 @@ package io.github.applecommander.acx.command; +import java.util.Optional; import java.util.logging.Logger; import com.webcodepro.applecommander.storage.Disk; @@ -11,10 +12,11 @@ import com.webcodepro.applecommander.storage.os.pascal.PascalFormatDisk; import com.webcodepro.applecommander.storage.os.prodos.ProdosFormatDisk; import com.webcodepro.applecommander.storage.physical.ImageOrder; +import io.github.applecommander.acx.OrderType; import io.github.applecommander.acx.SystemType; import io.github.applecommander.acx.base.ReusableCommandOptions; import io.github.applecommander.acx.converter.DataSizeConverter; -import io.github.applecommander.acx.converter.SystemTypeConverter; +import picocli.CommandLine.ArgGroup; import picocli.CommandLine.Command; import picocli.CommandLine.Option; @@ -27,12 +29,14 @@ public class CreateDiskCommand extends ReusableCommandOptions { defaultValue = "${ACX_DISK_NAME}") private String imageName; - @Option(names = { "-t", "--type" }, required = true, converter = SystemTypeConverter.class, - description = "Select system type (DOS, ProDOS, Pascal.") - private SystemType type; + @ArgGroup(multiplicity = "1", heading = "%nOperating System Selection:%n") + private SystemSelection systemSelection; + + @ArgGroup(heading = "%nDisk Sector Ordering Selection:%n") + private OrderSelection orderSelection = new OrderSelection(); @Option(names = { "-s", "--size" }, defaultValue = "140kb", converter = DataSizeConverter.class, - description = "Select disk size (140K, 800K, 10M).") + description = "Select disk size (examples: 140K, 800K, 10M).") private int size; @Option(names = { "-f", "--format" }, @@ -45,11 +49,20 @@ public class CreateDiskCommand extends ReusableCommandOptions { @Override public int handleCommand() throws Exception { - LOG.info(() -> String.format("Creating %s image of type %s.", DataSizeConverter.format(size), type)); + SystemType systemType = systemSelection.get(); - ImageOrder order = type.createImageOrder(size); + // This allows a defaulted OrderType to be adjusted based on SystemType. + OrderType actualOrderType = orderSelection.get().orElse(systemType.defaultOrderType()); + + // Size is constrained in DOS and Pascal + int correctedSize = systemType.validateSize(size); + + LOG.info(() -> String.format("Creating %s image of type %s (%s).", + DataSizeConverter.format(correctedSize), systemType, actualOrderType)); + + ImageOrder order = actualOrderType.createImageOrder(correctedSize); FormattedDisk[] disks = null; - switch (type) { + switch (systemType) { case DOS: disks = DosFormatDisk.create(imageName, order); break; @@ -69,11 +82,61 @@ public class CreateDiskCommand extends ReusableCommandOptions { if (formatSource != null) { Disk systemSource = new Disk(formatSource); - type.copySystem(disks[0], systemSource.getFormattedDisks()[0]); + systemType.copySystem(disks[0], systemSource.getFormattedDisks()[0]); } saveDisk(disks[0]); return 0; } + + private static class SystemSelection { + private SystemType systemType; + + public SystemType get() { + return systemType; + } + + @Option(names = "--dos", description = "DOS formatted disk.") + public void selectDos(boolean flag) { + systemType = SystemType.DOS; + } + @Option(names = "--ozdos", description = "OzDOS 800K formatted disk.") + public void selectOzdos(boolean flag) { + systemType = SystemType.OZDOS; + } + @Option(names = "--unidos", description = "UniDOS 800K formatted disk.") + public void selectUnidos(boolean flag) { + systemType = SystemType.UNIDOS; + } + @Option(names = "--pascal", description = "Pascal formatted disk.") + public void selectPascal(boolean flag) { + systemType = SystemType.PASCAL; + } + @Option(names = "--prodos", description = "ProDOS formatted disk.") + public void selectProdos(boolean flag) { + systemType = SystemType.PRODOS; + } + } + + private static class OrderSelection { + private Optional orderType = Optional.empty(); + + public Optional get() { + return orderType; + } + + @Option(names = { "--dos-order" }, description = "DOS ordered sectors.") + public void selectDosOrder(boolean flag) { + orderType = Optional.of(OrderType.DOS); + } + @Option(names = { "--nibble-order" }, description = "DOS ordered, nibble encoded sectors.") + public void selectNibbleOrder(boolean flag) { + orderType = Optional.of(OrderType.NIBBLE); + } + @Option(names = { "--prodos-order" }, description = "ProDOS ordered sectors/blocks.") + public void selectProdosOrder(boolean flag) { + orderType = Optional.of(OrderType.PRODOS); + } + } } diff --git a/app/cli-acx/src/test/java/io/github/applecommander/acx/OrderTypeTest.java b/app/cli-acx/src/test/java/io/github/applecommander/acx/OrderTypeTest.java new file mode 100644 index 0000000..6bce990 --- /dev/null +++ b/app/cli-acx/src/test/java/io/github/applecommander/acx/OrderTypeTest.java @@ -0,0 +1,35 @@ +package io.github.applecommander.acx; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.webcodepro.applecommander.storage.Disk; + +public class OrderTypeTest { + @Test + public void testCreateDosImageOrder() { + assertEquals(Disk.APPLE_140KB_DISK, OrderType.createDosImageOrder(0).getPhysicalSize()); + assertEquals(Disk.APPLE_140KB_DISK, OrderType.createDosImageOrder(Disk.APPLE_140KB_DISK).getPhysicalSize()); + assertEquals(Disk.APPLE_800KB_DISK, OrderType.createDosImageOrder(Disk.APPLE_140KB_DISK+1).getPhysicalSize()); + assertEquals(Disk.APPLE_800KB_DISK, OrderType.createDosImageOrder(Disk.APPLE_800KB_DISK).getPhysicalSize()); + assertEquals(Disk.APPLE_800KB_DISK, OrderType.createDosImageOrder(Disk.APPLE_800KB_DISK+1).getPhysicalSize()); + } + + @Test + public void testCreate140kNibbleImageOrder() { + assertEquals(Disk.APPLE_140KB_NIBBLE_DISK, OrderType.create140kNibbleImageOrder(0).getPhysicalSize()); + assertEquals(Disk.APPLE_140KB_NIBBLE_DISK, OrderType.create140kNibbleImageOrder(Disk.APPLE_140KB_DISK).getPhysicalSize()); + assertEquals(Disk.APPLE_140KB_NIBBLE_DISK, OrderType.create140kNibbleImageOrder(Disk.APPLE_140KB_DISK+1).getPhysicalSize()); + } + + @Test + public void testCreateProdosImageOrder() { + assertEquals(Disk.APPLE_140KB_DISK, OrderType.createProdosImageOrder(0).getPhysicalSize()); + assertEquals(Disk.APPLE_140KB_DISK, OrderType.createProdosImageOrder(Disk.APPLE_140KB_DISK).getPhysicalSize()); + assertEquals(Disk.APPLE_800KB_DISK, OrderType.createProdosImageOrder(Disk.APPLE_140KB_DISK+1).getPhysicalSize()); + assertEquals(Disk.APPLE_800KB_DISK, OrderType.createProdosImageOrder(Disk.APPLE_800KB_DISK).getPhysicalSize()); + assertEquals(Disk.APPLE_800KB_DISK+1, OrderType.createProdosImageOrder(Disk.APPLE_800KB_DISK+1).getPhysicalSize()); + assertEquals(Disk.APPLE_10MB_HARDDISK, OrderType.createProdosImageOrder(Disk.APPLE_10MB_HARDDISK).getPhysicalSize()); + } +} diff --git a/app/cli-acx/src/test/java/io/github/applecommander/acx/SystemTypeTest.java b/app/cli-acx/src/test/java/io/github/applecommander/acx/SystemTypeTest.java new file mode 100644 index 0000000..19ca985 --- /dev/null +++ b/app/cli-acx/src/test/java/io/github/applecommander/acx/SystemTypeTest.java @@ -0,0 +1,33 @@ +package io.github.applecommander.acx; + +import org.junit.Test; + +import static org.junit.Assert.*; +import com.webcodepro.applecommander.storage.Disk; + +public class SystemTypeTest { + @Test + public void testEnforce140KbDisk() { + assertEquals(Disk.APPLE_140KB_DISK, SystemType.enforce140KbDisk(0)); + assertEquals(Disk.APPLE_140KB_DISK, SystemType.enforce140KbDisk(Disk.APPLE_140KB_DISK)); + assertEquals(Disk.APPLE_140KB_DISK, SystemType.enforce140KbDisk(Disk.APPLE_800KB_DISK)); + } + + @Test + public void testEnforce800KbDisk() { + assertEquals(Disk.APPLE_800KB_DISK, SystemType.enforce800KbDisk(0)); + assertEquals(Disk.APPLE_800KB_DISK, SystemType.enforce800KbDisk(Disk.APPLE_800KB_DISK)); + assertEquals(Disk.APPLE_800KB_DISK, SystemType.enforce800KbDisk(Disk.APPLE_32MB_HARDDISK)); + } + + @Test + public void testEnforce140KbOr800KbUpTo32MbDisk() { + assertEquals(Disk.APPLE_140KB_DISK, SystemType.enforce140KbOr800KbUpTo32MbDisk(0)); + assertEquals(Disk.APPLE_140KB_DISK, SystemType.enforce140KbOr800KbUpTo32MbDisk(Disk.APPLE_140KB_DISK)); + assertEquals(Disk.APPLE_800KB_DISK, SystemType.enforce140KbOr800KbUpTo32MbDisk(Disk.APPLE_140KB_DISK+1)); + assertEquals(Disk.APPLE_800KB_DISK, SystemType.enforce140KbOr800KbUpTo32MbDisk(Disk.APPLE_800KB_DISK)); + assertEquals(Disk.APPLE_800KB_DISK+1, SystemType.enforce140KbOr800KbUpTo32MbDisk(Disk.APPLE_800KB_DISK+1)); + assertEquals(Disk.APPLE_32MB_HARDDISK, SystemType.enforce140KbOr800KbUpTo32MbDisk(Disk.APPLE_32MB_HARDDISK)); + assertEquals(Disk.APPLE_32MB_HARDDISK, SystemType.enforce140KbOr800KbUpTo32MbDisk(Integer.MAX_VALUE)); + } +} diff --git a/app/cli-acx/src/test/resources/disks/MERLIN8PRO1.DSK b/app/cli-acx/src/test/resources/disks/MERLIN8PRO1.DSK new file mode 100644 index 0000000..4131b05 Binary files /dev/null and b/app/cli-acx/src/test/resources/disks/MERLIN8PRO1.DSK differ diff --git a/app/cli-acx/src/test/resources/disks/UniDOS_3.3.dsk b/app/cli-acx/src/test/resources/disks/UniDOS_3.3.dsk new file mode 100644 index 0000000..02e4acf Binary files /dev/null and b/app/cli-acx/src/test/resources/disks/UniDOS_3.3.dsk differ