{"thread":{"id":"40100","subject":"[PATCH v11 06/13] ref-filter: add option to filter out tags, branches and remotes","startedAt":"2015-08-15T18:00:36Z","lastAt":"2015-08-17T14:46:43Z","messageCount":4,"participants":["Karthik Nayak","Eric Sunshine"],"isPatch":true,"patchVersion":11,"patchTotal":13},"messages":[{"id":"268131","messageId":"1439661643-16094-7-git-send-email-Karthik.188@gmail.com","threadId":"40100","inReplyTo":null,"subject":"[PATCH v11 06/13] ref-filter: add option to filter out tags, branches and remotes","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-08-15T18:00:36Z","receivedAt":"2015-08-15T18:00:36Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"From: Karthik Nayak <karthik.188@gmail.com>\n\nAdd a function called 'for_each_reftype_fullpath()' to refs.{c,h}\nwhich iterates through each ref for the given path without trimming\nthe path and also accounting for broken refs, if mentioned.\n\nAdd 'filter_ref_kind()' in ref-filter.c to check the kind of ref being\nhandled and return the kind to 'ref_filter_handler()', where we\ndiscard refs which we do not need and assign the kind to needed refs.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n ref-filter.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----\n ref-filter.h | 12 ++++++++++--\n refs.c       |  7 +++++++\n refs.h       |  1 +\n 4 files changed, 72 insertions(+), 7 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex eac99d0..abcd235 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1098,6 +1098,36 @@ static struct ref_array_item *new_ref_array_item(const char *refname,\n \treturn ref;\n }\n \n+static int filter_ref_kind(struct ref_filter *filter, const char *refname)\n+{\n+\tunsigned int i;\n+\n+\tstatic struct {\n+\t\tconst char *prefix;\n+\t\tunsigned int kind;\n+\t} ref_kind[] = {\n+\t\t{ \"refs/heads/\" , FILTER_REFS_BRANCHES },\n+\t\t{ \"refs/remotes/\" , FILTER_REFS_REMOTES },\n+\t\t{ \"refs/tags/\", FILTER_REFS_TAGS}\n+\t};\n+\n+\tif (filter->kind == FILTER_REFS_BRANCHES)\n+\t\treturn FILTER_REFS_BRANCHES;\n+\telse if (filter->kind == FILTER_REFS_REMOTES)\n+\t\treturn FILTER_REFS_REMOTES;\n+\telse if (filter->kind == FILTER_REFS_TAGS)\n+\t\treturn FILTER_REFS_TAGS;\n+\telse if (!strcmp(refname, \"HEAD\"))\n+\t\treturn FILTER_REFS_DETACHED_HEAD;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(ref_kind); i++) {\n+\t\tif (starts_with(refname, ref_kind[i].prefix))\n+\t\t\treturn ref_kind[i].kind;\n+\t}\n+\n+\treturn FILTER_REFS_OTHERS;\n+}\n+\n /*\n  * A call-back given to for_each_ref().  Filter refs and keep them for\n  * later object processing.\n@@ -1108,6 +1138,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n \tstruct ref_filter *filter = ref_cbdata->filter;\n \tstruct ref_array_item *ref;\n \tstruct commit *commit = NULL;\n+\tunsigned int kind;\n \n \tif (flag & REF_BAD_NAME) {\n \t\twarning(\"ignoring ref with broken name %s\", refname);\n@@ -1119,6 +1150,10 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n \t\treturn 0;\n \t}\n \n+\tkind = filter_ref_kind(filter, refname);\n+\tif (!(kind & filter->kind))\n+\t\treturn 0;\n+\n \tif (*filter->name_patterns && !match_name_as_path(filter->name_patterns, refname))\n \t\treturn 0;\n \n@@ -1150,6 +1185,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n \n \tREALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);\n \tref_cbdata->array->items[ref_cbdata->array->nr++] = ref;\n+\tref->kind = kind;\n \treturn 0;\n }\n \n@@ -1226,16 +1262,29 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int\n {\n \tstruct ref_filter_cbdata ref_cbdata;\n \tint ret = 0;\n+\tunsigned int broken = 0;\n \n \tref_cbdata.array = array;\n \tref_cbdata.filter = filter;\n \n \t/*  Simple per-ref filtering */\n-\tif (type & (FILTER_REFS_ALL | FILTER_REFS_INCLUDE_BROKEN))\n-\t\tret = for_each_rawref(ref_filter_handler, &ref_cbdata);\n-\telse if (type & FILTER_REFS_ALL)\n-\t\tret = for_each_ref(ref_filter_handler, &ref_cbdata);\n-\telse if (type)\n+\tif (type & FILTER_REFS_INCLUDE_BROKEN) {\n+\t\ttype -= FILTER_REFS_INCLUDE_BROKEN;\n+\t\tbroken = 1;\n+\t}\n+\n+\tfilter->kind = type;\n+\tif (type == FILTER_REFS_BRANCHES)\n+\t\tret = for_each_reftype_fullpath(ref_filter_handler, \"refs/heads/\", broken, &ref_cbdata);\n+\telse if (type == FILTER_REFS_REMOTES)\n+\t\tret = for_each_reftype_fullpath(ref_filter_handler, \"refs/remotes/\", broken, &ref_cbdata);\n+\telse if (type == FILTER_REFS_TAGS)\n+\t\tret = for_each_reftype_fullpath(ref_filter_handler, \"refs/tags/\", broken, &ref_cbdata);\n+\telse if (type & FILTER_REFS_ALL) {\n+\t\tret = for_each_reftype_fullpath(ref_filter_handler, \"\", broken, &ref_cbdata);\n+\t\tif (type & FILTER_REFS_DETACHED_HEAD)\n+\t\t\thead_ref(ref_filter_handler, &ref_cbdata);\n+\t} else\n \t\tdie(\"filter_refs: invalid type\");\n \n \t/*  Filters that need revision walking */\ndiff --git a/ref-filter.h b/ref-filter.h\nindex 144a633..64fedd3 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -14,8 +14,14 @@\n #define QUOTE_PYTHON 4\n #define QUOTE_TCL 8\n \n-#define FILTER_REFS_INCLUDE_BROKEN 0x1\n-#define FILTER_REFS_ALL 0x2\n+#define FILTER_REFS_INCLUDE_BROKEN 0x0001\n+#define FILTER_REFS_TAGS           0x0002\n+#define FILTER_REFS_BRANCHES       0x0004\n+#define FILTER_REFS_REMOTES        0x0008\n+#define FILTER_REFS_OTHERS         0x0010\n+#define FILTER_REFS_ALL            (FILTER_REFS_TAGS | FILTER_REFS_BRANCHES | \\\n+\t\t\t\t    FILTER_REFS_REMOTES | FILTER_REFS_OTHERS)\n+#define FILTER_REFS_DETACHED_HEAD  0x0020\n \n struct atom_value;\n \n@@ -28,6 +34,7 @@ struct ref_sorting {\n struct ref_array_item {\n \tunsigned char objectname[20];\n \tint flag;\n+\tunsigned int kind;\n \tconst char *symref;\n \tstruct commit *commit;\n \tstruct atom_value *value;\n@@ -52,6 +59,7 @@ struct ref_filter {\n \tstruct commit *merge_commit;\n \n \tunsigned int with_commit_tag_algo : 1;\n+\tunsigned int kind;\n };\n \n struct ref_filter_cbdata {\ndiff --git a/refs.c b/refs.c\nindex 2db2975..0f18c34 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -2145,6 +2145,13 @@ int for_each_replace_ref(each_ref_fn fn, void *cb_data)\n \t\t\t       strlen(git_replace_ref_base), 0, cb_data);\n }\n \n+int for_each_reftype_fullpath(each_ref_fn fn, char *type, unsigned int broken, void *cb_data)\n+{\n+\tif (broken)\n+\t\tbroken = DO_FOR_EACH_INCLUDE_BROKEN;\n+\treturn do_for_each_ref(&ref_cache, type, fn, 0, broken, cb_data);\n+}\n+\n int head_ref_namespaced(each_ref_fn fn, void *cb_data)\n {\n \tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/refs.h b/refs.h\nindex 6a3fa6d..7f91a72 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -179,6 +179,7 @@ extern int for_each_remote_ref(each_ref_fn fn, void *cb_data);\n extern int for_each_replace_ref(each_ref_fn fn, void *cb_data);\n extern int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data);\n extern int for_each_glob_ref_in(each_ref_fn fn, const char *pattern, const char *prefix, void *cb_data);\n+extern int for_each_reftype_fullpath(each_ref_fn fn, char *type, unsigned int broken, void *cb_data);\n \n extern int head_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data);\n extern int for_each_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data);\n-- \n2.5.0\n"},{"id":"268161","messageId":"CAPig+cTZvSW8ZRLFLhmQTYBwotVjMWANZy0OAZHpA79vW8GfGQ@mail.gmail.com","threadId":"40100","inReplyTo":"1439661643-16094-7-git-send-email-Karthik.188@gmail.com","subject":"Re: [PATCH v11 06/13] ref-filter: add option to filter out tags, branches and remotes","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-08-17T04:42:52Z","receivedAt":"2015-08-17T04:42:52Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sat, Aug 15, 2015 at 2:00 PM, Karthik Nayak <karthik.188@gmail.com> wrote:\n> Add a function called 'for_each_reftype_fullpath()' to refs.{c,h}\n> which iterates through each ref for the given path without trimming\n> the path and also accounting for broken refs, if mentioned.\n>\n> Add 'filter_ref_kind()' in ref-filter.c to check the kind of ref being\n> handled and return the kind to 'ref_filter_handler()', where we\n> discard refs which we do not need and assign the kind to needed refs.\n>\n> Signed-off-by: Karthik Nayak <karthik.188@gmail.com>\n> ---\n> diff --git a/ref-filter.c b/ref-filter.c\n> index eac99d0..abcd235 100644\n> --- a/ref-filter.c\n> +++ b/ref-filter.c\n> @@ -1226,16 +1262,29 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int\n>  {\n>         struct ref_filter_cbdata ref_cbdata;\n>         int ret = 0;\n> +       unsigned int broken = 0;\n>\n>         ref_cbdata.array = array;\n>         ref_cbdata.filter = filter;\n>\n>         /*  Simple per-ref filtering */\n> -       if (type & (FILTER_REFS_ALL | FILTER_REFS_INCLUDE_BROKEN))\n> -               ret = for_each_rawref(ref_filter_handler, &ref_cbdata);\n> -       else if (type & FILTER_REFS_ALL)\n> -               ret = for_each_ref(ref_filter_handler, &ref_cbdata);\n> -       else if (type)\n> +       if (type & FILTER_REFS_INCLUDE_BROKEN) {\n> +               type -= FILTER_REFS_INCLUDE_BROKEN;\n\nThe above is a somewhat unusual way to say the more idiomatic:\n\n    type &= ~FILTER_REFS_INCLUDE_BROKEN;\n\nwhen dealing with bit flags. Is there precedence elsewhere in the\nproject for choosing '-' over '~'?\n\n> +               broken = 1;\n> +       }\n> +\n> +       filter->kind = type;\n> +       if (type == FILTER_REFS_BRANCHES)\n> +               ret = for_each_reftype_fullpath(ref_filter_handler, \"refs/heads/\", broken, &ref_cbdata);\n> +       else if (type == FILTER_REFS_REMOTES)\n> +               ret = for_each_reftype_fullpath(ref_filter_handler, \"refs/remotes/\", broken, &ref_cbdata);\n> +       else if (type == FILTER_REFS_TAGS)\n> +               ret = for_each_reftype_fullpath(ref_filter_handler, \"refs/tags/\", broken, &ref_cbdata);\n> +       else if (type & FILTER_REFS_ALL) {\n> +               ret = for_each_reftype_fullpath(ref_filter_handler, \"\", broken, &ref_cbdata);\n\nThese cases are all the same except for the (string) second argument,\naren't they? This might be less noisy and easier to follow if you\nassign the appropriate string to a variable first, and then invoke\nfor_each_reftype_fullpath() once with the string variable as an\nargument.\n\n> +               if (type & FILTER_REFS_DETACHED_HEAD)\n> +                       head_ref(ref_filter_handler, &ref_cbdata);\n> +       } else\n>                 die(\"filter_refs: invalid type\");\n>\n>         /*  Filters that need revision walking */\n> diff --git a/ref-filter.h b/ref-filter.h\n> index 144a633..64fedd3 100644\n> --- a/ref-filter.h\n> +++ b/ref-filter.h\n> @@ -14,8 +14,14 @@\n> -#define FILTER_REFS_INCLUDE_BROKEN 0x1\n> -#define FILTER_REFS_ALL 0x2\n> +#define FILTER_REFS_INCLUDE_BROKEN 0x0001\n> +#define FILTER_REFS_TAGS           0x0002\n> +#define FILTER_REFS_BRANCHES       0x0004\n> +#define FILTER_REFS_REMOTES        0x0008\n> +#define FILTER_REFS_OTHERS         0x0010\n> +#define FILTER_REFS_ALL            (FILTER_REFS_TAGS | FILTER_REFS_BRANCHES | \\\n> +                                   FILTER_REFS_REMOTES | FILTER_REFS_OTHERS)\n> +#define FILTER_REFS_DETACHED_HEAD  0x0020\n\nI suppose there's some good reason that FILTER_REFS_DETACHED_HEAD is\nnot a member of FILTER_REFS_ALL? Perhaps add a comment explaining it?\n\n> diff --git a/refs.c b/refs.c\n> index 2db2975..0f18c34 100644\n> --- a/refs.c\n> +++ b/refs.c\n> @@ -2145,6 +2145,13 @@ int for_each_replace_ref(each_ref_fn fn, void *cb_data)\n>                                strlen(git_replace_ref_base), 0, cb_data);\n>  }\n>\n> +int for_each_reftype_fullpath(each_ref_fn fn, char *type, unsigned int broken, void *cb_data)\n> +{\n> +       if (broken)\n> +               broken = DO_FOR_EACH_INCLUDE_BROKEN;\n\nIt's a bit ugly and confusing to have the same variable, 'broken', act\nas both a boolean input argument and as a bit flag argument to the\ncalled function.\n\n> +       return do_for_each_ref(&ref_cache, type, fn, 0, broken, cb_data);\n> +}\n> +\n>  int head_ref_namespaced(each_ref_fn fn, void *cb_data)\n>  {\n>         struct strbuf buf = STRBUF_INIT;\n"},{"id":"268164","messageId":"CAPig+cQjtFHZgUvCVxTcXRCPykFN=RG5=bvkqF04h1MupPJV5g@mail.gmail.com","threadId":"40100","inReplyTo":"CAPig+cTZvSW8ZRLFLhmQTYBwotVjMWANZy0OAZHpA79vW8GfGQ@mail.gmail.com","subject":"Re: [PATCH v11 06/13] ref-filter: add option to filter out tags, branches and remotes","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-08-17T05:14:51Z","receivedAt":"2015-08-17T05:14:51Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, Aug 17, 2015 at 12:42 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> On Sat, Aug 15, 2015 at 2:00 PM, Karthik Nayak <karthik.188@gmail.com> wrote:\n>> -       if (type & (FILTER_REFS_ALL | FILTER_REFS_INCLUDE_BROKEN))\n>> -               ret = for_each_rawref(ref_filter_handler, &ref_cbdata);\n>> -       else if (type & FILTER_REFS_ALL)\n>> -               ret = for_each_ref(ref_filter_handler, &ref_cbdata);\n>> -       else if (type)\n>> +       if (type & FILTER_REFS_INCLUDE_BROKEN) {\n>> +               type -= FILTER_REFS_INCLUDE_BROKEN;\n>\n> The above is a somewhat unusual way to say the more idiomatic:\n>\n>     type &= ~FILTER_REFS_INCLUDE_BROKEN;\n>\n> when dealing with bit flags. Is there precedence elsewhere in the\n> project for choosing '-' over '~'?\n\ns/precedence/precedent/\n"},{"id":"268185","messageId":"CAOLa=ZRqs4fWOn_5s18KbacYgV0ti5G1idXdEc4H5Hz0=p9UFA@mail.gmail.com","threadId":"40100","inReplyTo":"CAPig+cTZvSW8ZRLFLhmQTYBwotVjMWANZy0OAZHpA79vW8GfGQ@mail.gmail.com","subject":"Re: [PATCH v11 06/13] ref-filter: add option to filter out tags, branches and remotes","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-08-17T14:46:43Z","receivedAt":"2015-08-17T14:46:43Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On Mon, Aug 17, 2015 at 10:12 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> On Sat, Aug 15, 2015 at 2:00 PM, Karthik Nayak <karthik.188@gmail.com> wrote:\n>> Add a function called 'for_each_reftype_fullpath()' to refs.{c,h}\n>> which iterates through each ref for the given path without trimming\n>> the path and also accounting for broken refs, if mentioned.\n>>\n>> Add 'filter_ref_kind()' in ref-filter.c to check the kind of ref being\n>> handled and return the kind to 'ref_filter_handler()', where we\n>> discard refs which we do not need and assign the kind to needed refs.\n>>\n>> Signed-off-by: Karthik Nayak <karthik.188@gmail.com>\n>> ---\n>> diff --git a/ref-filter.c b/ref-filter.c\n>> index eac99d0..abcd235 100644\n>> --- a/ref-filter.c\n>> +++ b/ref-filter.c\n>> @@ -1226,16 +1262,29 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int\n>>  {\n>>         struct ref_filter_cbdata ref_cbdata;\n>>         int ret = 0;\n>> +       unsigned int broken = 0;\n>>\n>>         ref_cbdata.array = array;\n>>         ref_cbdata.filter = filter;\n>>\n>>         /*  Simple per-ref filtering */\n>> -       if (type & (FILTER_REFS_ALL | FILTER_REFS_INCLUDE_BROKEN))\n>> -               ret = for_each_rawref(ref_filter_handler, &ref_cbdata);\n>> -       else if (type & FILTER_REFS_ALL)\n>> -               ret = for_each_ref(ref_filter_handler, &ref_cbdata);\n>> -       else if (type)\n>> +       if (type & FILTER_REFS_INCLUDE_BROKEN) {\n>> +               type -= FILTER_REFS_INCLUDE_BROKEN;\n>\n> The above is a somewhat unusual way to say the more idiomatic:\n>\n>     type &= ~FILTER_REFS_INCLUDE_BROKEN;\n>\n> when dealing with bit flags. Is there precedence elsewhere in the\n> project for choosing '-' over '~'?\n>\n\nI just preferred it this way, but will change it.\n\n>> +               broken = 1;\n>> +       }\n>> +\n>> +       filter->kind = type;\n>> +       if (type == FILTER_REFS_BRANCHES)\n>> +               ret = for_each_reftype_fullpath(ref_filter_handler, \"refs/heads/\", broken, &ref_cbdata);\n>> +       else if (type == FILTER_REFS_REMOTES)\n>> +               ret = for_each_reftype_fullpath(ref_filter_handler, \"refs/remotes/\", broken, &ref_cbdata);\n>> +       else if (type == FILTER_REFS_TAGS)\n>> +               ret = for_each_reftype_fullpath(ref_filter_handler, \"refs/tags/\", broken, &ref_cbdata);\n>> +       else if (type & FILTER_REFS_ALL) {\n>> +          e      ret = for_each_reftype_fullpath(ref_filter_handler, \"\", broken, &ref_cbdata);\n>\n> These cases are all the same except for the (string) second argument,\n> aren't they? This might be less noisy and easier to follow if you\n> assign the appropriate string to a variable first, and then invoke\n> for_each_reftype_fullpath() once with the string variable as an\n> argument.\n>\n\nThe problem is when we have FILTER_REFS_DETACHED_HEAD we need\nto call head_ref() after collecting all other refs, this is because in\nbranch.c we\nneed to print the detached head first, hence it's inserted to the end of the\nref_array. Doing it the way you suggested would require to check FILTER_REFS_ALL\nagain after the first time for setting the string variable. I'd find\nthat a bit more\nconfusing.\n\n>> +               if (type & FILTER_REFS_DETACHED_HEAD)\n>> +                       head_ref(ref_filter_handler, &ref_cbdata);\n>> +       } else\n>>                 die(\"filter_refs: invalid type\");\n>>\n>>         /*  Filters that need revision walking */\n>> diff --git a/ref-filter.h b/ref-filter.h\n>> index 144a633..64fedd3 100644\n>> --- a/ref-filter.h\n>> +++ b/ref-filter.h\n>> @@ -14,8 +14,14 @@\n>> -#define FILTER_REFS_INCLUDE_BROKEN 0x1\n>> -#define FILTER_REFS_ALL 0x2\n>> +#define FILTER_REFS_INCLUDE_BROKEN 0x0001\n>> +#define FILTER_REFS_TAGS           0x0002\n>> +#define FILTER_REFS_BRANCHES       0x0004\n>> +#define FILTER_REFS_REMOTES        0x0008\n>> +#define FILTER_REFS_OTHERS         0x0010\n>> +#define FILTER_REFS_ALL            (FILTER_REFS_TAGS | FILTER_REFS_BRANCHES | \\\n>> +                                   FILTER_REFS_REMOTES | FILTER_REFS_OTHERS)\n>> +#define FILTER_REFS_DETACHED_HEAD  0x0020\n>\n> I suppose there's some good reason that FILTER_REFS_DETACHED_HEAD is\n> not a member of FILTER_REFS_ALL? Perhaps add a comment explaining it?\n>\n>> diff --git a/refs.c b/refs.c\n>> index 2db2975..0f18c34 100644\n>> --- a/refs.c\n>> +++ b/refs.c\n>> @@ -2145,6 +2145,13 @@ int for_each_replace_ref(each_ref_fn fn, void *cb_data)\n>>                                strlen(git_replace_ref_base), 0, cb_data);\n>>  }\n>>\n>> +int for_each_reftype_fullpath(each_ref_fn fn, char *type, unsigned int broken, void *cb_data)\n>> +{\n>> +       if (broken)\n>> +               broken = DO_FOR_EACH_INCLUDE_BROKEN;\n>\n> It's a bit ugly and confusing to have the same variable, 'broken', act\n> as both a boolean input argument and as a bit flag argument to the\n> called function.\n>\n\nIll change that :)\n\n-- \nRegards,\nKarthik Nayak\n"}]}