diff --git a/site/4ed_abstract_document.cpp b/site/4ed_abstract_document.cpp
index 7f2e801a..4519b864 100644
--- a/site/4ed_abstract_document.cpp
+++ b/site/4ed_abstract_document.cpp
@@ -18,15 +18,8 @@ struct Enriched_Text{
internal Enriched_Text
load_enriched_text(char *directory, char *filename){
Enriched_Text result = {0};
-
- char space[256];
- String fname = make_fixed_width_string(space);
- append(&fname, directory);
- append(&fname, "/");
- append(&fname, filename);
- terminate_with_null(&fname);
-
- result.source = file_dump(fname.str);
+ char *fname = fm_str(directory, "/", filename);
+ result.source = file_dump(fname);
return(result);
}
@@ -35,6 +28,7 @@ load_enriched_text(char *directory, char *filename){
enum{
Doc_Root,
Doc_Section,
+ Doc_Error,
Doc_Todo,
Doc_Include,
Doc_DocList,
@@ -51,8 +45,6 @@ enum{
Doc_Video,
Doc_BeginParagraph,
Doc_EndParagraph,
- Doc_BeginSection,
- Doc_EndSection,
Doc_BeginList,
Doc_EndList,
Doc_BeginItem,
@@ -86,7 +78,7 @@ struct Document_Item{
Document_Item *last_child;
String name;
String id;
- i32 show_title;
+ b32 show_title;
} section;
struct{
@@ -254,36 +246,6 @@ add_image_instantiation(Basic_List *list, i32 w, i32 h){
instantiation->h = h;
}
-internal void
-set_section_name(Document_Item *item, char *name, i32 show_title){
- i32 name_len = str_size(name);
- item->section.name = make_string_cap(fm_push_array(char, name_len+1), 0, name_len+1);
- fm_align();
- append(&item->section.name, name);
- item->section.show_title = show_title;
-}
-
-internal void
-set_section_id(Document_Item *item, char *id){
- i32 id_len = str_size(id);
- item->section.id = make_string_cap(fm_push_array(char, id_len+1), 0, id_len+1);
- fm_align();
- append(&item->section.id, id);
-}
-
-internal void
-begin_document_description(Abstract_Item *doc, char *title, i32 show_title){
- *doc = null_abstract_item;
- doc->item_type = ItemType_Document;
-
- doc->root_item = fm_push_array(Document_Item, 1);
- *doc->root_item = null_document_item;
- doc->section_stack[doc->section_top] = doc->root_item;
- doc->root_item->type = Doc_Root;
-
- set_section_name(doc->root_item, title, show_title);
-}
-
internal Abstract_Item*
add_generic_file(Document_System *system, char *source_file, char *extension, char *name){
Abstract_Item *item = create_item(&system->file_list, name);
@@ -320,8 +282,38 @@ add_image_description(Document_System *system, char *source_file, char *extensio
return(item);
}
+internal void
+set_section_name(Document_Item *item, char *name, b32 show_title){
+ i32 name_len = str_size(name);
+ item->section.name = str_alloc(name_len + 1);
+ fm_align();
+ append(&item->section.name, name);
+ item->section.show_title = show_title;
+}
+
+internal void
+set_section_id(Document_Item *item, char *id){
+ i32 id_len = str_size(id);
+ item->section.id = str_alloc(id_len + 1);
+ fm_align();
+ append(&item->section.id, id);
+}
+
+internal void
+begin_document_description(Abstract_Item *doc, char *title, b32 show_title){
+ *doc = null_abstract_item;
+ doc->item_type = ItemType_Document;
+
+ doc->root_item = fm_push_array(Document_Item, 1);
+ *doc->root_item = null_document_item;
+ doc->section_stack[doc->section_top] = doc->root_item;
+ doc->root_item->type = Doc_Root;
+
+ set_section_name(doc->root_item, title, show_title);
+}
+
internal Abstract_Item*
-begin_document_description(Document_System *system, char *title, char *name, i32 show_title){
+begin_document_description(Document_System *system, char *title, char *name, b32 show_title){
Abstract_Item *item = create_item(&system->doc_list, name);
if (item){
begin_document_description(item, title, show_title);
@@ -359,7 +351,7 @@ begin_section(Abstract_Item *item, char *title, char *id){
section->type = Doc_Section;
- set_section_name(section, title, 1);
+ set_section_name(section, title, true);
if (id != 0){
set_section_id(section, id);
}
@@ -373,6 +365,29 @@ end_section(Abstract_Item *doc){
--doc->section_top;
}
+internal void
+add_error(Abstract_Item *doc, String text){
+ Assert(doc->section_top + 1 < ArrayCount(doc->section_stack));
+ Document_Item *parent = doc->section_stack[doc->section_top];
+ Document_Item *item = fm_push_array(Document_Item, 1);
+ *item = null_document_item;
+ item->type = Doc_Error;
+ item->string.string = str_alloc(text.size);
+ fm_align();
+ copy(&item->string.string, text);
+
+ append_child(parent, item);
+}
+
+internal void
+report_error_missing_body(Abstract_Item *doc, String command_body){
+ char space[512];
+ String error_string = make_fixed_width_string(space);
+ append(&error_string, "missing body for ");
+ append(&error_string, command_body);
+ add_error(doc, error_string);
+}
+
internal void
add_todo(Abstract_Item *doc){
Assert(doc->section_top + 1 < ArrayCount(doc->section_stack));
@@ -455,6 +470,7 @@ add_plain_old_text(Abstract_Item *doc, String text){
*item = null_document_item;
item->type = Doc_PlainOldText;
item->string.string = str_alloc(text.size);
+ fm_align();
copy(&item->string.string, text);
append_child(parent, item);
@@ -491,6 +507,7 @@ add_begin_style(Abstract_Item *doc, String text){
*item = null_document_item;
item->type = Doc_BeginStyle;
item->string.string = str_alloc(text.size);
+ fm_align();
copy(&item->string.string, text);
append_child(parent, item);
@@ -515,6 +532,7 @@ add_document_link(Abstract_Item *doc, String text){
*item = null_document_item;
item->type = Doc_DocumentLink;
item->string.string = str_alloc(text.size);
+ fm_align();
copy(&item->string.string, text);
append_child(parent, item);
@@ -528,6 +546,7 @@ add_begin_link(Abstract_Item *doc, String text){
*item = null_document_item;
item->type = Doc_BeginLink;
item->string.string = str_alloc(text.size);
+ fm_align();
copy(&item->string.string, text);
append_child(parent, item);
@@ -552,9 +571,11 @@ add_image(Abstract_Item *doc, String text, String extra_text){
*item = null_document_item;
item->type = Doc_Image;
item->string.string = str_alloc(text.size);
+ fm_align();
copy(&item->string.string, text);
if (extra_text.size > 0){
item->string.string2 = str_alloc(extra_text.size);
+ fm_align();
copy(&item->string.string2, extra_text);
}
@@ -569,6 +590,7 @@ add_video(Abstract_Item *doc, String text){
*item = null_document_item;
item->type = Doc_Video;
item->string.string = str_alloc(text.size);
+ fm_align();
copy(&item->string.string, text);
append_child(parent, item);
@@ -596,30 +618,6 @@ add_end_paragraph(Abstract_Item *doc){
append_child(parent, item);
}
-internal void
-add_begin_section(Abstract_Item *doc, String text){
- Assert(doc->section_top + 1 < ArrayCount(doc->section_stack));
- Document_Item *parent = doc->section_stack[doc->section_top];
- Document_Item *item = fm_push_array(Document_Item, 1);
- *item = null_document_item;
- item->type = Doc_BeginSection;
- item->string.string = str_alloc(text.size);
- copy(&item->string.string, text);
-
- append_child(parent, item);
-}
-
-internal void
-add_end_section(Abstract_Item *doc){
- Assert(doc->section_top + 1 < ArrayCount(doc->section_stack));
- Document_Item *parent = doc->section_stack[doc->section_top];
- Document_Item *item = fm_push_array(Document_Item, 1);
- *item = null_document_item;
- item->type = Doc_EndSection;
-
- append_child(parent, item);
-}
-
internal void
add_begin_list(Abstract_Item *doc){
Assert(doc->section_top + 1 < ArrayCount(doc->section_stack));
@@ -682,6 +680,8 @@ enum Command_Types{
Cmd_Section,
Cmd_EndSection,
Cmd_Version,
+ Cmd_TableOfContents,
+ Cmd_Todo,
// never below this
Cmd_COUNT,
};
@@ -696,7 +696,7 @@ get_enriched_commands(){
enriched_commands_global_array[Cmd_BackSlash] = make_lit_string("\\");
enriched_commands_global_array[Cmd_BeginStyle] = make_lit_string("BEGIN_STYLE");
enriched_commands_global_array[Cmd_EndStyle] = make_lit_string("END_STYLE");
- enriched_commands_global_array[Cmd_DocumentLink] = make_lit_string("DOC_LINK");
+ enriched_commands_global_array[Cmd_DocumentLink] = make_lit_string("DOC_LINK");
enriched_commands_global_array[Cmd_BeginList] = make_lit_string("BEGIN_LIST");
enriched_commands_global_array[Cmd_EndList] = make_lit_string("END_LIST");
enriched_commands_global_array[Cmd_BeginItem] = make_lit_string("BEGIN_ITEM");
@@ -708,6 +708,8 @@ get_enriched_commands(){
enriched_commands_global_array[Cmd_Section] = make_lit_string("SECTION");
enriched_commands_global_array[Cmd_EndSection] = make_lit_string("END_SECTION");
enriched_commands_global_array[Cmd_Version] = make_lit_string("VERSION");
+ enriched_commands_global_array[Cmd_TableOfContents] = make_lit_string("TABLE_OF_CONTENTS");
+ enriched_commands_global_array[Cmd_Todo] = make_lit_string("TODO");
}
return(enriched_commands_global_array);
}
@@ -765,12 +767,14 @@ extract_command_body(String l, i32 *i_in_out, String *body_text_out){
internal Abstract_Item*
make_document_from_text(Document_System *doc_system, char *title, char *name, Enriched_Text *text){
String source = text->source;
- Abstract_Item *doc = begin_document_description(doc_system, title, name, 0);
+ Abstract_Item *doc = begin_document_description(doc_system, title, name, false);
for (String line = get_first_double_line(source);
line.str;
line = get_next_double_line(source, line)){
String l = skip_chop_whitespace(line);
+ if (l.size == 0) continue;
+
add_begin_paragraph(doc);
i32 start = 0, i = 0;
@@ -819,7 +823,7 @@ make_document_from_text(Document_System *doc_system, char *title, char *name, En
add_begin_style(doc, body_text);
}
else{
- // TODO(allen):
+ report_error_missing_body(doc, command_string);
}
}break;
@@ -837,7 +841,7 @@ make_document_from_text(Document_System *doc_system, char *title, char *name, En
add_document_link(doc, body_text);
}
else{
- // TODO(allen):
+ report_error_missing_body(doc, command_string);
}
}break;
@@ -869,7 +873,7 @@ make_document_from_text(Document_System *doc_system, char *title, char *name, En
add_begin_link(doc, body_text);
}
else{
- // TODO(allen):
+ report_error_missing_body(doc, command_string);
}
}break;
@@ -888,7 +892,7 @@ make_document_from_text(Document_System *doc_system, char *title, char *name, En
add_image(doc, body_text, size_parameter);
}
else{
- // TODO(allen):
+ report_error_missing_body(doc, command_string);
}
}break;
@@ -900,7 +904,7 @@ make_document_from_text(Document_System *doc_system, char *title, char *name, En
add_video(doc, body_text);
}
else{
- // TODO(allen):
+ report_error_missing_body(doc, command_string);
}
}break;
@@ -911,16 +915,25 @@ make_document_from_text(Document_System *doc_system, char *title, char *name, En
if (has_body){
String extra_text = {0};
extract_command_body(l, &i, &extra_text);
- add_begin_section(doc, body_text);
+
+ String title = str_alloc(body_text.size + 1);
+ copy(&title, body_text);
+ terminate_with_null(&title);
+
+ String id = str_alloc(extra_text.size + 1);
+ copy(&id, extra_text);
+ terminate_with_null(&id);
+
+ begin_section(doc, title.str, id.str);
}
else{
- // TODO(allen):
+ report_error_missing_body(doc, command_string);
}
}break;
case Cmd_EndSection:
{
- add_end_section(doc);
+ end_section(doc);
}break;
case Cmd_Version:
@@ -928,14 +941,34 @@ make_document_from_text(Document_System *doc_system, char *title, char *name, En
add_version(doc);
}break;
+ case Cmd_TableOfContents:
+ {
+ add_table_of_contents(doc);
+ }break;
+
+ case Cmd_Todo:
+ {
+ add_todo(doc);
+ }break;
+
default:
{
- // TODO(allen):
+ char space[512];
+ String error = make_fixed_width_string(space);
+ append(&error, "unrecognized command ");
+ append(&error, command_string);
+ add_error(doc, error);
}break;
}
+
+ start = i;
}
}
+ if (start != i){
+ add_plain_old_text(doc, substr(l, start, i - start));
+ }
+
add_end_paragraph(doc);
}
@@ -1029,14 +1062,24 @@ append_section_number(String *out, Section_Counter *section_counter){
append_section_number_reduced(out, section_counter, 0);
}
+#define ERROR_HTML_START "! generator error: "
+#define ERROR_HTML_END " !"
+
+internal void
+output_error(String *out, String error){
+ append(out, ERROR_HTML_START);
+ append(out, error);
+ append(out, ERROR_HTML_END);
+ fprintf(stdout, "error: %.*s\n", error.size, error.str);
+}
+
internal void
report_error_html_missing_body(String *out, String command_name){
-#define STR_START "! Doc generator error: missing body for "
-#define STR_SLOW " !"
- append(out, STR_START);
- append(out, command_name);
- append(out, STR_SLOW);
- fprintf(stdout, "error: missing body for %.*s\n", command_name.size, command_name.str);
+ char space[512];
+ String str = make_fixed_width_string(space);
+ append(&str, "missing body for ");
+ append(&str, command_name);
+ output_error(out, str);
}
internal void
@@ -1074,11 +1117,10 @@ html_render_section_header(String *out, String section_name, String section_id,
#define HTML_WIDTH 800
internal void
-output_plain_old_text(String *out, char *text, u32 length){
- String l = make_string(text, length);
+output_plain_old_text(String *out, String l){
u32 start = 0;
u32 i = 0;
- for (; i < length; ++i){
+ for (; i < (u32)l.size; ++i){
char ch = l.str[i];
switch (ch){
case '<':
@@ -1102,13 +1144,13 @@ output_plain_old_text(String *out, char *text, u32 length){
}
internal void
-output_begin_style(String *out, char *name, u32 length){
- String l = make_string(name, length);
+output_begin_style(String *out, String l){
if (match(l, "code")){
append(out, "");
}
else{
fprintf(stdout, "error: unrecognized style\n");
+ append(out, "");
}
}
@@ -1118,8 +1160,7 @@ output_end_style(String *out){
}
internal void
-output_document_link(String *out, char *name, u32 length){
- String l = make_string(name, length);
+output_document_link(String *out, String l){
append(out, "");
@@ -1128,8 +1169,7 @@ output_document_link(String *out, char *name, u32 length){
}
internal void
-output_begin_link(Document_System *doc_system, String *out, char *name, u32 length){
- String l = make_string(name, length);
+output_begin_link(Document_System *doc_system, String *out, String l){
append(out, " ");
}
else{
- append(out, "! Doc generator error: unrecognized video type !");
- fprintf(stdout, "error: unrecognized video type %.*s\n", l.size, l.str);
+ char space[512];
+ String str = make_fixed_width_string(space);
+ append(&str, "unrecognized video type ");
+ append(&str, l);
+ output_error(out, str);
}
}
@@ -1240,9 +1278,8 @@ output_end_paragraph(String *out){
}
internal void
-output_begin_section(String *out, Section_Counter *section_counter, char *name, u32 length){
- String l = make_string(name, length);
- html_render_section_header(out, l, null_string, section_counter);
+output_begin_section(String *out, Section_Counter *section_counter, String l, String l2){
+ html_render_section_header(out, l, l2, section_counter);
++section_counter->nest_level;
section_counter->list_item_counter = 0;
}
@@ -1254,8 +1291,7 @@ output_end_section(String *out, Section_Counter *section_counter){
++section_counter->counter[section_counter->nest_level];
}
else{
- append(out, "! Doc generator error: unmatched section end !");
- fprintf(stdout, "error: unmatched section end\n");
+ output_error(out, make_lit_string("unmatched section end"));
}
}
@@ -1302,7 +1338,7 @@ write_enriched_text_html(String *out, Enriched_Text *text, Document_System *doc_
for (; i < l.size; ++i){
char ch = l.str[i];
if (ch == '\\'){
- output_plain_old_text(out, l.str + start, i - start);
+ output_plain_old_text(out, substr(l, start, i - start));
i32 command_start = i + 1;
i32 command_end = command_start;
@@ -1338,7 +1374,7 @@ write_enriched_text_html(String *out, Enriched_Text *text, Document_System *doc_
String body_text = {0};
b32 has_body = extract_command_body(l, &i, &body_text);
if (has_body){
- output_begin_style(out, body_text.str, body_text.size);
+ output_begin_style(out, body_text);
}
else{
report_error_html_missing_body(out, command_string);
@@ -1356,7 +1392,7 @@ write_enriched_text_html(String *out, Enriched_Text *text, Document_System *doc_
String body_text = {0};
b32 has_body = extract_command_body(l, &i, &body_text);
if (has_body){
- output_document_link(out, body_text.str, body_text.size);
+ output_document_link(out, body_text);
}
else{
report_error_html_missing_body(out, command_string);
@@ -1388,7 +1424,7 @@ write_enriched_text_html(String *out, Enriched_Text *text, Document_System *doc_
String body_text = {0};
b32 has_body = extract_command_body(l, &i, &body_text);
if (has_body){
- output_begin_link(doc_system, out, body_text.str, body_text.size);
+ output_begin_link(doc_system, out, body_text);
}
else{
report_error_html_missing_body(out, command_string);
@@ -1407,7 +1443,7 @@ write_enriched_text_html(String *out, Enriched_Text *text, Document_System *doc_
if (has_body){
String size_parameter = {0};
extract_command_body(l, &i, &size_parameter);
- output_image(doc_system, out, body_text.str, body_text.size, size_parameter.str, size_parameter.size);
+ output_image(doc_system, out, body_text, size_parameter);
}
else{
report_error_html_missing_body(out, command_string);
@@ -1419,7 +1455,7 @@ write_enriched_text_html(String *out, Enriched_Text *text, Document_System *doc_
String body_text = {0};
b32 has_body = extract_command_body(l, &i, &body_text);
if (has_body){
- output_video(out, body_text.str, body_text.size);
+ output_video(out, body_text);
}
else{
report_error_html_missing_body(out, command_string);
@@ -1433,7 +1469,7 @@ write_enriched_text_html(String *out, Enriched_Text *text, Document_System *doc_
if (has_body){
String extra_text = {0};
extract_command_body(l, &i, &extra_text);
- output_begin_section(out, section_counter, body_text.str, body_text.size);
+ output_begin_section(out, section_counter, body_text, extra_text);
}
else{
report_error_html_missing_body(out, command_string);
@@ -1450,10 +1486,19 @@ write_enriched_text_html(String *out, Enriched_Text *text, Document_System *doc_
append(out, VERSION);
}break;
+ case Cmd_TableOfContents:
+ {
+ String str = make_lit_string("Cmd_TableOfContents does not work in this system");
+ output_error(out, str);
+ }break;
+
default:
{
- append(out, "! Doc generator error: unrecognized command !");
- fprintf(stdout, "error: unrecognized command %.*s\n", command_string.size, command_string.str);
+ char space[512];
+ String str = make_fixed_width_string(space);
+ append(&str, "unrecognized command ");
+ append(&str, command_string);
+ output_error(out, str);
}break;
}
@@ -1462,7 +1507,7 @@ write_enriched_text_html(String *out, Enriched_Text *text, Document_System *doc_
}
if (start != i){
- output_plain_old_text(out, l.str + start, i - start);
+ output_plain_old_text(out, substr(l, start, i - start));
}
output_end_paragraph(out);
@@ -2162,6 +2207,13 @@ doc_item_html(String *out, Document_System *doc_system, Used_Links *used_links,
}
}break;
+ case Doc_Error:
+ {
+ if (head){
+ output_error(out, item->string.string);
+ }
+ }break;
+
case Doc_Todo:
{
if (head){
@@ -2272,7 +2324,7 @@ doc_item_html(String *out, Document_System *doc_system, Used_Links *used_links,
case Doc_PlainOldText:
{
if (head){
- output_plain_old_text(out, item->string.string.str, item->string.string.size);
+ output_plain_old_text(out, item->string.string);
}
}break;
@@ -2286,7 +2338,7 @@ doc_item_html(String *out, Document_System *doc_system, Used_Links *used_links,
case Doc_BeginStyle:
{
if (head){
- output_begin_style(out, item->string.string.str, item->string.string.size);
+ output_begin_style(out, item->string.string);
}
}break;
@@ -2300,14 +2352,14 @@ doc_item_html(String *out, Document_System *doc_system, Used_Links *used_links,
case Doc_DocumentLink:
{
if (head){
- output_document_link(out, item->string.string.str, item->string.string.size);
+ output_document_link(out, item->string.string);
}
}break;
case Doc_BeginLink:
{
if (head){
- output_begin_link(doc_system, out, item->string.string.str, item->string.string.size);
+ output_begin_link(doc_system, out, item->string.string);
}
}break;
@@ -2321,14 +2373,14 @@ doc_item_html(String *out, Document_System *doc_system, Used_Links *used_links,
case Doc_Image:
{
if (head){
- output_image(doc_system, out, item->string.string.str, item->string.string.size, item->string.string2.str, item->string.string2.size);
+ output_image(doc_system, out, item->string.string, item->string.string2);
}
}break;
case Doc_Video:
{
if (head){
- output_video(out, item->string.string.str, item->string.string.size);
+ output_video(out, item->string.string);
}
}break;
@@ -2346,21 +2398,6 @@ doc_item_html(String *out, Document_System *doc_system, Used_Links *used_links,
}
}break;
- // HACK(allen): There is also a Doc_Section type item where the section is actually a parent to the children and begin/end are handled by the one item. That should be the only type.
- case Doc_BeginSection:
- {
- if (head){
- output_begin_section(out, section_counter, item->string.string.str, item->string.string.size);
- }
- }break;
-
- case Doc_EndSection:
- {
- if (head){
- output_end_section(out, section_counter);
- }
- }break;
-
case Doc_BeginList:
{
if (head){
diff --git a/site/4ed_sitegen.cpp b/site/4ed_sitegen.cpp
index 086ee85c..571577cf 100644
--- a/site/4ed_sitegen.cpp
+++ b/site/4ed_sitegen.cpp
@@ -109,7 +109,7 @@ generate_4coder_docs(Document_System *doc_system, char *code_directory, char *sr
*lexer_introduction = load_enriched_text(src_directory, "lexer_introduction.txt");
// NOTE(allen): Put together the abstract document
- Abstract_Item *doc = begin_document_description(doc_system, "4coder API Docs", "custom_docs", 1);
+ Abstract_Item *doc = begin_document_description(doc_system, "4coder API Docs", "custom_docs", true);
add_table_of_contents(doc);
diff --git a/site/source_material/docs.txt b/site/source_material/docs.txt
index dc7df435..d9debc3a 100644
--- a/site/source_material/docs.txt
+++ b/site/source_material/docs.txt
@@ -38,7 +38,7 @@
\END_SECTION
\END_SECTION
-\SECTION{String Library}
+\SECTION{String Library}{string_library}
\SECTION{String Library Intro}
\TODO
\END_SECTION
@@ -52,7 +52,7 @@
\END_SECTION
\END_SECTION
-\SECTION{Lexer Library}
+\SECTION{Lexer Library}{lexer_library}
\SECTION{Lexer Intro}
\INCLUDE{lexer_introduction.txt}
\END_SECTION
diff --git a/site/source_material/tutorials.txt b/site/source_material/tutorials.txt
index c96864da..321d38f2 100644
--- a/site/source_material/tutorials.txt
+++ b/site/source_material/tutorials.txt
@@ -5,19 +5,19 @@
Getting started with 4coder and navigating your files:
-\VIDEO{youtube:https://www.youtube.com/embed/h5cbOcnSrcc}
+\VIDEO{youtube:h5cbOcnSrcc}
Setting up and navigating your project with 4coder:
-\VIDEO{youtube:https://www.youtube.com/embed/glPEpaT6GH0}
+\VIDEO{youtube:glPEpaT6GH0}
Extending your project with a project.4coder file:
-\VIDEO{youtube:https://www.youtube.com/embed/iZLtS3IoatE}
+\VIDEO{youtube:iZLtS3IoatE}
Using customizable keywords in the 4coder custom API:
-\VIDEO{youtube:https://www.youtube.com/watch?v=qoEvc4uC9Uw}
+\VIDEO{youtube:qoEvc4uC9Uw}
More tutorials coming soon.
diff --git a/string/4coder_string_build_num.txt b/string/4coder_string_build_num.txt
index 694ecf9f..0a5554c6 100644
--- a/string/4coder_string_build_num.txt
+++ b/string/4coder_string_build_num.txt
@@ -1,5 +1,5 @@
1
0
-101
+102