diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json
new file mode 100644
index 0000000000000000000000000000000000000000..cea4d3f4e0eea515bf71ca8cef4037d5fd8282ba
--- /dev/null
+++ b/.vscode/c_cpp_properties.json
@@ -0,0 +1,18 @@
+{
+  "configurations": [
+    {
+      "name": "windows-gcc-x64",
+      "includePath": [
+        "${workspaceFolder}/**"
+      ],
+      "compilerPath": "gcc",
+      "cStandard": "${default}",
+      "cppStandard": "${default}",
+      "intelliSenseMode": "windows-gcc-x64",
+      "compilerArgs": [
+        ""
+      ]
+    }
+  ],
+  "version": 4
+}
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000000000000000000000000000000000000..2d04a8e47410964b417596ecec7d57f86e759d8a
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,24 @@
+{
+  "version": "0.2.0",
+  "configurations": [
+    {
+      "name": "C/C++ Runner: Debug Session",
+      "type": "cppdbg",
+      "request": "launch",
+      "args": [],
+      "stopAtEntry": false,
+      "externalConsole": true,
+      "cwd": "c:/Users/ADMIN/Desktop/cs283/cs283",
+      "program": "c:/Users/ADMIN/Desktop/cs283/cs283/build/Debug/outDebug",
+      "MIMode": "gdb",
+      "miDebuggerPath": "gdb",
+      "setupCommands": [
+        {
+          "description": "Enable pretty-printing for gdb",
+          "text": "-enable-pretty-printing",
+          "ignoreFailures": true
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000000000000000000000000000000000000..bb879da5a0774e5e3a4e5e90dba7a0770370c0f7
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,59 @@
+{
+  "C_Cpp_Runner.cCompilerPath": "gcc",
+  "C_Cpp_Runner.cppCompilerPath": "g++",
+  "C_Cpp_Runner.debuggerPath": "gdb",
+  "C_Cpp_Runner.cStandard": "",
+  "C_Cpp_Runner.cppStandard": "",
+  "C_Cpp_Runner.msvcBatchPath": "C:/Program Files/Microsoft Visual Studio/VR_NR/Community/VC/Auxiliary/Build/vcvarsall.bat",
+  "C_Cpp_Runner.useMsvc": false,
+  "C_Cpp_Runner.warnings": [
+    "-Wall",
+    "-Wextra",
+    "-Wpedantic",
+    "-Wshadow",
+    "-Wformat=2",
+    "-Wcast-align",
+    "-Wconversion",
+    "-Wsign-conversion",
+    "-Wnull-dereference"
+  ],
+  "C_Cpp_Runner.msvcWarnings": [
+    "/W4",
+    "/permissive-",
+    "/w14242",
+    "/w14287",
+    "/w14296",
+    "/w14311",
+    "/w14826",
+    "/w44062",
+    "/w44242",
+    "/w14905",
+    "/w14906",
+    "/w14263",
+    "/w44265",
+    "/w14928"
+  ],
+  "C_Cpp_Runner.enableWarnings": true,
+  "C_Cpp_Runner.warningsAsError": false,
+  "C_Cpp_Runner.compilerArgs": [],
+  "C_Cpp_Runner.linkerArgs": [],
+  "C_Cpp_Runner.includePaths": [],
+  "C_Cpp_Runner.includeSearch": [
+    "*",
+    "**/*"
+  ],
+  "C_Cpp_Runner.excludeSearch": [
+    "**/build",
+    "**/build/**",
+    "**/.*",
+    "**/.*/**",
+    "**/.vscode",
+    "**/.vscode/**"
+  ],
+  "C_Cpp_Runner.useAddressSanitizer": false,
+  "C_Cpp_Runner.useUndefinedSanitizer": false,
+  "C_Cpp_Runner.useLeakSanitizer": false,
+  "C_Cpp_Runner.showCompilationTime": false,
+  "C_Cpp_Runner.useLinkTimeOptimization": false,
+  "C_Cpp_Runner.msvcSecureNoWarnings": false
+}
\ No newline at end of file
diff --git a/A3/dsh_cli.c b/A3/dsh_cli.c
new file mode 100644
index 0000000000000000000000000000000000000000..092ed1f2f9328b7f4493fd4080b4c2bcffe7e789
--- /dev/null
+++ b/A3/dsh_cli.c
@@ -0,0 +1,134 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "dshlib.h"
+
+/*
+ * trim_whitespace:
+ *   Removes leading and trailing whitespace from a string.
+ *   This function modifies the string in-place and returns a pointer to the trimmed string.
+ */
+static char *trim_whitespace(char *str)
+{
+    char *end;
+    // Trim leading whitespace.
+    while (*str && isspace((unsigned char)*str))
+        str++;
+    if (*str == '\0') // All spaces?
+        return str;
+    // Trim trailing whitespace.
+    end = str + strlen(str) - 1;
+    while (end > str && isspace((unsigned char)*end))
+        end--;
+    // Write new null terminator.
+    *(end + 1) = '\0';
+    return str;
+}
+
+int main(void)
+{
+    /* Buffer for full command line input.
+       SH_CMD_MAX is defined as EXE_MAX + ARG_MAX */
+    char cmd_buff[SH_CMD_MAX];
+    command_list_t clist;
+    int rc;
+
+    while (1)
+    {
+        /* Print the prompt */
+        printf("%s", SH_PROMPT);
+
+        /* Read one line of input. Using sizeof(cmd_buff) prevents overflow. */
+        if (fgets(cmd_buff, sizeof(cmd_buff), stdin) == NULL)
+        {
+            printf("\n");
+            break;
+        }
+
+        /* Remove the trailing newline */
+        cmd_buff[strcspn(cmd_buff, "\n")] = '\0';
+
+        /* Trim whitespace for built-in command checks */
+        char *input = trim_whitespace(cmd_buff);
+
+        /* Check for the built-in exit command */
+        if (strcmp(input, EXIT_CMD) == 0)
+        {
+            exit(0);
+        }
+
+        /* Extra Credit: If the user types "dragon", print the Drexel dragon ASCII art */
+        if (strcmp(input, "dragon") == 0)
+        {
+            printf("                                                                        @%%%%                        \n"
+                   "                                                                     %%%%%%                          \n"
+                   "                                                                    %%%%%%                           \n"
+                   "                                                                 % %%%%%%%           @               \n"
+                   "                                                                %%%%%%%%%%        %%%%%%%            \n"
+                   "                                       %%%%%%%  %%%%@         %%%%%%%%%%%%@    %%%%%%  @%%%%         \n"
+                   "                                  %%%%%%%%%%%%%%%%%%%%%%      %%%%%%%%%%%%%%%%%%%%%%%%%%%%           \n"
+                   "                                %%%%%%%%%%%%%%%%%%%%%%%%%%   %%%%%%%%%%%% %%%%%%%%%%%%%%%            \n"
+                   "                               %%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%     %%%             \n"
+                   "                             %%%%%%%%%%%%%%%%%%%%%%%%%%%%@ @%%%%%%%%%%%%%%%%%%        %%             \n"
+                   "                            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%                 \n"
+                   "                            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%               \n"
+                   "                            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%%@               \n"
+                   "      %%%%%%%%@           %%%%%%%%%%%%%%%%        %%%%%%%%%%%%%%%%%%%%%%%%%%      %%                 \n"
+                   "    %%%%%%%%%%%%%         %%@%%%%%%%%%%%%           %%%%%%%%%%% %%%%%%%%%%%%      @%                 \n"
+                   "  %%%%%%%%%%   %%%        %%%%%%%%%%%%%%            %%%%%%%%%%%%%%%%%%%%%%%%                         \n"
+                   " %%%%%%%%%       %         %%%%%%%%%%%%%             %%%%%%%%%%%%@%%%%%%%%%%%                        \n"
+                   "%%%%%%%%%@                % %%%%%%%%%%%%%            @%%%%%%%%%%%%%%%%%%%%%%%%%                      \n"
+                   "%%%%%%%%@                 %%@%%%%%%%%%%%%            @%%%%%%%%%%%%%%%%%%%%%%%%%%%%                   \n"
+                   "%%%%%%%@                   %%%%%%%%%%%%%%%           %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%               \n"
+                   "%%%%%%%%%%                  %%%%%%%%%%%%%%%          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%      %%%%   \n"
+                   "%%%%%%%%%@                   @%%%%%%%%%%%%%%         %%%%%%%%%%%%@ %%%% %%%%%%%%%%%%%%%%%   %%%%%%%% \n"
+                   "%%%%%%%%%%                  %%%%%%%%%%%%%%%%%        %%%%%%%%%%%%%      %%%%%%%%%%%%%%%%%% %%%%%%%%% \n"
+                   "%%%%%%%%%@%%@                %%%%%%%%%%%%%%%%@       %%%%%%%%%%%%%%     %%%%%%%%%%%%%%%%%%%%%%%%  %% \n"
+                   " %%%%%%%%%%                  % %%%%%%%%%%%%%%@        %%%%%%%%%%%%%%   %%%%%%%%%%%%%%%%%%%%%%%%%% %% \n"
+                   "  %%%%%%%%%%%%  @           %%%%%%%%%%%%%%%%%%        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %%%  \n"
+                   "   %%%%%%%%%%%%% %%  %  %@ %%%%%%%%%%%%%%%%%%          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    %%%  \n"
+                   "    %%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%           @%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    %%%%%%%  \n"
+                   "     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%              %%%%%%%%%%%%%%%%%%%%%%%%%%%%        %%%    \n"
+                   "      @%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                  %%%%%%%%%%%%%%%%%%%%%%%%%                \n"
+                   "        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                      %%%%%%%%%%%%%%%%%%%  %%%%%%%           \n"
+                   "           %%%%%%%%%%%%%%%%%%%%%%%%%%                           %%%%%%%%%%%%%%%  @%%%%%%%%%          \n"
+                   "              %%%%%%%%%%%%%%%%%%%%           @%@%                  @%%%%%%%%%%%%%%%%%%   %%%         \n"
+                   "                  %%%%%%%%%%%%%%%        %%%%%%%%%%                    %%%%%%%%%%%%%%%    %          \n"
+                   "                %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                      %%%%%%%%%%%%%%             \n"
+                   "                %%%%%%%%%%%%%%%%%%%%%%%%%%  %%%% %%%                      %%%%%%%%%%  %%%@           \n"
+                   "                     %%%%%%%%%%%%%%%%%%% %%%%%% %%                          %%%%%%%%%%%%%@           \n"
+                   "                                                                                 %%%%%%%@            \n");
+            continue;
+        }
+
+        /* Parse the input into a command list */
+        rc = build_cmd_list(cmd_buff, &clist);
+
+        if (rc == WARN_NO_CMDS)
+        {
+            printf("%s", CMD_WARN_NO_CMD);
+        }
+        else if (rc == ERR_TOO_MANY_COMMANDS)
+        {
+            /* Use the provided constant for maximum commands */
+            printf(CMD_ERR_PIPE_LIMIT, CMD_MAX);
+        }
+        else if (rc == ERR_CMD_OR_ARGS_TOO_BIG)
+        {
+            printf("error: command or arguments too big\n");
+        }
+        else if (rc == OK)
+        {
+            printf(CMD_OK_HEADER, clist.num);
+            for (int i = 0; i < clist.num; i++)
+            {
+                if (strlen(clist.commands[i].args) == 0)
+                    printf("<%d> %s\n", i + 1, clist.commands[i].exe);
+                else
+                    printf("<%d> %s [%s]\n", i + 1, clist.commands[i].exe, clist.commands[i].args);
+            }
+        }
+    }
+    return 0;
+}
diff --git a/A3/dshlib.c b/A3/dshlib.c
new file mode 100644
index 0000000000000000000000000000000000000000..33cfe5179fe66ffe3cd2296d1f2d03786d990674
--- /dev/null
+++ b/A3/dshlib.c
@@ -0,0 +1,130 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "dshlib.h"
+
+/*
+ * Helper function: trim leading and trailing whitespace in a string.
+ * This function modifies the string in place and returns a pointer to the trimmed string.
+ */
+static char *trim_whitespace(char *str)
+{
+    char *end;
+    // Trim leading space.
+    while (*str && isspace((unsigned char)*str))
+        str++;
+    if (*str == '\0') // All spaces?
+        return str;
+    // Trim trailing space.
+    end = str + strlen(str) - 1;
+    while (end > str && isspace((unsigned char)*end))
+        end--;
+    // Write new null terminator.
+    *(end + 1) = '\0';
+    return str;
+}
+
+/*
+ *  build_cmd_list
+ *    cmd_line:     the command line from the user
+ *    clist *:      pointer to clist structure to be populated
+ *
+ *  This function builds the command_list_t structure passed by the caller
+ *  It does this by first splitting the cmd_line into commands by spltting
+ *  the string based on any pipe characters '|'.  It then traverses each
+ *  command.  For each command (a substring of cmd_line), it then parses
+ *  that command by taking the first token as the executable name, and
+ *  then the remaining tokens as the arguments.
+ *
+ *  NOTE your implementation should be able to handle properly removing
+ *  leading and trailing spaces!
+ *
+ *  errors returned:
+ *
+ *    OK:                      No Error
+ *    ERR_TOO_MANY_COMMANDS:   There is a limit of CMD_MAX (see dshlib.h)
+ *                             commands.
+ *    ERR_CMD_OR_ARGS_TOO_BIG: One of the commands provided by the user
+ *                             was larger than allowed, either the
+ *                             executable name, or the arg string.
+ *
+ *  Standard Library Functions You Might Want To Consider Using
+ *      memset(), strcmp(), strcpy(), strtok(), strlen(), strchr()
+ */
+
+int build_cmd_list(char *cmd_line, command_list_t *clist)
+{
+    /* Initialize the command list. */
+    clist->num = 0;
+
+    /* Trim the entire input line first. */
+    char *line_trimmed = trim_whitespace(cmd_line);
+    if (strlen(line_trimmed) == 0)
+        return WARN_NO_CMDS;
+
+    char *saveptr1;
+    /* Split the command line on the pipe '|' character.
+       Note: PIPE_STRING is defined as "|" in dshlib.h. */
+    char *cmd_token = strtok_r(cmd_line, PIPE_STRING, &saveptr1);
+    while (cmd_token != NULL)
+    {
+        /* Trim whitespace from this command token. */
+        char *command_str = trim_whitespace(cmd_token);
+        /* Only process non-empty commands. */
+        if (strlen(command_str) > 0)
+        {
+            if (clist->num >= CMD_MAX)
+                return ERR_TOO_MANY_COMMANDS;
+
+            command_t *cmd = &clist->commands[clist->num];
+            /* Clear the command fields */
+            memset(cmd->exe, 0, EXE_MAX);
+            memset(cmd->args, 0, ARG_MAX);
+
+            char *saveptr2;
+            /* Tokenize the command by spaces.
+               The first token is the executable. */
+            char *token = strtok_r(command_str, " ", &saveptr2);
+            if (token == NULL)
+            {
+                /* No tokens found; skip to the next command. */
+                cmd_token = strtok_r(NULL, PIPE_STRING, &saveptr1);
+                continue;
+            }
+            /* Check the executable length. */
+            if (strlen(token) >= EXE_MAX)
+                return ERR_CMD_OR_ARGS_TOO_BIG;
+            strcpy(cmd->exe, token);
+
+            /* The remaining tokens (if any) are the arguments.
+               We rebuild them as a single string (tokens separated by a space). */
+            char args_buffer[ARG_MAX] = "";
+            int first_arg = 1;
+            token = strtok_r(NULL, " ", &saveptr2);
+            while (token != NULL)
+            {
+                if (!first_arg)
+                {
+                    if (strlen(args_buffer) + 1 >= ARG_MAX)
+                        return ERR_CMD_OR_ARGS_TOO_BIG;
+                    strcat(args_buffer, " ");
+                }
+                if (strlen(args_buffer) + strlen(token) >= ARG_MAX)
+                    return ERR_CMD_OR_ARGS_TOO_BIG;
+                strcat(args_buffer, token);
+                first_arg = 0;
+                token = strtok_r(NULL, " ", &saveptr2);
+            }
+            strcpy(cmd->args, args_buffer);
+            clist->num++;
+        }
+        cmd_token = strtok_r(NULL, PIPE_STRING, &saveptr1);
+    }
+
+    if (clist->num == 0)
+        return WARN_NO_CMDS;
+
+    return OK;
+}
\ No newline at end of file
diff --git a/A3/dshlib.h b/A3/dshlib.h
new file mode 100644
index 0000000000000000000000000000000000000000..1353bbd3ba39a4099cdf58ab8f8827e2d3e4e5aa
--- /dev/null
+++ b/A3/dshlib.h
@@ -0,0 +1,50 @@
+#ifndef __DSHLIB_H__
+#define __DSHLIB_H__
+
+// Constants for command structure sizes
+#define EXE_MAX 64
+#define ARG_MAX 256
+#define CMD_MAX 8
+// Longest command that can be read from the shell
+#define SH_CMD_MAX EXE_MAX + ARG_MAX
+
+typedef struct command
+{
+    char exe[EXE_MAX];
+    char args[ARG_MAX];
+} command_t;
+
+typedef struct command_list
+{
+    int num;
+    command_t commands[CMD_MAX];
+} command_list_t;
+
+// Special character #defines
+#define SPACE_CHAR ' '
+#define PIPE_CHAR '|'
+#define PIPE_STRING "|"
+
+#define SH_PROMPT "dsh> "
+#define EXIT_CMD "exit"
+
+// Standard Return Codes
+#define OK 0
+#define WARN_NO_CMDS -1
+#define ERR_TOO_MANY_COMMANDS -2
+#define ERR_CMD_OR_ARGS_TOO_BIG -3
+
+// starter code
+#define M_NOT_IMPL "The requested operation is not implemented yet!\n"
+#define EXIT_NOT_IMPL 3
+#define NOT_IMPLEMENTED_YET 0
+
+// prototypes
+int build_cmd_list(char *cmd_line, command_list_t *clist);
+
+// output constants
+#define CMD_OK_HEADER "PARSED COMMAND LINE - TOTAL COMMANDS %d\n"
+#define CMD_WARN_NO_CMD "warning: no commands provided\n"
+#define CMD_ERR_PIPE_LIMIT "error: piping limited to %d commands\n"
+
+#endif
\ No newline at end of file
diff --git a/A3/makefile b/A3/makefile
new file mode 100644
index 0000000000000000000000000000000000000000..9d20e5b5c474c8217fcc26b24b9a795b4b1a8127
--- /dev/null
+++ b/A3/makefile
@@ -0,0 +1,27 @@
+# Compiler settings
+CC = gcc
+CFLAGS = -Wall -Wextra -g
+
+# Target executable name
+TARGET = dsh
+
+# Find all source and header files
+SRCS = $(wildcard *.c)
+HDRS = $(wildcard *.h)
+
+# Default target
+all: $(TARGET)
+
+# Compile source to executable
+$(TARGET): $(SRCS) $(HDRS)
+	$(CC) $(CFLAGS) -o $(TARGET) $(SRCS)
+
+# Clean up build files
+clean:
+	rm -f $(TARGET)
+
+test:
+	./test.sh
+
+# Phony targets
+.PHONY: all clean
\ No newline at end of file
diff --git a/A3/questions.md b/A3/questions.md
new file mode 100644
index 0000000000000000000000000000000000000000..46599817906265ed9315b46547bc84071d3d7029
--- /dev/null
+++ b/A3/questions.md
@@ -0,0 +1,30 @@
+1. In this assignment I suggested you use `fgets()` to get user input in the main while loop. Why is `fgets()` a good choice for this application?
+
+    > **Answer**:  I think fgets() reads an entire line safely, including spaces, and it stops at a newline or EOF, which fits perfectly for interactive shell input without risking buffer overflows.
+
+2. You needed to use `malloc()` to allocte memory for `cmd_buff` in `dsh_cli.c`. Can you explain why you needed to do that, instead of allocating a fixed-size array?
+
+    > **Answer**:  I use malloc() because it allows for dynamic allocation so we can adjust the buffer size if needed. With a fixed-size array, we might run into limitations or waste memory if the commands are smaller than expected.
+
+
+3. In `dshlib.c`, the function `build_cmd_list(`)` must trim leading and trailing spaces from each command before storing it. Why is this necessary? If we didn't trim spaces, what kind of issues might arise when executing commands in our shell?
+
+    > **Answer**:  I think trimming is necessary to remove unwanted spaces that could cause misinterpretation of commands. Without trimming, extra spaces might make the shell try to execute an invalid command name or pass empty arguments.
+
+4. For this question you need to do some research on STDIN, STDOUT, and STDERR in Linux. We've learned this week that shells are "robust brokers of input and output". Google _"linux shell stdin stdout stderr explained"_ to get started.
+
+- One topic you should have found information on is "redirection". Please provide at least 3 redirection examples that we should implement in our custom shell, and explain what challenges we might have implementing them.
+
+    > **Answer**:  Redirection Examples: command < input.txt — I think the challenge here is correctly opening the file and handling errors if it doesn’t exist. command > output.txt — This requires ensuring the file is created or truncated, and dealing with permission issues. command >> output.txt — Appending adds complexity in managing file pointers and ensuring data is added correctly.
+
+- You should have also learned about "pipes". Redirection and piping both involve controlling input and output in the shell, but they serve different purposes. Explain the key differences between redirection and piping.
+
+    > **Answer**:  Redirection involves rerouting a command’s input or output to or from a file. For example, using < to take input from a file or > to send output to a file. Piping, on the other hand, connects the STDOUT of one command directly to the STDIN of another command using the | symbol. While redirection is about interfacing with persistent storage (files), piping is about linking processes in real time. Piping enables commands to work together in a pipeline without intermediate files, whereas redirection usually deals with static input/output sources.
+
+- STDERR is often used for error messages, while STDOUT is for regular output. Why is it important to keep these separate in a shell?
+
+    > **Answer**:   Keeping STDERR separate from STDOUT is important because they serve different purposes. STDOUT is meant for regular, expected output, while STDERR is reserved for error messages. Separating them allows users and scripts to distinguish between normal output and error conditions, making debugging easier. It also lets users redirect errors to a different location (for example, an error log) without mixing them with standard output, preserving clarity and control over what gets displayed or recorded.
+
+- How should our custom shell handle errors from commands that fail? Consider cases where a command outputs both STDOUT and STDERR. Should we provide a way to merge them, and if so, how?
+
+    > **Answer**:  Our custom shell should capture errors by monitoring the exit status of commands and by ensuring that error messages are sent to STDERR. In cases where a command produces both STDOUT and STDERR, the shell might provide redirection options that allow users to merge the streams (using operators like 2>&1) if desired. However, by default, they should remain separate to maintain clarity. The shell could also provide informative error messages and possibly a mechanism (such as specific flags or configuration) that allows the user to decide whether to merge the outputs or keep them distinct, thereby giving greater control over the output handling in different contexts.
\ No newline at end of file
diff --git a/A3/test.sh b/A3/test.sh
new file mode 100644
index 0000000000000000000000000000000000000000..43b0aea5390fb6da6a58a95d044174e10c2b5b5e
--- /dev/null
+++ b/A3/test.sh
@@ -0,0 +1,213 @@
+
+#!/usr/bin/env bats
+
+@test "Simple Command" {
+    run ./dsh <<EOF                
+test_command
+exit
+EOF
+
+    # Strip all whitespace (spaces, tabs, newlines) from the output
+    stripped_output=$(echo "$output" | tr -d '[:space:]')
+
+    # Expected output with all whitespace removed for easier matching
+    expected_output="dsh>PARSEDCOMMANDLINE-TOTALCOMMANDS1<1>test_commanddsh>"
+
+    # These echo commands will help with debugging and will only print
+    #if the test fails
+    echo "Captured stdout:" 
+    echo "Output: $output"
+    echo "Exit Status: $status"
+
+    # Check exact match
+    [ "$stripped_output" = "$expected_output" ]
+
+    # Assertions
+    [ "$status" -eq 0 ]
+
+}
+
+@test "Simple Command with Args" {
+    run ./dsh <<EOF                
+cmd -a1 -a2
+exit
+EOF
+
+    # Strip all whitespace (spaces, tabs, newlines) from the output
+    stripped_output=$(echo "$output" | tr -d '[:space:]')
+
+    # Expected output 
+    expected_output="dsh>PARSEDCOMMANDLINE-TOTALCOMMANDS1<1>cmd[-a1-a2]dsh>"
+
+    # These echo commands will help with debugging and will only print
+    #if the test fails
+    echo "Captured stdout:" 
+    echo "Output: $output"
+    echo "Exit Status: $status"
+
+    # Check exact match
+    [ "$stripped_output" = "$expected_output" ]
+
+    # Assertions
+    [ "$status" -eq 0 ]
+
+}
+
+
+@test "No command provided" {
+    run ./dsh <<EOF                
+
+exit
+EOF
+
+    # Strip all whitespace (spaces, tabs, newlines) from the output
+    stripped_output=$(echo "$output" | tr -d '[:space:]')
+
+    # Expected output with all whitespace removed for easier matching
+    expected_output="dsh>warning:nocommandsprovideddsh>"
+
+    # These echo commands will help with debugging and will only print
+    #if the test fails
+    echo "Captured stdout:" 
+    echo "Output: $output"
+    echo "Exit Status: $status"
+
+    # Check exact match
+    [ "$stripped_output" = "$expected_output" ]
+
+    # Assertions
+    [ "$status" -eq 0 ]
+
+}
+
+@test "Two commands" {
+    run ./dsh <<EOF                
+command_one | command_two
+exit
+EOF
+
+    # Strip all whitespace (spaces, tabs, newlines) from the output
+    stripped_output=$(echo "$output" | tr -d '[:space:]')
+
+    # Expected output with all whitespace removed for easier matching
+    expected_output="dsh>PARSEDCOMMANDLINE-TOTALCOMMANDS2<1>command_one<2>command_twodsh>"
+
+    # These echo commands will help with debugging and will only print
+    #if the test fails
+    echo "Captured stdout:" 
+    echo "Output: $output"
+    echo "Exit Status: $status"
+
+    # Check exact match
+    [ "$stripped_output" = "$expected_output" ]
+
+    # Assertions
+    [ "$status" -eq 0 ]
+
+}
+
+@test "three commands with args" {
+    run ./dsh <<EOF                
+cmd1 a1 a2 a3 | cmd2 a4 a5 a6 | cmd3 a7 a8 a9
+exit
+EOF
+
+    # Strip all whitespace (spaces, tabs, newlines) from the output
+    stripped_output=$(echo "$output" | tr -d '[:space:]')
+
+    # Expected output with all whitespace removed for easier matching
+    expected_output="dsh>PARSEDCOMMANDLINE-TOTALCOMMANDS3<1>cmd1[a1a2a3]<2>cmd2[a4a5a6]<3>cmd3[a7a8a9]dsh>"
+
+    # These echo commands will help with debugging and will only print
+    #if the test fails
+    echo "Captured stdout:" 
+    echo "Output: $output"
+    echo "Exit Status: $status"
+
+    # Check exact match
+    [ "$stripped_output" = "$expected_output" ]
+
+    # Assertions
+    [ "$status" -eq 0 ]
+
+}
+
+@test "try max (8) commands" {
+    run ./dsh <<EOF                
+cmd1 | cmd2 | cmd3 | cmd4 | cmd5 | cmd6 | cmd7 | cmd8
+exit
+EOF
+
+    # Strip all whitespace (spaces, tabs, newlines) from the output
+    stripped_output=$(echo "$output" | tr -d '[:space:]')
+
+    # Expected output with all whitespace removed for easier matching
+    expected_output="dsh>PARSEDCOMMANDLINE-TOTALCOMMANDS8<1>cmd1<2>cmd2<3>cmd3<4>cmd4<5>cmd5<6>cmd6<7>cmd7<8>cmd8dsh>"
+
+    # These echo commands will help with debugging and will only print
+    #if the test fails
+    echo "Captured stdout:" 
+    echo "Output: $output"
+    echo "Exit Status: $status"
+
+    # Check exact match
+    [ "$stripped_output" = "$expected_output" ]
+
+    # Assertions
+    [ "$status" -eq 0 ]
+
+}
+
+@test "try too many commands" {
+    run ./dsh <<EOF                
+cmd1 | cmd2 | cmd3 | cmd4 | cmd5 | cmd6 | cmd7 | cmd8 | cmd9
+exit
+EOF
+
+    # Strip all whitespace (spaces, tabs, newlines) from the output
+    stripped_output=$(echo "$output" | tr -d '[:space:]')
+
+    # Expected output with all whitespace removed for easier matching
+    expected_output="dsh>error:pipinglimitedto8commandsdsh>"
+
+    # These echo commands will help with debugging and will only print
+    #if the test fails
+    echo "Captured stdout:" 
+    echo "Output: $output"
+    echo "Exit Status: $status"
+
+    # Check exact match
+    [ "$stripped_output" = "$expected_output" ]
+
+    # Assertions
+    [ "$status" -eq 0 ]
+
+}
+
+@test "kitchen sink - multiple commands" {
+    run ./dsh <<EOF                
+cmd1
+cmd2 arg arg2
+p1 | p2
+p3 p3a1 p3a2 | p4 p4a1 p4a2
+EOF
+
+    # Strip all whitespace (spaces, tabs, newlines) from the output
+    stripped_output=$(echo "$output" | tr -d '[:space:]')
+
+    # Expected output with all whitespace removed for easier matching
+    expected_output="dsh>PARSEDCOMMANDLINE-TOTALCOMMANDS1<1>cmd1dsh>PARSEDCOMMANDLINE-TOTALCOMMANDS1<1>cmd2[argarg2]dsh>PARSEDCOMMANDLINE-TOTALCOMMANDS2<1>p1<2>p2dsh>PARSEDCOMMANDLINE-TOTALCOMMANDS2<1>p3[p3a1p3a2]<2>p4[p4a1p4a2]dsh>"
+
+    # These echo commands will help with debugging and will only print
+    #if the test fails
+    echo "Captured stdout:" 
+    echo "Output: $output"
+    echo "Exit Status: $status"
+
+    # Check exact match
+    [ "$stripped_output" = "$expected_output" ]
+
+    # Assertions
+    [ "$status" -eq 0 ]
+
+}