From 7eaccc0332830eb2cdff88495ce6a00f382f96ee Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Mon, 24 Oct 2022 00:53:51 +0200 Subject: [PATCH 01/16] examples/outline.c: Rename variable "p" to "parser" --- expat/examples/outline.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/expat/examples/outline.c b/expat/examples/outline.c index 936f0e09..4ff69ee2 100644 --- a/expat/examples/outline.c +++ b/expat/examples/outline.c @@ -85,16 +85,16 @@ end(void *data, const XML_Char *el) { int main(int argc, char *argv[]) { - XML_Parser p = XML_ParserCreate(NULL); + XML_Parser parser = XML_ParserCreate(NULL); (void)argc; (void)argv; - if (! p) { + if (! parser) { fprintf(stderr, "Couldn't allocate memory for parser\n"); exit(-1); } - XML_SetElementHandler(p, start, end); + XML_SetElementHandler(parser, start, end); for (;;) { int done; @@ -107,17 +107,17 @@ main(int argc, char *argv[]) { } done = feof(stdin); - if (XML_Parse(p, Buff, len, done) == XML_STATUS_ERROR) { + if (XML_Parse(parser, Buff, len, done) == XML_STATUS_ERROR) { fprintf(stderr, "Parse error at line %" XML_FMT_INT_MOD "u:\n%" XML_FMT_STR "\n", - XML_GetCurrentLineNumber(p), - XML_ErrorString(XML_GetErrorCode(p))); + XML_GetCurrentLineNumber(parser), + XML_ErrorString(XML_GetErrorCode(parser))); exit(-1); } if (done) break; } - XML_ParserFree(p); + XML_ParserFree(parser); return 0; } From bd351fad2003e419fffa69fb0df87b3a021d3145 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Mon, 24 Oct 2022 00:58:25 +0200 Subject: [PATCH 02/16] examples/outline.c: Make "Buff" a local variable --- expat/examples/outline.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/expat/examples/outline.c b/expat/examples/outline.c index 4ff69ee2..5b179692 100644 --- a/expat/examples/outline.c +++ b/expat/examples/outline.c @@ -53,8 +53,6 @@ #define BUFFSIZE 8192 -char Buff[BUFFSIZE]; - int Depth; static void XMLCALL @@ -85,6 +83,7 @@ end(void *data, const XML_Char *el) { int main(int argc, char *argv[]) { + char Buff[BUFFSIZE]; XML_Parser parser = XML_ParserCreate(NULL); (void)argc; (void)argv; From 56d85659ac7bd3b3487c1cf698a15a547efe9047 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Mon, 24 Oct 2022 01:28:42 +0200 Subject: [PATCH 03/16] examples/outline.c: Rename "Buff" to "buf" for consistency across examples --- expat/examples/outline.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/expat/examples/outline.c b/expat/examples/outline.c index 5b179692..e403040e 100644 --- a/expat/examples/outline.c +++ b/expat/examples/outline.c @@ -83,7 +83,7 @@ end(void *data, const XML_Char *el) { int main(int argc, char *argv[]) { - char Buff[BUFFSIZE]; + char buf[BUFFSIZE]; XML_Parser parser = XML_ParserCreate(NULL); (void)argc; (void)argv; @@ -99,14 +99,14 @@ main(int argc, char *argv[]) { int done; int len; - len = (int)fread(Buff, 1, BUFFSIZE, stdin); + len = (int)fread(buf, 1, BUFFSIZE, stdin); if (ferror(stdin)) { fprintf(stderr, "Read error\n"); exit(-1); } done = feof(stdin); - if (XML_Parse(parser, Buff, len, done) == XML_STATUS_ERROR) { + if (XML_Parse(parser, buf, len, done) == XML_STATUS_ERROR) { fprintf(stderr, "Parse error at line %" XML_FMT_INT_MOD "u:\n%" XML_FMT_STR "\n", XML_GetCurrentLineNumber(parser), From 9c7bd378b6b008b99018d4374a2ec4172e9e4898 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Mon, 24 Oct 2022 01:30:24 +0200 Subject: [PATCH 04/16] examples: Resolve use of unused variables argc and argv --- expat/examples/elements.c | 4 +--- expat/examples/outline.c | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/expat/examples/elements.c b/expat/examples/elements.c index 481d4447..0c959f35 100644 --- a/expat/examples/elements.c +++ b/expat/examples/elements.c @@ -76,13 +76,11 @@ endElement(void *userData, const XML_Char *name) { } int -main(int argc, char *argv[]) { +main(void) { char buf[BUFSIZ]; XML_Parser parser = XML_ParserCreate(NULL); int done; int depth = 0; - (void)argc; - (void)argv; XML_SetUserData(parser, &depth); XML_SetElementHandler(parser, startElement, endElement); diff --git a/expat/examples/outline.c b/expat/examples/outline.c index e403040e..db36a503 100644 --- a/expat/examples/outline.c +++ b/expat/examples/outline.c @@ -82,11 +82,9 @@ end(void *data, const XML_Char *el) { } int -main(int argc, char *argv[]) { +main(void) { char buf[BUFFSIZE]; XML_Parser parser = XML_ParserCreate(NULL); - (void)argc; - (void)argv; if (! parser) { fprintf(stderr, "Couldn't allocate memory for parser\n"); From fcb91e43bd4fe0ef21f1797f94b6ea02d03fcab9 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Mon, 24 Oct 2022 01:35:06 +0200 Subject: [PATCH 05/16] examples: Make passing of depth pointer consistent across examples --- expat/examples/elements.c | 4 ++-- expat/examples/outline.c | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/expat/examples/elements.c b/expat/examples/elements.c index 0c959f35..1361edd8 100644 --- a/expat/examples/elements.c +++ b/expat/examples/elements.c @@ -58,7 +58,7 @@ static void XMLCALL startElement(void *userData, const XML_Char *name, const XML_Char **atts) { int i; - int *depthPtr = (int *)userData; + int *const depthPtr = (int *)userData; (void)atts; for (i = 0; i < *depthPtr; i++) @@ -69,7 +69,7 @@ startElement(void *userData, const XML_Char *name, const XML_Char **atts) { static void XMLCALL endElement(void *userData, const XML_Char *name) { - int *depthPtr = (int *)userData; + int *const depthPtr = (int *)userData; (void)name; *depthPtr -= 1; diff --git a/expat/examples/outline.c b/expat/examples/outline.c index db36a503..0efa0eae 100644 --- a/expat/examples/outline.c +++ b/expat/examples/outline.c @@ -53,14 +53,12 @@ #define BUFFSIZE 8192 -int Depth; - static void XMLCALL start(void *data, const XML_Char *el, const XML_Char **attr) { int i; - (void)data; + int *const depthPtr = (int *)data; - for (i = 0; i < Depth; i++) + for (i = 0; i < *depthPtr; i++) printf(" "); printf("%" XML_FMT_STR, el); @@ -70,27 +68,29 @@ start(void *data, const XML_Char *el, const XML_Char **attr) { } printf("\n"); - Depth++; + *depthPtr += 1; } static void XMLCALL end(void *data, const XML_Char *el) { - (void)data; + int *const depthPtr = (int *)data; (void)el; - Depth--; + *depthPtr -= 1; } int main(void) { char buf[BUFFSIZE]; XML_Parser parser = XML_ParserCreate(NULL); + int depth = 0; if (! parser) { fprintf(stderr, "Couldn't allocate memory for parser\n"); exit(-1); } + XML_SetUserData(parser, &depth); XML_SetElementHandler(parser, start, end); for (;;) { From 93a757ab7dfde74327da6316fbaddde13f56ae77 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Mon, 24 Oct 2022 01:36:26 +0200 Subject: [PATCH 06/16] examples/outline.c: Make use of BUFSIZ from stdio.h consistent across examples --- expat/examples/outline.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/expat/examples/outline.c b/expat/examples/outline.c index 0efa0eae..048c83c0 100644 --- a/expat/examples/outline.c +++ b/expat/examples/outline.c @@ -51,8 +51,6 @@ # define XML_FMT_STR "s" #endif -#define BUFFSIZE 8192 - static void XMLCALL start(void *data, const XML_Char *el, const XML_Char **attr) { int i; @@ -81,7 +79,7 @@ end(void *data, const XML_Char *el) { int main(void) { - char buf[BUFFSIZE]; + char buf[BUFSIZ]; XML_Parser parser = XML_ParserCreate(NULL); int depth = 0; @@ -97,7 +95,7 @@ main(void) { int done; int len; - len = (int)fread(buf, 1, BUFFSIZE, stdin); + len = (int)fread(buf, 1, BUFSIZ, stdin); if (ferror(stdin)) { fprintf(stderr, "Read error\n"); exit(-1); From 023b95dba00117cd1fed2d8a97ce80331376a1f9 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Mon, 24 Oct 2022 01:45:47 +0200 Subject: [PATCH 07/16] examples/outline.c: Make element handler signatures consistent across examples --- expat/examples/outline.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/expat/examples/outline.c b/expat/examples/outline.c index 048c83c0..6d51a35d 100644 --- a/expat/examples/outline.c +++ b/expat/examples/outline.c @@ -52,17 +52,17 @@ #endif static void XMLCALL -start(void *data, const XML_Char *el, const XML_Char **attr) { +startElement(void *userData, const XML_Char *name, const XML_Char **atts) { int i; - int *const depthPtr = (int *)data; + int *const depthPtr = (int *)userData; for (i = 0; i < *depthPtr; i++) printf(" "); - printf("%" XML_FMT_STR, el); + printf("%" XML_FMT_STR, name); - for (i = 0; attr[i]; i += 2) { - printf(" %" XML_FMT_STR "='%" XML_FMT_STR "'", attr[i], attr[i + 1]); + for (i = 0; atts[i]; i += 2) { + printf(" %" XML_FMT_STR "='%" XML_FMT_STR "'", atts[i], atts[i + 1]); } printf("\n"); @@ -70,9 +70,9 @@ start(void *data, const XML_Char *el, const XML_Char **attr) { } static void XMLCALL -end(void *data, const XML_Char *el) { - int *const depthPtr = (int *)data; - (void)el; +endElement(void *userData, const XML_Char *name) { + int *const depthPtr = (int *)userData; + (void)name; *depthPtr -= 1; } @@ -89,7 +89,7 @@ main(void) { } XML_SetUserData(parser, &depth); - XML_SetElementHandler(parser, start, end); + XML_SetElementHandler(parser, startElement, endElement); for (;;) { int done; From 2b3b95c670a58ce9f79b42772261f10ddb1c5430 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Mon, 24 Oct 2022 01:50:03 +0200 Subject: [PATCH 08/16] examples/outline.c: Be consistent in main loop exit across examples --- expat/examples/outline.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/expat/examples/outline.c b/expat/examples/outline.c index 6d51a35d..d553d234 100644 --- a/expat/examples/outline.c +++ b/expat/examples/outline.c @@ -81,6 +81,7 @@ int main(void) { char buf[BUFSIZ]; XML_Parser parser = XML_ParserCreate(NULL); + int done; int depth = 0; if (! parser) { @@ -90,9 +91,7 @@ main(void) { XML_SetUserData(parser, &depth); XML_SetElementHandler(parser, startElement, endElement); - - for (;;) { - int done; + do { int len; len = (int)fread(buf, 1, BUFSIZ, stdin); @@ -109,10 +108,7 @@ main(void) { XML_ErrorString(XML_GetErrorCode(parser))); exit(-1); } - - if (done) - break; - } + } while (! done); XML_ParserFree(parser); return 0; } From 37386fd2d3fa798f3c5bd94366f3efe66e31dec5 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Mon, 24 Oct 2022 01:53:06 +0200 Subject: [PATCH 09/16] examples/elements.c: Be consistent in parse error reporting format across examples --- expat/examples/elements.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/expat/examples/elements.c b/expat/examples/elements.c index 1361edd8..cf7d29e2 100644 --- a/expat/examples/elements.c +++ b/expat/examples/elements.c @@ -88,9 +88,10 @@ main(void) { size_t len = fread(buf, 1, sizeof(buf), stdin); done = len < sizeof(buf); if (XML_Parse(parser, buf, (int)len, done) == XML_STATUS_ERROR) { - fprintf(stderr, "%" XML_FMT_STR " at line %" XML_FMT_INT_MOD "u\n", - XML_ErrorString(XML_GetErrorCode(parser)), - XML_GetCurrentLineNumber(parser)); + fprintf(stderr, + "Parse error at line %" XML_FMT_INT_MOD "u:\n%" XML_FMT_STR "\n", + XML_GetCurrentLineNumber(parser), + XML_ErrorString(XML_GetErrorCode(parser))); XML_ParserFree(parser); return 1; } From 894b98d9b39a5ffa26caaff4cc9444c14642cb87 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Mon, 24 Oct 2022 01:40:33 +0200 Subject: [PATCH 10/16] examples: Be consistent across examples regarding read looping and main exit --- expat/examples/elements.c | 12 ++++++++++-- expat/examples/outline.c | 14 ++++++++------ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/expat/examples/elements.c b/expat/examples/elements.c index cf7d29e2..a2673d37 100644 --- a/expat/examples/elements.c +++ b/expat/examples/elements.c @@ -85,8 +85,16 @@ main(void) { XML_SetUserData(parser, &depth); XML_SetElementHandler(parser, startElement, endElement); do { - size_t len = fread(buf, 1, sizeof(buf), stdin); - done = len < sizeof(buf); + const size_t len = fread(buf, 1, sizeof(buf), stdin); + + if (ferror(stdin)) { + fprintf(stderr, "Read error\n"); + XML_ParserFree(parser); + return 1; + } + + done = feof(stdin); + if (XML_Parse(parser, buf, (int)len, done) == XML_STATUS_ERROR) { fprintf(stderr, "Parse error at line %" XML_FMT_INT_MOD "u:\n%" XML_FMT_STR "\n", diff --git a/expat/examples/outline.c b/expat/examples/outline.c index d553d234..4f2490f3 100644 --- a/expat/examples/outline.c +++ b/expat/examples/outline.c @@ -86,27 +86,29 @@ main(void) { if (! parser) { fprintf(stderr, "Couldn't allocate memory for parser\n"); - exit(-1); + return 1; } XML_SetUserData(parser, &depth); XML_SetElementHandler(parser, startElement, endElement); do { - int len; + const size_t len = fread(buf, 1, sizeof(buf), stdin); - len = (int)fread(buf, 1, BUFSIZ, stdin); if (ferror(stdin)) { fprintf(stderr, "Read error\n"); - exit(-1); + XML_ParserFree(parser); + return 1; } + done = feof(stdin); - if (XML_Parse(parser, buf, len, done) == XML_STATUS_ERROR) { + if (XML_Parse(parser, buf, (int)len, done) == XML_STATUS_ERROR) { fprintf(stderr, "Parse error at line %" XML_FMT_INT_MOD "u:\n%" XML_FMT_STR "\n", XML_GetCurrentLineNumber(parser), XML_ErrorString(XML_GetErrorCode(parser))); - exit(-1); + XML_ParserFree(parser); + return 1; } } while (! done); XML_ParserFree(parser); From 77409cde885f54d9a8be4a18ec5b88c0935cc8bb Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Mon, 24 Oct 2022 02:04:45 +0200 Subject: [PATCH 11/16] examples/elements.c: Be consistent across examples regarding OOM detection --- expat/examples/elements.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/expat/examples/elements.c b/expat/examples/elements.c index a2673d37..f0497ece 100644 --- a/expat/examples/elements.c +++ b/expat/examples/elements.c @@ -82,6 +82,11 @@ main(void) { int done; int depth = 0; + if (! parser) { + fprintf(stderr, "Couldn't allocate memory for parser\n"); + return 1; + } + XML_SetUserData(parser, &depth); XML_SetElementHandler(parser, startElement, endElement); do { From 2f38031778d6512f3e6b684492b4d0cc3428baef Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Mon, 24 Oct 2022 02:10:03 +0200 Subject: [PATCH 12/16] examples/elements.c: Resolve unused include of --- expat/examples/elements.c | 1 - 1 file changed, 1 deletion(-) diff --git a/expat/examples/elements.c b/expat/examples/elements.c index f0497ece..6a96fb4e 100644 --- a/expat/examples/elements.c +++ b/expat/examples/elements.c @@ -49,7 +49,6 @@ #endif #ifdef XML_UNICODE_WCHAR_T -# include # define XML_FMT_STR "ls" #else # define XML_FMT_STR "s" From dbf1202529f7a531e65c43f0db2324520a85d10a Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Mon, 24 Oct 2022 02:20:04 +0200 Subject: [PATCH 13/16] examples: Make use of XML_GetBuffer --- expat/examples/elements.c | 12 +++++++++--- expat/examples/outline.c | 12 +++++++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/expat/examples/elements.c b/expat/examples/elements.c index 6a96fb4e..1a3c786d 100644 --- a/expat/examples/elements.c +++ b/expat/examples/elements.c @@ -76,7 +76,6 @@ endElement(void *userData, const XML_Char *name) { int main(void) { - char buf[BUFSIZ]; XML_Parser parser = XML_ParserCreate(NULL); int done; int depth = 0; @@ -89,7 +88,14 @@ main(void) { XML_SetUserData(parser, &depth); XML_SetElementHandler(parser, startElement, endElement); do { - const size_t len = fread(buf, 1, sizeof(buf), stdin); + void *const buf = XML_GetBuffer(parser, BUFSIZ); + if (! buf) { + fprintf(stderr, "Couldn't allocate memory for buffer\n"); + XML_ParserFree(parser); + return 1; + } + + const size_t len = fread(buf, 1, BUFSIZ, stdin); if (ferror(stdin)) { fprintf(stderr, "Read error\n"); @@ -99,7 +105,7 @@ main(void) { done = feof(stdin); - if (XML_Parse(parser, buf, (int)len, done) == XML_STATUS_ERROR) { + if (XML_ParseBuffer(parser, (int)len, done) == XML_STATUS_ERROR) { fprintf(stderr, "Parse error at line %" XML_FMT_INT_MOD "u:\n%" XML_FMT_STR "\n", XML_GetCurrentLineNumber(parser), diff --git a/expat/examples/outline.c b/expat/examples/outline.c index 4f2490f3..d154e33b 100644 --- a/expat/examples/outline.c +++ b/expat/examples/outline.c @@ -79,7 +79,6 @@ endElement(void *userData, const XML_Char *name) { int main(void) { - char buf[BUFSIZ]; XML_Parser parser = XML_ParserCreate(NULL); int done; int depth = 0; @@ -92,7 +91,14 @@ main(void) { XML_SetUserData(parser, &depth); XML_SetElementHandler(parser, startElement, endElement); do { - const size_t len = fread(buf, 1, sizeof(buf), stdin); + void *const buf = XML_GetBuffer(parser, BUFSIZ); + if (! buf) { + fprintf(stderr, "Couldn't allocate memory for buffer\n"); + XML_ParserFree(parser); + return 1; + } + + const size_t len = fread(buf, 1, BUFSIZ, stdin); if (ferror(stdin)) { fprintf(stderr, "Read error\n"); @@ -102,7 +108,7 @@ main(void) { done = feof(stdin); - if (XML_Parse(parser, buf, (int)len, done) == XML_STATUS_ERROR) { + if (XML_ParseBuffer(parser, (int)len, done) == XML_STATUS_ERROR) { fprintf(stderr, "Parse error at line %" XML_FMT_INT_MOD "u:\n%" XML_FMT_STR "\n", XML_GetCurrentLineNumber(parser), From 9294082e74b4845191ccc695cdf16eb53a0d3f9d Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Mon, 24 Oct 2022 02:26:10 +0200 Subject: [PATCH 14/16] examples: Add some whitespace for readability --- expat/examples/elements.c | 2 ++ expat/examples/outline.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/expat/examples/elements.c b/expat/examples/elements.c index 1a3c786d..5098d7d9 100644 --- a/expat/examples/elements.c +++ b/expat/examples/elements.c @@ -87,6 +87,7 @@ main(void) { XML_SetUserData(parser, &depth); XML_SetElementHandler(parser, startElement, endElement); + do { void *const buf = XML_GetBuffer(parser, BUFSIZ); if (! buf) { @@ -114,6 +115,7 @@ main(void) { return 1; } } while (! done); + XML_ParserFree(parser); return 0; } diff --git a/expat/examples/outline.c b/expat/examples/outline.c index d154e33b..d23fa94b 100644 --- a/expat/examples/outline.c +++ b/expat/examples/outline.c @@ -90,6 +90,7 @@ main(void) { XML_SetUserData(parser, &depth); XML_SetElementHandler(parser, startElement, endElement); + do { void *const buf = XML_GetBuffer(parser, BUFSIZ); if (! buf) { @@ -117,6 +118,7 @@ main(void) { return 1; } } while (! done); + XML_ParserFree(parser); return 0; } From a608db28836e18c809cc4a3afc1ba8fa38872d29 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Mon, 24 Oct 2022 02:33:34 +0200 Subject: [PATCH 15/16] cmake: Resolve duplication related to building examples --- expat/CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/expat/CMakeLists.txt b/expat/CMakeLists.txt index a1ffe874..2bf0bcbe 100644 --- a/expat/CMakeLists.txt +++ b/expat/CMakeLists.txt @@ -580,12 +580,12 @@ endif() # if(EXPAT_BUILD_EXAMPLES) add_executable(elements examples/elements.c) - set_property(TARGET elements PROPERTY RUNTIME_OUTPUT_DIRECTORY examples) - target_link_libraries(elements expat) - add_executable(outline examples/outline.c) - set_property(TARGET outline PROPERTY RUNTIME_OUTPUT_DIRECTORY examples) - target_link_libraries(outline expat) + + foreach(_target elements outline) + set_property(TARGET ${_target} PROPERTY RUNTIME_OUTPUT_DIRECTORY examples) + target_link_libraries(${_target} expat) + endforeach() endif() # From 55ca00111253d8735ea78fbec63431403cbb6cb6 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Mon, 24 Oct 2022 15:18:12 +0200 Subject: [PATCH 16/16] Changes: Document #666 --- expat/Changes | 2 ++ 1 file changed, 2 insertions(+) diff --git a/expat/Changes b/expat/Changes index ea7d7e4c..2e8b2669 100644 --- a/expat/Changes +++ b/expat/Changes @@ -13,6 +13,8 @@ Release x.x.x xxx xxxxxxxxxxxx xx xxxx Other changes: #663 Protect header expat_config.h from multiple inclusion + #666 examples: Make use of XML_GetBuffer and be more + consistent across examples #648 Address compiler warnings Special thanks to: