You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucy.apache.org by nw...@apache.org on 2013/05/30 22:36:29 UTC

[lucy-commits] [11/26] git commit: refs/heads/separate-clownfish-wip2 - Add is_included member to CFCParcel

Add is_included member to CFCParcel

Needed to tell whether a parcel is from an include directory. Also add
CFCParcel_source_parcels which list all non-included parcels from source
directories.

TODO: Fix Perl bindings


Project: http://git-wip-us.apache.org/repos/asf/lucy/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy/commit/577de073
Tree: http://git-wip-us.apache.org/repos/asf/lucy/tree/577de073
Diff: http://git-wip-us.apache.org/repos/asf/lucy/diff/577de073

Branch: refs/heads/separate-clownfish-wip2
Commit: 577de07347f9207f933ad1ca8efba905b22bf260
Parents: 05fa068
Author: Nick Wellnhofer <we...@aevum.de>
Authored: Mon May 20 22:36:34 2013 +0200
Committer: Nick Wellnhofer <we...@aevum.de>
Committed: Thu May 30 22:30:17 2013 +0200

----------------------------------------------------------------------
 clownfish/compiler/perl/lib/Clownfish/CFC.xs |    6 +-
 clownfish/compiler/src/CFCHierarchy.c        |   18 +++++--
 clownfish/compiler/src/CFCParcel.c           |   52 +++++++++++++++++----
 clownfish/compiler/src/CFCParcel.h           |   19 ++++++--
 clownfish/compiler/src/CFCParseHeader.y      |    7 ++-
 clownfish/compiler/src/CFCTestClass.c        |    7 ++-
 clownfish/compiler/src/CFCTestParcel.c       |   22 +++++++--
 clownfish/compiler/src/CFCTestParser.c       |    8 +++-
 clownfish/compiler/src/CFCTestSymbol.c       |   12 ++++-
 clownfish/compiler/src/CFCTestType.c         |    9 ++--
 10 files changed, 123 insertions(+), 37 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/577de073/clownfish/compiler/perl/lib/Clownfish/CFC.xs
----------------------------------------------------------------------
diff --git a/clownfish/compiler/perl/lib/Clownfish/CFC.xs b/clownfish/compiler/perl/lib/Clownfish/CFC.xs
index 347ccca..6d3f4f2 100644
--- a/clownfish/compiler/perl/lib/Clownfish/CFC.xs
+++ b/clownfish/compiler/perl/lib/Clownfish/CFC.xs
@@ -1041,7 +1041,7 @@ _new(name_sv, cnick_sv, version)
 CODE:
     const char *name  = SvOK(name_sv)  ? SvPV_nolen(name_sv)  : NULL;
     const char *cnick = SvOK(cnick_sv) ? SvPV_nolen(cnick_sv) : NULL;
-    CFCParcel *self = CFCParcel_new(name, cnick, version);
+    CFCParcel *self = CFCParcel_new(name, cnick, version, false);
     RETVAL = S_cfcbase_to_perlref(self);
     CFCBase_decref((CFCBase*)self);
 OUTPUT: RETVAL
@@ -1050,7 +1050,7 @@ SV*
 _new_from_file(path)
     const char *path;
 CODE:
-    CFCParcel *self = CFCParcel_new_from_file(path);
+    CFCParcel *self = CFCParcel_new_from_file(path, false);
     RETVAL = S_cfcbase_to_perlref(self);
     CFCBase_decref((CFCBase*)self);
 OUTPUT: RETVAL
@@ -1059,7 +1059,7 @@ SV*
 _new_from_json(json)
     const char *json;
 CODE:
-    CFCParcel *self = CFCParcel_new_from_json(json);
+    CFCParcel *self = CFCParcel_new_from_json(json, false);
     RETVAL = S_cfcbase_to_perlref(self);
     CFCBase_decref((CFCBase*)self);
 OUTPUT: RETVAL

http://git-wip-us.apache.org/repos/asf/lucy/blob/577de073/clownfish/compiler/src/CFCHierarchy.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCHierarchy.c b/clownfish/compiler/src/CFCHierarchy.c
index 5c5b192..f5d40eb 100644
--- a/clownfish/compiler/src/CFCHierarchy.c
+++ b/clownfish/compiler/src/CFCHierarchy.c
@@ -58,6 +58,10 @@ struct CFCHierarchy {
     size_t num_classes;
 };
 
+typedef struct CFCParseParcelFilesContext {
+    int is_included;
+} CFCParseParcelFilesContext;
+
 // CFCUtil_walk() callback which parses .cfp files.
 static void
 S_parse_parcel_files(const char *path, void *context);
@@ -185,11 +189,14 @@ CFCHierarchy_add_include_dir(CFCHierarchy *self, const char *include_dir) {
 
 void
 CFCHierarchy_build(CFCHierarchy *self) {
+    CFCParseParcelFilesContext context;
+    context.is_included = false;
     for (size_t i = 0; self->sources[i] != NULL; i++) {
-        CFCUtil_walk(self->sources[i], S_parse_parcel_files, NULL);
+        CFCUtil_walk(self->sources[i], S_parse_parcel_files, &context);
     }
+    context.is_included = false;
     for (size_t i = 0; self->includes[i] != NULL; i++) {
-        CFCUtil_walk(self->includes[i], S_parse_parcel_files, NULL);
+        CFCUtil_walk(self->includes[i], S_parse_parcel_files, &context);
     }
     for (size_t i = 0; self->sources[i] != NULL; i++) {
         S_parse_cf_files(self, self->sources[i], 0);
@@ -207,8 +214,8 @@ CFCHierarchy_build(CFCHierarchy *self) {
 }
 
 static void
-S_parse_parcel_files(const char *path, void *context) {
-    (void)context; // unused
+S_parse_parcel_files(const char *path, void *arg) {
+    CFCParseParcelFilesContext *context = (CFCParseParcelFilesContext*)arg;
 
     // Ignore hidden files.
     if (strstr(path, CHY_DIR_SEP ".") != NULL) {
@@ -218,7 +225,8 @@ S_parse_parcel_files(const char *path, void *context) {
     // Parse .cfp files and register the parcels they define.
     size_t path_len = strlen(path);
     if (path_len > 4 && (strcmp((path + path_len - 4), ".cfp") == 0)) {
-        CFCParcel *parcel = CFCParcel_new_from_file(path);
+        CFCParcel *parcel = CFCParcel_new_from_file(path,
+                                                    context->is_included);
         CFCParcel *existing = CFCParcel_fetch(CFCParcel_get_name(parcel));
         if (existing) {
             if (!CFCParcel_equals(parcel, existing)) {

http://git-wip-us.apache.org/repos/asf/lucy/blob/577de073/clownfish/compiler/src/CFCParcel.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCParcel.c b/clownfish/compiler/src/CFCParcel.c
index 1cfe17e..f628f66 100644
--- a/clownfish/compiler/src/CFCParcel.c
+++ b/clownfish/compiler/src/CFCParcel.c
@@ -37,6 +37,7 @@ struct CFCParcel {
     char *prefix;
     char *Prefix;
     char *PREFIX;
+    int is_included;
 };
 
 static CFCParcel *default_parcel = NULL;
@@ -105,6 +106,27 @@ CFCParcel_register(CFCParcel *self) {
     registry[num_registered]   = NULL;
 }
 
+CFCParcel**
+CFCParcel_source_parcels(void) {
+    size_t size = (num_registered + 1) * sizeof(CFCParcel*);
+    CFCParcel **parcels = (CFCParcel**)MALLOCATE(size);
+    size_t n = 0;
+
+    for (size_t i = 0; registry[i]; ++i) {
+        CFCParcel  *parcel = registry[i];
+        const char *prefix = CFCParcel_get_prefix(parcel);
+
+        // Skip default and included parcels.
+        if (*prefix && !CFCParcel_included(parcel)) {
+            parcels[n++] = parcel;
+        }
+    }
+
+    parcels[n] = NULL;
+
+    return parcels;
+}
+
 void
 CFCParcel_reap_singletons(void) {
     for (size_t i = 0; i < num_registered; i++) {
@@ -133,14 +155,15 @@ static const CFCMeta CFCPARCEL_META = {
 };
 
 CFCParcel*
-CFCParcel_new(const char *name, const char *cnick, CFCVersion *version) {
+CFCParcel_new(const char *name, const char *cnick, CFCVersion *version,
+              int is_included) {
     CFCParcel *self = (CFCParcel*)CFCBase_allocate(&CFCPARCEL_META);
-    return CFCParcel_init(self, name, cnick, version);
+    return CFCParcel_init(self, name, cnick, version, is_included);
 }
 
 CFCParcel*
 CFCParcel_init(CFCParcel *self, const char *name, const char *cnick,
-               CFCVersion *version) {
+               CFCVersion *version, int is_included) {
     // Validate name.
     if (!name || !S_validate_name_or_cnick(name)) {
         CFCUtil_die("Invalid name: '%s'", name ? name : "[NULL]");
@@ -190,11 +213,14 @@ CFCParcel_init(CFCParcel *self, const char *name, const char *cnick,
     self->Prefix[prefix_len] = '\0';
     self->PREFIX[prefix_len] = '\0';
 
+    // Set is_included.
+    self->is_included = is_included;
+
     return self;
 }
 
 static CFCParcel*
-S_new_from_json(const char *json, const char *path) {
+S_new_from_json(const char *json, const char *path, int is_included) {
     JSONNode *parsed = S_parse_json_for_parcel(json);
     if (!parsed) {
         CFCUtil_die("Invalid JSON parcel definition in '%s'", path);
@@ -235,7 +261,7 @@ S_new_from_json(const char *json, const char *path) {
     if (!version) {
         CFCUtil_die("Missing required key 'version' (filepath '%s')", path);
     }
-    CFCParcel *self = CFCParcel_new(name, nickname, version);
+    CFCParcel *self = CFCParcel_new(name, nickname, version, is_included);
     CFCBase_decref((CFCBase*)version);
 
     for (size_t i = 0, max = parsed->num_kids; i < max; i += 2) {
@@ -257,15 +283,15 @@ S_new_from_json(const char *json, const char *path) {
 }
 
 CFCParcel*
-CFCParcel_new_from_json(const char *json) {
-    return S_new_from_json(json, "[NULL]");
+CFCParcel_new_from_json(const char *json, int is_included) {
+    return S_new_from_json(json, "[NULL]", is_included);
 }
 
 CFCParcel*
-CFCParcel_new_from_file(const char *path) {
+CFCParcel_new_from_file(const char *path, int is_included) {
     size_t len;
     char *json = CFCUtil_slurp_text(path, &len);
-    CFCParcel *self = S_new_from_json(json, path);
+    CFCParcel *self = S_new_from_json(json, path, is_included);
     FREEMEM(json);
     return self;
 }
@@ -284,7 +310,7 @@ CFCParcel_destroy(CFCParcel *self) {
 CFCParcel*
 CFCParcel_default_parcel(void) {
     if (default_parcel == NULL) {
-        default_parcel = CFCParcel_new("", "", NULL);
+        default_parcel = CFCParcel_new("", "", NULL, false);
     }
     return default_parcel;
 }
@@ -296,6 +322,7 @@ CFCParcel_equals(CFCParcel *self, CFCParcel *other) {
     if (CFCVersion_compare_to(self->version, other->version) != 0) {
         return false;
     }
+    if (self->is_included != other->is_included) { return false; }
     return true;
 }
 
@@ -329,6 +356,11 @@ CFCParcel_get_PREFIX(CFCParcel *self) {
     return self->PREFIX;
 }
 
+int
+CFCParcel_included(CFCParcel *self) {
+    return self->is_included;
+}
+
 /*****************************************************************************
  * The hack JSON parser coded up below is only meant to parse Clownfish parcel
  * file content.  It is limited in its capabilities because so little is legal

http://git-wip-us.apache.org/repos/asf/lucy/blob/577de073/clownfish/compiler/src/CFCParcel.h
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCParcel.h b/clownfish/compiler/src/CFCParcel.h
index 9ea3a4a..e77e5a8 100644
--- a/clownfish/compiler/src/CFCParcel.h
+++ b/clownfish/compiler/src/CFCParcel.h
@@ -50,6 +50,12 @@ CFCParcel_fetch(const char *name);
 void
 CFCParcel_register(CFCParcel *self);
 
+/** Return a NULL-terminated list of all registered parcels that are not
+ * included. Must be freed by the caller.
+ */
+CFCParcel**
+CFCParcel_source_parcels(void);
+
 /** Decref all singletons at shutdown.
  */
 void
@@ -57,17 +63,17 @@ CFCParcel_reap_singletons(void);
 
 CFCParcel*
 CFCParcel_new(const char *name, const char *cnick,
-              struct CFCVersion *version);
+              struct CFCVersion *version, int is_included);
 
 CFCParcel*
-CFCParcel_new_from_file(const char *path);
+CFCParcel_new_from_file(const char *path, int is_included);
 
 CFCParcel*
-CFCParcel_new_from_json(const char *json);
+CFCParcel_new_from_json(const char *json, int is_included);
 
 CFCParcel*
 CFCParcel_init(CFCParcel *self, const char *name, const char *cnick,
-               struct CFCVersion *version);
+               struct CFCVersion *version, int is_included);
 
 void
 CFCParcel_destroy(CFCParcel *self);
@@ -104,6 +110,11 @@ CFCParcel_get_Prefix(CFCParcel *self);
 const char*
 CFCParcel_get_PREFIX(CFCParcel *self);
 
+/** Return true if the parcel is from an include directory.
+ */
+int
+CFCParcel_included(CFCParcel *self);
+
 #ifdef __cplusplus
 }
 #endif

http://git-wip-us.apache.org/repos/asf/lucy/blob/577de073/clownfish/compiler/src/CFCParseHeader.y
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCParseHeader.y b/clownfish/compiler/src/CFCParseHeader.y
index 9b14db5..c9f9215 100644
--- a/clownfish/compiler/src/CFCParseHeader.y
+++ b/clownfish/compiler/src/CFCParseHeader.y
@@ -315,7 +315,12 @@ parcel_definition(A) ::= PARCEL qualified_id(B) SEMICOLON.
 {
     A = CFCParcel_fetch(B);
     if (!A) {
-        A = CFCParcel_new(B, NULL, NULL);
+        CFCFileSpec *file_spec = CFCParser_get_file_spec(state);
+        int is_included = false;
+        if (file_spec) {
+            is_included = CFCFileSpec_included(file_spec);
+        }
+        A = CFCParcel_new(B, NULL, NULL, is_included);
         CFCParcel_register(A);
         CFCBase_decref((CFCBase*)A);
     }

http://git-wip-us.apache.org/repos/asf/lucy/blob/577de073/clownfish/compiler/src/CFCTestClass.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTestClass.c b/clownfish/compiler/src/CFCTestClass.c
index 9f841f9..2eb4183 100644
--- a/clownfish/compiler/src/CFCTestClass.c
+++ b/clownfish/compiler/src/CFCTestClass.c
@@ -31,6 +31,11 @@
 #include "CFCUtil.h"
 #include "CFCVariable.h"
 
+#ifndef true
+  #define true 1
+  #define false 0
+#endif
+
 static void
 S_run_tests(CFCTest *test);
 
@@ -47,7 +52,7 @@ static void
 S_run_tests(CFCTest *test) {
     CFCParser *parser = CFCParser_new();
 
-    CFCParcel *neato = CFCParcel_new("Neato", NULL, NULL);
+    CFCParcel *neato = CFCParcel_new("Neato", NULL, NULL, false);
     CFCFileSpec *file_spec = CFCFileSpec_new(".", "Foo/FooJr", 0);
     CFCClass *thing_class
         = CFCTest_parse_class(test, parser, "class Thing {}");

http://git-wip-us.apache.org/repos/asf/lucy/blob/577de073/clownfish/compiler/src/CFCTestParcel.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTestParcel.c b/clownfish/compiler/src/CFCTestParcel.c
index e468e9f..9c63f18 100644
--- a/clownfish/compiler/src/CFCTestParcel.c
+++ b/clownfish/compiler/src/CFCTestParcel.c
@@ -23,20 +23,32 @@
 #include "CFCVersion.h"
 #include "CFCTest.h"
 
+#ifndef true
+  #define true 1
+  #define false 0
+#endif
+
 static void
 S_run_tests(CFCTest *test);
 
 const CFCTestBatch CFCTEST_BATCH_PARCEL = {
     "Clownfish::CFC::Model::Parcel",
-    10,
+    12,
     S_run_tests
 };
 
 static void
 S_run_tests(CFCTest *test) {
     {
-        CFCParcel *parcel = CFCParcel_new("Foo", NULL, NULL);
+        CFCParcel *parcel = CFCParcel_new("Foo", NULL, NULL, false);
         OK(test, parcel != NULL, "new");
+        OK(test, !CFCParcel_included(parcel), "not included");
+        CFCBase_decref((CFCBase*)parcel);
+    }
+
+    {
+        CFCParcel *parcel = CFCParcel_new("Foo", NULL, NULL, true);
+        OK(test, CFCParcel_included(parcel), "included");
         CFCBase_decref((CFCBase*)parcel);
     }
 
@@ -47,14 +59,14 @@ S_run_tests(CFCTest *test) {
             "            \"nickname\": \"Crust\",\n"
             "            \"version\": \"v0.1.0\"\n"
             "        }\n";
-        CFCParcel *parcel = CFCParcel_new_from_json(json);
+        CFCParcel *parcel = CFCParcel_new_from_json(json, false);
         OK(test, parcel != NULL, "new_from_json");
         CFCBase_decref((CFCBase*)parcel);
     }
 
     {
         const char *path = "t" CHY_DIR_SEP "cfsource" CHY_DIR_SEP "Animal.cfp";
-        CFCParcel *parcel = CFCParcel_new_from_file(path);
+        CFCParcel *parcel = CFCParcel_new_from_file(path, false);
         OK(test, parcel != NULL, "new_from_file");
         CFCBase_decref((CFCBase*)parcel);
     }
@@ -72,7 +84,7 @@ S_run_tests(CFCTest *test) {
     }
 
     {
-        CFCParcel *parcel = CFCParcel_new("Crustacean", "Crust", NULL);
+        CFCParcel *parcel = CFCParcel_new("Crustacean", "Crust", NULL, false);
         CFCParcel_register(parcel);
         STR_EQ(test, CFCVersion_get_vstring(CFCParcel_get_version(parcel)),
                "v0", "get_version");

http://git-wip-us.apache.org/repos/asf/lucy/blob/577de073/clownfish/compiler/src/CFCTestParser.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTestParser.c b/clownfish/compiler/src/CFCTestParser.c
index 46611dd..04c39e7 100644
--- a/clownfish/compiler/src/CFCTestParser.c
+++ b/clownfish/compiler/src/CFCTestParser.c
@@ -27,6 +27,11 @@
 #include "CFCUtil.h"
 #include "CFCVariable.h"
 
+#ifndef true
+  #define true 1
+  #define false 0
+#endif
+
 static void
 S_run_tests(CFCTest *test);
 
@@ -49,7 +54,8 @@ S_run_tests(CFCTest *test) {
     {
         CFCParcel *fish = CFCTest_parse_parcel(test, parser, "parcel Fish;");
 
-        CFCParcel *registered = CFCParcel_new("Crustacean", "Crust", NULL);
+        CFCParcel *registered
+            = CFCParcel_new("Crustacean", "Crust", NULL, false);
         CFCParcel_register(registered);
         CFCParcel *parcel
             = CFCTest_parse_parcel(test, parser, "parcel Crustacean;");

http://git-wip-us.apache.org/repos/asf/lucy/blob/577de073/clownfish/compiler/src/CFCTestSymbol.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTestSymbol.c b/clownfish/compiler/src/CFCTestSymbol.c
index 7dfe8d9..8f6518e 100644
--- a/clownfish/compiler/src/CFCTestSymbol.c
+++ b/clownfish/compiler/src/CFCTestSymbol.c
@@ -20,6 +20,11 @@
 #include "CFCSymbol.h"
 #include "CFCTest.h"
 
+#ifndef true
+  #define true 1
+  #define false 0
+#endif
+
 static void
 S_run_tests(CFCTest *test);
 
@@ -89,7 +94,8 @@ S_run_tests(CFCTest *test) {
     }
 
     {
-        CFCParcel *lucifer_parcel = CFCParcel_new("Lucifer", NULL, NULL);
+        CFCParcel *lucifer_parcel
+            = CFCParcel_new("Lucifer", NULL, NULL, false);
         CFCParcel_register(lucifer_parcel);
         CFCSymbol *lucifer
             = CFCSymbol_new(lucifer_parcel, "parcel", NULL, NULL, "sym");
@@ -103,7 +109,7 @@ S_run_tests(CFCTest *test) {
         const char *PREFIX = CFCSymbol_get_PREFIX(lucifer);
         STR_EQ(test, PREFIX, "LUCIFER_", "get_PREFIX");
 
-        CFCParcel *luser_parcel = CFCParcel_new("Luser", NULL, NULL);
+        CFCParcel *luser_parcel = CFCParcel_new("Luser", NULL, NULL, false);
         CFCParcel_register(luser_parcel);
         CFCSymbol *luser
             = CFCSymbol_new(luser_parcel, "parcel", NULL, NULL, "sym");
@@ -127,7 +133,7 @@ S_run_tests(CFCTest *test) {
     }
 
     {
-        CFCParcel *eep_parcel = CFCParcel_new("Eep", NULL, NULL);
+        CFCParcel *eep_parcel = CFCParcel_new("Eep", NULL, NULL, false);
         CFCParcel_register(eep_parcel);
         CFCSymbol *eep
             = CFCSymbol_new(eep_parcel, "parcel", "Op::Ork", NULL, "ah_ah");

http://git-wip-us.apache.org/repos/asf/lucy/blob/577de073/clownfish/compiler/src/CFCTestType.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTestType.c b/clownfish/compiler/src/CFCTestType.c
index 759aa42..9dc135f 100644
--- a/clownfish/compiler/src/CFCTestType.c
+++ b/clownfish/compiler/src/CFCTestType.c
@@ -79,7 +79,7 @@ S_run_tests(CFCTest *test) {
 
 static void
 S_run_basic_tests(CFCTest *test) {
-    CFCParcel *neato_parcel = CFCParcel_new("Neato", NULL, NULL);
+    CFCParcel *neato_parcel = CFCParcel_new("Neato", NULL, NULL, false);
     CFCParcel_register(neato_parcel);
     CFCType *type = CFCType_new(0, neato_parcel, "mytype_t", 0, NULL);
 
@@ -333,7 +333,7 @@ S_run_object_tests(CFCTest *test) {
         CFCBase_decref((CFCBase*)parser);
     }
 
-    CFCParcel *neato_parcel = CFCParcel_new("Neato", NULL, NULL);
+    CFCParcel *neato_parcel = CFCParcel_new("Neato", NULL, NULL, false);
     CFCClass *foo_class
         = CFCClass_create(neato_parcel, NULL, "Foo", NULL, NULL, NULL, NULL,
                           NULL, false, false);
@@ -356,7 +356,8 @@ S_run_object_tests(CFCTest *test) {
     }
 
     {
-        CFCParcel *foreign_parcel = CFCParcel_new("Foreign", NULL, NULL);
+        CFCParcel *foreign_parcel
+            = CFCParcel_new("Foreign", NULL, NULL, false);
         CFCClass *foreign_foo_class
             = CFCClass_create(foreign_parcel, NULL, "Foo", NULL, NULL, NULL,
                               NULL, NULL, false, false);
@@ -423,7 +424,7 @@ S_run_va_list_tests(CFCTest *test) {
 static void
 S_run_arbitrary_tests(CFCTest *test) {
     {
-        CFCParcel *neato_parcel = CFCParcel_new("Neato", NULL, NULL);
+        CFCParcel *neato_parcel = CFCParcel_new("Neato", NULL, NULL, false);
         CFCParcel_register(neato_parcel);
 
         CFCType *foo = CFCType_new_arbitrary(neato_parcel, "foo_t");