diff --git a/4coder_file.h b/4coder_file.h
index 305a360a..575e1801 100644
--- a/4coder_file.h
+++ b/4coder_file.h
@@ -51,8 +51,8 @@ struct Cross_Platform_File_Info{
 struct Cross_Platform_File_List{
     Cross_Platform_File_Info *info;
     int32_t count;
-    int32_t final_length;
-    Filename_Character final_name[4096];
+    int32_t path_length;
+    Filename_Character path_name[4096];
 };
 
 typedef bool32 File_Filter(Filename_Character *name, int32_t len);
@@ -147,46 +147,59 @@ filter_is_code_file(Filename_Character *name, int32_t len){
 
 //// WINDOWS BEGIN ////
 static Cross_Platform_File_List
-get_file_list(Partition *part, Filename_Character *dir, File_Filter *filter){
+get_file_list(Partition *part, Filename_Character *pattern, File_Filter *filter){
     if (part == 0){
         fprintf(stdout, "fatal error: NULL part passed to %s\n", __FUNCTION__);
         exit(1);
     }
-    if (dir == 0){
-        fprintf(stdout, "fatal error: NULL dir passed to %s\n", __FUNCTION__);
+    if (pattern == 0){
+        fprintf(stdout, "fatal error: NULL pattern passed to %s\n", __FUNCTION__);
         exit(1);
     }
     
+    int32_t pattern_length = 0;
+    for (; pattern[pattern_length] != 0; ++pattern_length);
+    int32_t last_slash = pattern_length;
+    for (; last_slash > 0 && pattern[last_slash] != SLASH; --last_slash);
+    if (last_slash < 0){
+        fprintf(stdout, "fatal error: invalid file pattern\n");
+        exit(1);
+    }
+    pattern[last_slash] = 0;
+    
     HANDLE dir_handle =
-        CreateFile(dir,
+        CreateFile(pattern,
                    FILE_LIST_DIRECTORY,
                    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                    0,
                    OPEN_EXISTING,
                    FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
                    0);
+    pattern[last_slash] = SLASH;
     
     if (dir_handle == INVALID_HANDLE_VALUE){
         fprintf(stdout, "fatal error: could not open directory handle\n");
         exit(1);
     }
     
-    Filename_Character final_name[4096];
-    DWORD final_length = GetFinalPathNameByHandle(dir_handle, final_name, sizeof(final_name), 0);
-    if (final_length > sizeof(final_name)){
+    Filename_Character path_name[4096];
+    DWORD path_length = GetFinalPathNameByHandle(dir_handle, path_name, sizeof(path_name), 0);
+    if (path_length > sizeof(path_name)){
         fprintf(stdout, "fatal error: path name too long for local buffer\n");
         exit(1);
     }
     CloseHandle(dir_handle);
     
-    final_length -= 4;
-    memmove(final_name, final_name + 4, final_length*sizeof(*final_name));
-    final_name[final_length] = '\\';
-    final_name[final_length + 1] = '*';
-    final_name[final_length + 2] = 0;
+    path_length -= 4;
+    memmove(path_name, path_name + 4, path_length*sizeof(*path_name));
+    path_name[path_length] = 0;
+    
+    // TODO(allen): // TODO(allen): // TODO(allen): // TODO(allen): // TODO(allen): 
+    // TODO(allen): // TODO(allen): // TODO(allen): // TODO(allen): // TODO(allen): 
+    // Get this working with the new search by pattern structure!!!
     
     WIN32_FIND_DATA find_data = {0};
-    HANDLE search = FindFirstFile(final_name, &find_data);
+    HANDLE search = FindFirstFile(pattern, &find_data);
     if (search == INVALID_HANDLE_VALUE){
         fprintf(stdout, "fatal error: could not begin a file search\n");
         exit(1);
@@ -235,7 +248,7 @@ get_file_list(Partition *part, Filename_Character *dir, File_Filter *filter){
     
     Cross_Platform_File_Info *info_ptr_base = info_ptr;
     
-    search = FindFirstFile(final_name, &find_data);
+    search = FindFirstFile(pattern, &find_data);
     if (search == INVALID_HANDLE_VALUE){
         fprintf(stdout, "fatal error: could not restart a file search\n");
         exit(1);
@@ -281,9 +294,9 @@ get_file_list(Partition *part, Filename_Character *dir, File_Filter *filter){
     
     list.info = info_ptr_base;
     list.count = adjusted_file_count;
-    list.final_length = final_length;
-    memcpy(list.final_name, final_name, list.final_length*sizeof(*final_name));
-    list.final_name[list.final_length] = 0;
+    list.path_length = path_length;
+    memcpy(list.path_name, path_name, list.path_length*sizeof(*path_name));
+    list.path_name[list.path_length] = 0;
     
     return(list);
 }
diff --git a/4coder_metadata_generator.cpp b/4coder_metadata_generator.cpp
index f0587b06..d3220ef9 100644
--- a/4coder_metadata_generator.cpp
+++ b/4coder_metadata_generator.cpp
@@ -633,16 +633,22 @@ parse_file(Partition *part, Meta_Command_Entry_Arrays *entry_arrays, Filename_Ch
 }
 
 static void
-parse_files_in_directory(Partition *part, Meta_Command_Entry_Arrays *entry_arrays, Filename_Character *root, bool32 recursive){
-    Cross_Platform_File_List list = get_file_list(part, root, filter_is_code_file);
+parse_files_by_pattern(Partition *part, Meta_Command_Entry_Arrays *entry_arrays, Filename_Character *pattern, bool32 recursive){
+    Cross_Platform_File_List list = get_file_list(part, pattern, filter_is_code_file);
     for (int32_t i = 0; i < list.count; ++i){
         Cross_Platform_File_Info *info = &list.info[i];
         
         if (info->is_folder && match(make_string(info->name, info->len), "4coder_generated")){
             continue;
         }
+        if (!recursive && info->is_folder){
+            continue;
+        }
         
-        int32_t full_name_len = list.final_length + 1 + info->len;
+        int32_t full_name_len = list.path_length + 1 + info->len;
+        if (info->is_folder){
+            full_name_len += 2;
+        }
         Filename_Character *full_name = push_array(part, Filename_Character, full_name_len + 1);
         push_align(part, 8);
         
@@ -651,16 +657,18 @@ parse_files_in_directory(Partition *part, Meta_Command_Entry_Arrays *entry_array
             exit(1);
         }
         
-        memmove(full_name, list.final_name, list.final_length*sizeof(*full_name));
-        full_name[list.final_length] = SLASH;
-        memmove(full_name + list.final_length + 1, info->name, info->len*sizeof(*full_name));
+        memmove(full_name, list.path_name, list.path_length*sizeof(*full_name));
+        full_name[list.path_length] = SLASH;
+        memmove(full_name + list.path_length + 1, info->name, info->len*sizeof(*full_name));
         full_name[full_name_len] = 0;
         
         if (!info->is_folder){
             parse_file(part, entry_arrays, full_name, full_name_len);
         }
         else{
-            parse_files_in_directory(part, entry_arrays, full_name, recursive);
+            full_name[full_name_len - 2] = SLASH;
+            full_name[full_name_len - 1] = '*';
+            parse_files_by_pattern(part, entry_arrays, full_name, true);
         }
     }
 }
@@ -671,7 +679,7 @@ show_usage(int argc, char **argv){
     if (argc >= 1){
         name = argv[0];
     }
-    fprintf(stdout, "usage:\n%s [-R] <4coder-root-directory> <scan-root-directory> [<scan-root-directory2> ...]\n", name);
+    fprintf(stdout, "usage:\n%s [-R] <4coder-root-directory> <input-file-pattern> [<input-file-pattern> ...]\n", name);
     exit(0);
 }
 
@@ -700,8 +708,8 @@ main(int argc, char **argv){
     
     Meta_Command_Entry_Arrays entry_arrays = {0};
     for (int32_t i = start_i; i < argc; ++i){
-        Filename_Character *root_name = encode(part, argv[i]);
-        parse_files_in_directory(part, &entry_arrays, root_name, recursive);
+        Filename_Character *pattern_name = encode(part, argv[i]);
+        parse_files_by_pattern(part, &entry_arrays, pattern_name, recursive);
     }
     
     int32_t out_dir_len = str_size(out_directory);
diff --git a/build_metadata.bat b/build_metadata.bat
index 054ebace..0a66d2a7 100644
--- a/build_metadata.bat
+++ b/build_metadata.bat
@@ -1,13 +1,14 @@
 @echo off
 
-SET OPTS=/W4 /wd4310 /wd4100 /wd4201 /wd4505 /wd4996 /wd4127 /wd4510 /wd4512 /wd4610 /wd4390 /WX
-SET OPTS=%OPTS% /GR- /EHa- /nologo /FC
+set OPTS=/W4 /wd4310 /wd4100 /wd4201 /wd4505 /wd4996 /wd4127 /wd4510 /wd4512 /wd4610 /wd4390 /WX
+set OPTS=%OPTS% /GR- /EHa- /nologo /FC
 
 pushd ..\build
 cl %OPTS% ..\code\4coder_metadata_generator.cpp /Zi /Femetadata_generator
 popd
 
-SET CODE_HOME=%~dp0
-..\build\metadata_generator -R "%CODE_HOME% " "%CODE_HOME% "
+set code_home=%~dp0
+if %code_home:~-1%==\ (set code_home=%code_home:~0,-1%)
+..\build\metadata_generator -R "%code_home%" "%code_home%\*"
 
 
diff --git a/build_tests.bat b/build_tests.bat
index 84283d55..f1030ddc 100644
--- a/build_tests.bat
+++ b/build_tests.bat
@@ -21,5 +21,7 @@ cl %opts% %inc% %code_home%\meta\4ed_test_builder.cpp /Zi /Fetest_builder
 popd
 
 pushd %data_home%
-%build_home%\test_builder %code_home%\test_scripts
+%build_home%\test_builder %code_home%\test_scripts\test_full_click.4is
+%build_home%\test_builder %code_home%\test_scripts\test_write_4coder_awesomeness.4is
+%build_home%\test_builder %code_home%\test_scripts\test_bootstrap.4is
 popd
\ No newline at end of file
diff --git a/buildsuper_x64.bat b/buildsuper_x64.bat
index 5a0e4d43..374c9917 100644
--- a/buildsuper_x64.bat
+++ b/buildsuper_x64.bat
@@ -4,23 +4,24 @@ REM This stores the path of the buildsuper.bat script
 REM in CODE_HOME.  This way you can always include the
 REM default files no matter where you store your code.
 REM And no matter how you call buildsuper.bat.
-SET CODE_HOME=%~dp0
+set code_home=%~dp0
+if %code_home:~-1%==\ (set code_home=%code_home:~0,-1%)
 
-IF NOT "%Platform%" == "X64" IF NOT "%Platform%" == "x64" (call "%CODE_HOME%\\windows_scripts\\setup_cl_x64.bat")
+if NOT "%Platform%" == "X64" IF NOT "%Platform%" == "x64" (call "%code_home%\windows_scripts\setup_cl_x64.bat")
 
-SET SRC=%1
-if "%SRC%" == "" SET SRC=4coder_default_bindings.cpp
+set SRC=%1
+if "%SRC%" == "" set SRC=4coder_default_bindings.cpp
 
-SET OPTS=/W4 /wd4310 /wd4100 /wd4201 /wd4505 /wd4996 /wd4127 /wd4510 /wd4512 /wd4610 /wd4457 /WX
-SET OPTS=%OPTS% /GR- /nologo /FC
-SET DEBUG=/Zi
-SET BUILD_DLL=/LD /link /INCREMENTAL:NO /OPT:REF
-SET EXPORTS=/EXPORT:get_bindings /EXPORT:get_alpha_4coder_version
+set OPTS=/W4 /wd4310 /wd4100 /wd4201 /wd4505 /wd4996 /wd4127 /wd4510 /wd4512 /wd4610 /wd4457 /WX
+set OPTS=%OPTS% /GR- /nologo /FC
+set DEBUG=/Zi
+set BUILD_DLL=/LD /link /INCREMENTAL:NO /OPT:REF
+set EXPORTS=/EXPORT:get_bindings /EXPORT:get_alpha_4coder_version
 
-cl /I"%CODE_HOME% " %OPTS% %DEBUG% "%CODE_HOME%4coder_metadata_generator.cpp" /Femetadata_generator
-metadata_generator -R "%CODE_HOME% " "%CODE_HOME% "
+cl /I"%code_home%" %OPTS% %DEBUG% "%code_home%\4coder_metadata_generator.cpp" /Femetadata_generator
+metadata_generator -R "%code_home%" "%code_home%\*"
 
-cl /I"%CODE_HOME% " %OPTS% %DEBUG% %SRC% /Fecustom_4coder %BUILD_DLL% %EXPORTS%
+cl /I"%code_home%" %OPTS% %DEBUG% %SRC% /Fecustom_4coder %BUILD_DLL% %EXPORTS%
 
 REM file spammation preventation
 del metadata_generator*
diff --git a/buildsuper_x86.bat b/buildsuper_x86.bat
index 7ee41184..72a36a96 100644
--- a/buildsuper_x86.bat
+++ b/buildsuper_x86.bat
@@ -4,23 +4,24 @@ REM This stores the path of the buildsuper.bat script
 REM in CODE_HOME.  This way you can always include the
 REM default files no matter where you store your code.
 REM And no matter how you call buildsuper.bat.
-SET CODE_HOME=%~dp0
+set code_home=%~dp0
+if %code_home:~-1%==\ (set code_home=%code_home:~0,-1%)
 
-IF NOT "%Platform%" == "X86" IF NOT "%Platform%" == "x86" (call "%CODE_HOME%\\windows_scripts\\setup_cl_x86.bat")
+if NOT "%Platform%" == "X86" IF NOT "%Platform%" == "x86" (call "%code_home%\windows_scripts\setup_cl_x86.bat")
 
-SET SRC=%1
-if "%SRC%" == "" SET SRC=4coder_default_bindings.cpp
+set SRC=%1
+if "%SRC%" == "" set SRC=4coder_default_bindings.cpp
 
-SET OPTS=/W4 /wd4310 /wd4100 /wd4201 /wd4505 /wd4996 /wd4127 /wd4510 /wd4512 /wd4610 /wd4457 /WX
-SET OPTS=%OPTS% /GR- /nologo /FC
-SET DEBUG=/Zi
-SET BUILD_DLL=/LD /link /INCREMENTAL:NO /OPT:REF
-SET EXPORTS=/EXPORT:get_bindings /EXPORT:get_alpha_4coder_version
+set OPTS=/W4 /wd4310 /wd4100 /wd4201 /wd4505 /wd4996 /wd4127 /wd4510 /wd4512 /wd4610 /wd4457 /WX
+set OPTS=%OPTS% /GR- /nologo /FC
+set DEBUG=/Zi
+set BUILD_DLL=/LD /link /INCREMENTAL:NO /OPT:REF
+set EXPORTS=/EXPORT:get_bindings /EXPORT:get_alpha_4coder_version
 
-cl %OPTS% /I"%CODE_HOME% " %DEBUG% "%CODE_HOME%4coder_metadata_generator.cpp" /Femetadata_generator
-metadata_generator -R "%CODE_HOME% " "%CODE_HOME% "
+cl %OPTS% /I"%code_home%" %DEBUG% "%code_home%\4coder_metadata_generator.cpp" /Femetadata_generator
+metadata_generator -R "%code_home%" "%code_home%\*"
 
-cl %OPTS% /I"%CODE_HOME% " %DEBUG% "%SRC%" /Fecustom_4coder %BUILD_DLL% %EXPORTS%
+cl %OPTS% /I"%code_home%" %DEBUG% "%SRC%" /Fecustom_4coder %BUILD_DLL% %EXPORTS%
 
 REM file spammation preventation
 del metadata_generator*
diff --git a/meta/4ed_test_builder.cpp b/meta/4ed_test_builder.cpp
index 225dc764..aa89deae 100644
--- a/meta/4ed_test_builder.cpp
+++ b/meta/4ed_test_builder.cpp
@@ -201,11 +201,19 @@ require_integer(Line_Parse_Context context, i32 index, i32 *int_out){
 }
 
 internal bool32
-require_string(Line_Parse_Context context, i32 index, String *str_out){
+require_unquoted_string(Line_Parse_Context context, i32 index, String *str_out){
     bool32 result = false;
     if (index < context.words.count){
-        *str_out = context.words.strings[index];
-        result = true;
+        String str = context.words.strings[index];
+        if (str.str[0] != '"'){
+            *str_out = str;
+            result = true;
+        }
+        else{
+            show_error(context,
+                       context.words.strings[context.words.count - 1].str,
+                       "expected a simple word (a simple word must be unquoted)");
+        }
     }
     else{
         show_error(context,
@@ -215,6 +223,11 @@ require_string(Line_Parse_Context context, i32 index, String *str_out){
     return(result);
 }
 
+internal bool32
+require_any_string(Line_Parse_Context context, i32 index, String *str_out){
+    bool32 result = require_unquoted_string(context, index, str_out);
+    return(result);
+}
 
 internal bool32
 key_name_to_code(Line_Parse_Context context, String key_name, u32 *key_code_out){
@@ -241,10 +254,6 @@ key_name_to_code(Line_Parse_Context context, String key_name, u32 *key_code_out)
         KEY_CODE_CHK(key_page_up);
         KEY_CODE_CHK(key_page_down);
         KEY_CODE_CHK(key_esc);
-        KEY_CODE_CHK(key_mouse_left);
-        KEY_CODE_CHK(key_mouse_right);
-        KEY_CODE_CHK(key_mouse_left_release);
-        KEY_CODE_CHK(key_mouse_right_release);
         KEY_CODE_CHK(key_f1);
         KEY_CODE_CHK(key_f2);
         KEY_CODE_CHK(key_f3);
@@ -262,6 +271,8 @@ key_name_to_code(Line_Parse_Context context, String key_name, u32 *key_code_out)
         KEY_CODE_CHK(key_f15);
         KEY_CODE_CHK(key_f16);
         KEY_CODE_CHK_SET("key_space", ' ');
+        KEY_CODE_CHK_SET("key_newline", '\n');
+        KEY_CODE_CHK_SET("key_tab", '\t');
     }
     
     if (!result){
@@ -292,8 +303,7 @@ mod_name_to_flags(Line_Parse_Context context, Partition *part, String mod_name,
         MDFR_FLAG_CHK(MDFR_SHIFT);
         else{
             result = false;
-            show_error(context, flag_string.str,
-                       "unrecognized flag string");
+            show_error(context, flag_string.str, "unrecognized flag string");
             break;
         }
         
@@ -306,25 +316,27 @@ mod_name_to_flags(Line_Parse_Context context, Partition *part, String mod_name,
 }
 
 internal void
-process_script_inner(Partition *part, char *name){
-    String data = file_dump(part, name);
-    String_Array lines = get_lines(part, data);
+process_script_inner(Partition *scratch, char *name){
+    String data = file_dump(scratch, name);
+    String_Array lines = get_lines(scratch, data);
     
-    Simulation_Event *events = push_array(part, Simulation_Event, 0);
+    Simulation_Event *events = push_array(scratch, Simulation_Event, 0);
     i32 event_count = 0;
     
     i32 time_counter = 0;
     
     for (i32 i = 0; i < lines.count; ++i){
-        Temp_Memory word_temp = begin_temp_memory(part);
+        Temp_Memory word_temp = begin_temp_memory(scratch);
         String line = lines.strings[i];
-        String_Array words = get_words(part, line);
+        String_Array words = get_words(scratch, line);
         
         Line_Parse_Context context = {0};
         context.name = name;
         context.data = data;
         context.words = words;
         
+        i32 current_debug_number = 0;
+        
         bool32 emit_event = false;
         Simulation_Event event = {0};
         
@@ -332,9 +344,13 @@ process_script_inner(Partition *part, char *name){
         i32 type_increment = 0;
         String type_string = {0};
         
+        bool32 emit_invoke = false;
+        String invoke_file = {0};
+        
         if (words.count != 0){
             String first_word = words.strings[0];
             if (!match(substr(first_word, 0, 2), "//")){
+                
                 if (match(first_word, "debug_number")){
                     i32 debug_number = 0;
                     if (require_integer(context, 1, &debug_number) &&
@@ -343,11 +359,13 @@ process_script_inner(Partition *part, char *name){
                         event.counter_index = time_counter;
                         event.type = SimulationEvent_DebugNumber;
                         event.debug_number = debug_number;
+                        current_debug_number = debug_number;
                     }
                     else{
                         return;
                     }
                 }
+                
                 else if (match(first_word, "wait")){
                     i32 increment = 0;
                     if (require_integer(context, 1, &increment) &&
@@ -358,16 +376,17 @@ process_script_inner(Partition *part, char *name){
                         return;
                     }
                 }
+                
                 else if (match(first_word, "key")){
                     String key_name = {0};
                     String mod_name = {0};
-                    if (require_string(context, 1, &key_name) &&
-                        require_string(context, 2, &mod_name) &&
+                    if (require_unquoted_string(context, 1, &key_name) &&
+                        require_unquoted_string(context, 2, &mod_name) &&
                         require_blank(context, 3)){
                         u32 key_code = 0;
                         u8 modifiers = 0;
                         if (key_name_to_code(context, key_name, &key_code) &&
-                            mod_name_to_flags(context, part, mod_name, &modifiers)){
+                            mod_name_to_flags(context, scratch, mod_name, &modifiers)){
                             emit_event = true;
                             event.counter_index = time_counter;
                             event.type = SimulationEvent_Key;
@@ -382,11 +401,12 @@ process_script_inner(Partition *part, char *name){
                         return;
                     }
                 }
+                
                 else if (match(first_word, "type")){
                     i32 increment = 0;
                     String string = {0};
                     if (require_integer(context, 1, &increment) &&
-                        require_string(context, 2, &string) &&
+                        require_unquoted_string(context, 2, &string) &&
                         require_blank(context, 3)){
                         emit_type = true;
                         type_increment = increment;
@@ -396,6 +416,19 @@ process_script_inner(Partition *part, char *name){
                         return;
                     }
                 }
+                
+                else if (match(first_word, "invoke")){
+                    String file = {0};
+                    if (require_any_string(context, 1, &file) &&
+                        require_blank(context, 2)){
+                        emit_invoke = true;
+                        invoke_file = file;
+                    }
+                    else{
+                        return;
+                    }
+                }
+                
                 else if (match(first_word, "mouse_left_press")){
                     if (require_blank(context, 1)){
                         emit_event = true;
@@ -406,6 +439,7 @@ process_script_inner(Partition *part, char *name){
                         return;
                     }
                 }
+                
                 else if (match(first_word, "mouse_right_press")){
                     if (require_blank(context, 1)){
                         emit_event = true;
@@ -416,6 +450,7 @@ process_script_inner(Partition *part, char *name){
                         return;
                     }
                 }
+                
                 else if (match(first_word, "mouse_left_release")){
                     if (require_blank(context, 1)){
                         emit_event = true;
@@ -426,6 +461,7 @@ process_script_inner(Partition *part, char *name){
                         return;
                     }
                 }
+                
                 else if (match(first_word, "mouse_right_release")){
                     if (require_blank(context, 1)){
                         emit_event = true;
@@ -436,6 +472,7 @@ process_script_inner(Partition *part, char *name){
                         return;
                     }
                 }
+                
                 else if (match(first_word, "mouse_wheel")){
                     i32 wheel = 0;
                     if (require_integer(context, 1, &wheel) &&
@@ -449,6 +486,7 @@ process_script_inner(Partition *part, char *name){
                         return;
                     }
                 }
+                
                 else if (match(first_word, "mouse_xy")){
                     i32 x = 0;
                     i32 y = 0;
@@ -465,6 +503,7 @@ process_script_inner(Partition *part, char *name){
                         return;
                     }
                 }
+                
                 else if (match(first_word, "exit")){
                     if (require_blank(context, 1)){
                         emit_event = true;
@@ -475,9 +514,9 @@ process_script_inner(Partition *part, char *name){
                         return;
                     }
                 }
+                
                 else{
-                    show_error(name, data, first_word.str,
-                               "unrecognized control word");
+                    show_error(name, data, first_word.str, "unrecognized control word");
                     return;
                 }
             }
@@ -486,7 +525,7 @@ process_script_inner(Partition *part, char *name){
         end_temp_memory(word_temp);
         
         if (emit_event){
-            Simulation_Event *new_event = push_array(part, Simulation_Event, 1);
+            Simulation_Event *new_event = push_array(scratch, Simulation_Event, 1);
             memset(new_event, 0, sizeof(*new_event));
             *new_event = event;
             event_count += 1;
@@ -494,7 +533,7 @@ process_script_inner(Partition *part, char *name){
         
         if (emit_type){
             for (i32 j = 0; j < type_string.size; ++j){
-                Simulation_Event *new_event = push_array(part, Simulation_Event, 1);
+                Simulation_Event *new_event = push_array(scratch, Simulation_Event, 1);
                 memset(new_event, 0, sizeof(*new_event));
                 new_event->counter_index = time_counter;
                 new_event->type = SimulationEvent_Key;
@@ -504,10 +543,48 @@ process_script_inner(Partition *part, char *name){
                 time_counter += type_increment;
             }
         }
+        
+        if (emit_invoke){
+            Temp_Memory invoke_temp = begin_temp_memory(scratch);
+            
+            char *invoke_name = push_array(scratch, char, invoke_file.size + 1);
+            push_align(scratch, 8);
+            memcpy(invoke_name, invoke_file.str, invoke_file.size);
+            invoke_name[invoke_file.size] = 0;
+            String invoke_data = file_dump(scratch, invoke_name);
+            if (invoke_data.str == 0){
+                show_error(name, data, invoke_file.str, "could not open invoked file");
+                return;
+            }
+            i32 count = *(i32*)invoke_data.str;
+            Simulation_Event *events = (Simulation_Event*)(invoke_data.str + 4);
+            Simulation_Event *event = events;
+            for (i32 i = 0; i < count; ++i, ++event){
+                event->counter_index = event->counter_index + time_counter;
+                if (event->type == SimulationEvent_Exit){
+                    count = i + 1;
+                    event->type = SimulationEvent_DebugNumber;
+                }
+                if (event->type == SimulationEvent_DebugNumber){
+                    event->debug_number = current_debug_number;
+                }
+            }
+            if (count > 0){
+                time_counter = events[count - 1].counter_index;
+            }
+            end_temp_memory(invoke_temp);
+            
+            // NOTE(allen): This is pulling back events from inside a
+            // closed temp block.  Don't let it get separated from the
+            // end_temp_memory call!
+            void *ptr = push_array(scratch, Simulation_Event, count);
+            memmove(ptr, events, sizeof(*events)*count);
+            event_count += count;
+        }
     }
     
     String out_name_s = front_of_directory(make_string_slowly(name));
-    char *out_name = push_array(part, char, out_name_s.size + 1);
+    char *out_name = push_array(scratch, char, out_name_s.size + 1);
     memcpy(out_name, out_name_s.str, out_name_s.size);
     Assert(out_name[out_name_s.size - 1] == 's');
     out_name[out_name_s.size - 1] = 'd';
@@ -526,9 +603,9 @@ process_script_inner(Partition *part, char *name){
 }
 
 internal void
-process_script(Partition *part, char *name){
-    Temp_Memory temp = begin_temp_memory(part);
-    process_script_inner(part, name);
+process_script(Partition *scratch, char *name){
+    Temp_Memory temp = begin_temp_memory(scratch);
+    process_script_inner(scratch, name);
     end_temp_memory(temp);
 }
 
@@ -550,8 +627,8 @@ main(int argc, char **argv){
     for (i32 i = 1; i < argc; ++i){
         Cross_Platform_File_List files = get_file_list(part, encode(part, argv[i]), filter_all);
         
-        char *final_name = unencode(part, files.final_name, files.final_length);
-        String final_name_s = make_string_slowly(final_name);
+        char *path_name = unencode(part, files.path_name, files.path_length);
+        String path_name_s = make_string_slowly(path_name);
         
         Cross_Platform_File_Info *info = files.info;
         for (i32 j = 0; j < files.count; ++j, ++info){
@@ -565,12 +642,12 @@ main(int argc, char **argv){
                 continue;
             }
             
-            i32 whole_name_max = final_name_s.size + 1 + s.size + 1;
+            i32 whole_name_max = path_name_s.size + 1 + s.size + 1;
             char *whole_name = push_array(part, char, whole_name_max);
             push_align(part, 8);
             
             String w = make_string_cap(whole_name, 0, whole_name_max);
-            append(&w, final_name_s);
+            append(&w, path_name_s);
             append(&w, '/');
             append(&w, s);
             terminate_with_null(&w);
diff --git a/string/4coder_string_build_num.txt b/string/4coder_string_build_num.txt
index 3f0270e7..62991c28 100644
--- a/string/4coder_string_build_num.txt
+++ b/string/4coder_string_build_num.txt
@@ -1,5 +1,5 @@
 1
 0
-110
+111
 
 
diff --git a/test_scripts/test_bootstrap.4is b/test_scripts/test_bootstrap.4is
index fd2f8e67..a8acfe0b 100644
--- a/test_scripts/test_bootstrap.4is
+++ b/test_scripts/test_bootstrap.4is
@@ -7,16 +7,10 @@ key _ MDFR_CTRL
 
 wait 5
 debug_number 2
-type 2 4coder
-key key_space MDFR_NONE
-wait 2
-type 2 awesomeness
+invoke test_write_4coder_awesomeness.4id
 
 wait 30
-mouse_left_press
-
-wait 10
-mouse_left_release
+invoke test_full_click.4id
 
 wait 10
 mouse_left_press
diff --git a/test_scripts/test_full_click.4is b/test_scripts/test_full_click.4is
new file mode 100644
index 00000000..9770ee65
--- /dev/null
+++ b/test_scripts/test_full_click.4is
@@ -0,0 +1,6 @@
+
+mouse_left_press
+wait 2
+mouse_left_release
+
+exit
diff --git a/test_scripts/test_write_4coder_awesomeness.4is b/test_scripts/test_write_4coder_awesomeness.4is
new file mode 100644
index 00000000..b011dc27
--- /dev/null
+++ b/test_scripts/test_write_4coder_awesomeness.4is
@@ -0,0 +1,6 @@
+
+type 2 4coder
+key key_tab MDFR_NONE
+wait 2
+type 2 awesomeness
+exit
\ No newline at end of file