diff options
author | Sam Thursfield <sam@afuera.me.uk> | 2022-03-27 22:43:17 +0000 |
---|---|---|
committer | Sam Thursfield <sam@afuera.me.uk> | 2022-03-27 22:43:17 +0000 |
commit | 282f55f349f1310b21d81d782f6bdb923697152e (patch) | |
tree | 927cde051e0d3bef3a04f21355c29aa21e4fb246 | |
parent | 60046b2bcd21ec4e4866d73d9167cc0633efedb6 (diff) | |
parent | 7ab14938c335aab539e67ef8768316b377e7a1d2 (diff) | |
download | tracker-282f55f349f1310b21d81d782f6bdb923697152e.tar.gz |
Merge branch 'wip/carlosg/more-sparql-fixes' into 'master'
Sparql compliance fixes
See merge request GNOME/tracker!503
30 files changed, 139 insertions, 48 deletions
diff --git a/src/libtracker-data/tracker-sparql-grammar.h b/src/libtracker-data/tracker-sparql-grammar.h index 8835539ad..673c39721 100644 --- a/src/libtracker-data/tracker-sparql-grammar.h +++ b/src/libtracker-data/tracker-sparql-grammar.h @@ -556,7 +556,7 @@ static const TrackerGrammarRule rule_iri[] = { OR(helper_iri_or), NIL }; * TRACKER EXTENSION: * The terminal PARAMETERIZED_VAR is additionally accepted */ -static const TrackerGrammarRule helper_String_or[] = { T(STRING_LITERAL1), T(STRING_LITERAL2), T(STRING_LITERAL_LONG1), T(STRING_LITERAL_LONG2), T(PARAMETERIZED_VAR), NIL }; +static const TrackerGrammarRule helper_String_or[] = { T(STRING_LITERAL_LONG1), T(STRING_LITERAL_LONG2), T(STRING_LITERAL1), T(STRING_LITERAL2), T(PARAMETERIZED_VAR), NIL }; static const TrackerGrammarRule rule_String[] = { OR(helper_String_or), NIL }; /* BooleanLiteral ::= 'true' | 'false' diff --git a/src/libtracker-data/tracker-sparql-types.c b/src/libtracker-data/tracker-sparql-types.c index 9211ddbf2..50ad62c05 100644 --- a/src/libtracker-data/tracker-sparql-types.c +++ b/src/libtracker-data/tracker-sparql-types.c @@ -560,7 +560,8 @@ tracker_path_element_property_new (TrackerPathOperator op, g_return_val_if_fail (TRACKER_IS_PROPERTY (prop), NULL); g_return_val_if_fail (op == TRACKER_PATH_OPERATOR_NONE || - op == TRACKER_PATH_OPERATOR_NEGATED, NULL); + op == TRACKER_PATH_OPERATOR_NEGATED || + op == TRACKER_PATH_OPERATOR_NEGATED_INVERSE, NULL); elem = g_new0 (TrackerPathElement, 1); elem->op = op; @@ -631,6 +632,9 @@ tracker_path_element_set_unique_name (TrackerPathElement *elem, case TRACKER_PATH_OPERATOR_INTERSECTION: name = "intersect"; break; + case TRACKER_PATH_OPERATOR_NEGATED_INVERSE: + name = "neg_inv"; + break; default: g_assert_not_reached (); } diff --git a/src/libtracker-data/tracker-sparql-types.h b/src/libtracker-data/tracker-sparql-types.h index 3829fd1d6..23bb06ea0 100644 --- a/src/libtracker-data/tracker-sparql-types.h +++ b/src/libtracker-data/tracker-sparql-types.h @@ -160,6 +160,7 @@ typedef enum { TRACKER_PATH_OPERATOR_ZEROORMORE, /* * */ TRACKER_PATH_OPERATOR_NEGATED, /* ! */ TRACKER_PATH_OPERATOR_INTERSECTION, /* Used for negated paths */ + TRACKER_PATH_OPERATOR_NEGATED_INVERSE, /* !^, used for negated paths */ } TrackerPathOperator; struct _TrackerPathElement { diff --git a/src/libtracker-data/tracker-sparql.c b/src/libtracker-data/tracker-sparql.c index d32005212..98cd0711e 100644 --- a/src/libtracker-data/tracker-sparql.c +++ b/src/libtracker-data/tracker-sparql.c @@ -1093,12 +1093,22 @@ _prepend_path_element (TrackerSparql *sparql, path_elem->data.composite.child1->name); break; case TRACKER_PATH_OPERATOR_NEGATED: - _append_string_printf (sparql, - "\"%s\" (ID, value, graph, ID_type, value_type) AS " - "(SELECT subject AS ID, object AS value, graph, %d, object_type " - "FROM \"tracker_triples\" ", - path_elem->name, - TRACKER_PROPERTY_TYPE_RESOURCE); + case TRACKER_PATH_OPERATOR_NEGATED_INVERSE: + if (path_elem->op == TRACKER_PATH_OPERATOR_NEGATED) { + _append_string_printf (sparql, + "\"%s\" (ID, value, graph, ID_type, value_type) AS " + "(SELECT subject AS ID, object_raw AS value, graph, %d, object_type " + "FROM \"tracker_triples\" ", + path_elem->name, + TRACKER_PROPERTY_TYPE_RESOURCE); + } else { + _append_string_printf (sparql, + "\"%s\" (ID, value, graph, ID_type, value_type) AS " + "(SELECT object_raw AS ID, subject AS value, graph, object_type, %d " + "FROM \"tracker_triples\" ", + path_elem->name, + TRACKER_PROPERTY_TYPE_RESOURCE); + } if (!tracker_token_is_empty (&sparql->current_state->graph) && tracker_sparql_find_graph (sparql, tracker_token_get_idstring (&sparql->current_state->graph))) { @@ -6928,6 +6938,45 @@ translate_PathPrimary (TrackerSparql *sparql, return TRUE; } +static TrackerPathElement * +intersect_path_elements (TrackerSparql *sparql, + GPtrArray *path_elems) +{ + TrackerPathElement *elem; + + if (path_elems->len == 0) + return NULL; + + if (path_elems->len == 1) + return g_ptr_array_index (path_elems, 0); + + if (path_elems->len > 1) { + guint i; + + elem = tracker_path_element_operator_new (TRACKER_PATH_OPERATOR_INTERSECTION, + tracker_token_get_idstring (&sparql->current_state->graph), + g_ptr_array_index (path_elems, 0), + g_ptr_array_index (path_elems, 1)); + tracker_select_context_add_path_element (TRACKER_SELECT_CONTEXT (sparql->context), + elem); + _prepend_path_element (sparql, elem); + + for (i = 2; i < path_elems->len; i++) { + TrackerPathElement *child; + + child = g_ptr_array_index (path_elems, i); + elem = tracker_path_element_operator_new (TRACKER_PATH_OPERATOR_INTERSECTION, + tracker_token_get_idstring (&sparql->current_state->graph), + child, elem); + tracker_select_context_add_path_element (TRACKER_SELECT_CONTEXT (sparql->context), + elem); + _prepend_path_element (sparql, elem); + } + } + + return elem; +} + static gboolean translate_PathNegatedPropertySet (TrackerSparql *sparql, GError **error) @@ -6939,45 +6988,47 @@ translate_PathNegatedPropertySet (TrackerSparql *sparql, if (_check_in_rule (sparql, NAMED_RULE_PathOneInPropertySet)) _call_rule (sparql, NAMED_RULE_PathOneInPropertySet, error); else if (_accept (sparql, RULE_TYPE_LITERAL, LITERAL_OPEN_PARENS)) { - GPtrArray *path_elems; + TrackerPathElement *negated, *negated_inverse; + GPtrArray *negated_elems, *negated_inverse_elems; - path_elems = g_ptr_array_new (); + negated_elems = g_ptr_array_new (); + negated_inverse_elems = g_ptr_array_new (); - _call_rule (sparql, NAMED_RULE_PathEltOrInverse, error); - g_ptr_array_add (path_elems, sparql->current_state->path); + _call_rule (sparql, NAMED_RULE_PathOneInPropertySet, error); + g_ptr_array_add (sparql->current_state->path->op == TRACKER_PATH_OPERATOR_NEGATED ? + negated_elems : negated_inverse_elems, + sparql->current_state->path); - while (_check_in_rule (sparql, NAMED_RULE_PathOneInPropertySet)) { + while (_accept (sparql, RULE_TYPE_LITERAL, LITERAL_PATH_ALTERNATIVE)) { _call_rule (sparql, NAMED_RULE_PathOneInPropertySet, error); - g_ptr_array_add (path_elems, sparql->current_state->path); + g_ptr_array_add (sparql->current_state->path->op == TRACKER_PATH_OPERATOR_NEGATED ? + negated_elems : negated_inverse_elems, + sparql->current_state->path); } - if (path_elems->len > 1) { - guint i; + negated = intersect_path_elements (sparql, negated_elems); + negated_inverse = intersect_path_elements (sparql, negated_inverse_elems); - path_elem = tracker_path_element_operator_new (TRACKER_PATH_OPERATOR_INTERSECTION, + if (negated && negated_inverse) { + path_elem = tracker_path_element_operator_new (TRACKER_PATH_OPERATOR_ALTERNATIVE, tracker_token_get_idstring (&sparql->current_state->graph), - g_ptr_array_index (path_elems, 0), - g_ptr_array_index (path_elems, 1)); + negated, negated_inverse); tracker_select_context_add_path_element (TRACKER_SELECT_CONTEXT (sparql->context), path_elem); _prepend_path_element (sparql, path_elem); - - for (i = 2; i < path_elems->len; i++) { - TrackerPathElement *child; - - child = g_ptr_array_index (path_elems, i); - path_elem = tracker_path_element_operator_new (TRACKER_PATH_OPERATOR_INTERSECTION, - tracker_token_get_idstring (&sparql->current_state->graph), - child, path_elem); - tracker_select_context_add_path_element (TRACKER_SELECT_CONTEXT (sparql->context), - path_elem); - _prepend_path_element (sparql, path_elem); - } - - sparql->current_state->path = path_elem; + } else if (negated) { + path_elem = negated; + } else if (negated_inverse) { + path_elem = negated_inverse; + } else { + g_assert_not_reached (); } + sparql->current_state->path = path_elem; + _expect (sparql, RULE_TYPE_LITERAL, LITERAL_CLOSE_PARENS); + g_ptr_array_unref (negated_elems); + g_ptr_array_unref (negated_inverse_elems); } else { g_assert_not_reached (); } @@ -7024,7 +7075,9 @@ translate_PathOneInPropertySet (TrackerSparql *sparql, prop); if (!path_elem) { - path_elem = tracker_path_element_property_new (TRACKER_PATH_OPERATOR_NEGATED, + path_elem = tracker_path_element_property_new (inverse ? + TRACKER_PATH_OPERATOR_NEGATED_INVERSE : + TRACKER_PATH_OPERATOR_NEGATED, tracker_token_get_idstring (&sparql->current_state->graph), prop); tracker_select_context_add_path_element (TRACKER_SELECT_CONTEXT (sparql->context), @@ -7038,17 +7091,6 @@ translate_PathOneInPropertySet (TrackerSparql *sparql, g_assert_not_reached (); } - if (inverse) { - path_elem = tracker_path_element_operator_new (TRACKER_PATH_OPERATOR_INVERSE, - tracker_token_get_idstring (&sparql->current_state->graph), - sparql->current_state->path, - NULL); - tracker_select_context_add_path_element (TRACKER_SELECT_CONTEXT (sparql->context), - path_elem); - _prepend_path_element (sparql, path_elem); - sparql->current_state->path = path_elem; - } - return TRUE; } diff --git a/src/libtracker-data/tracker-vtab-triples.c b/src/libtracker-data/tracker-vtab-triples.c index 469a6f02e..6879da38b 100644 --- a/src/libtracker-data/tracker-vtab-triples.c +++ b/src/libtracker-data/tracker-vtab-triples.c @@ -44,6 +44,7 @@ enum { COL_PREDICATE, COL_OBJECT, COL_OBJECT_TYPE, + COL_OBJECT_RAW, N_COLS }; @@ -158,7 +159,8 @@ triples_connect (sqlite3 *db, " subject INTEGER, " " predicate INTEGER, " " object INTEGER, " - " object_type INTEGER" + " object_type INTEGER, " + " object_raw INTEGER" ")"); if (rc == SQLITE_OK) { @@ -200,7 +202,8 @@ triples_best_index (sqlite3_vtab *vtab, * translation to strings can be done. */ if (info->aConstraint[i].iColumn == COL_OBJECT || - info->aConstraint[i].iColumn == COL_OBJECT_TYPE) + info->aConstraint[i].iColumn == COL_OBJECT_TYPE || + info->aConstraint[i].iColumn == COL_OBJECT_RAW) continue; if (info->aConstraint[i].iColumn == COL_ROWID) { @@ -478,13 +481,15 @@ init_stmt (TrackerTriplesCursor *cursor) "SELECT %" G_GINT64_FORMAT ", t.ID, " " (SELECT ID From Resource WHERE Uri = \"%s\"), " " %s, " - " %d " + " %d, " + " t.\"%s\" " "FROM \"%s\".\"%s\" AS t " "WHERE 1 ", graph_id, tracker_property_get_uri (property), string_expr, tracker_property_get_data_type (property), + tracker_property_get_name (property), graph, tracker_property_get_table_name (property)); diff --git a/tests/libtracker-data/basic/long-strings.out b/tests/libtracker-data/basic/long-strings.out new file mode 100644 index 000000000..28c6e7be9 --- /dev/null +++ b/tests/libtracker-data/basic/long-strings.out @@ -0,0 +1 @@ +"hello" "This is a "quoted" string" "hello" "This is a 'quoted' string" diff --git a/tests/libtracker-data/basic/long-strings.rq b/tests/libtracker-data/basic/long-strings.rq new file mode 100644 index 000000000..9b7abccf9 --- /dev/null +++ b/tests/libtracker-data/basic/long-strings.rq @@ -0,0 +1 @@ +SELECT ("""hello""" AS ?a) ("""This is a "quoted" string""" AS ?b) ('''hello''' AS ?b) ('''This is a 'quoted' string''' AS ?d) {} diff --git a/tests/libtracker-data/property-paths/negated-path-1.out b/tests/libtracker-data/property-paths/negated-path-1.out new file mode 100644 index 000000000..ef0350743 --- /dev/null +++ b/tests/libtracker-data/property-paths/negated-path-1.out @@ -0,0 +1 @@ +"Alice" diff --git a/tests/libtracker-data/property-paths/negated-path-1.rq b/tests/libtracker-data/property-paths/negated-path-1.rq new file mode 100644 index 000000000..6c03cb750 --- /dev/null +++ b/tests/libtracker-data/property-paths/negated-path-1.rq @@ -0,0 +1 @@ +select foaf:name(?a) { [ foaf:name "Bob" ] !foaf:member ?a . ?a a foaf:Agent } order by foaf:name(?a) diff --git a/tests/libtracker-data/property-paths/negated-path-10.out b/tests/libtracker-data/property-paths/negated-path-10.out new file mode 100644 index 000000000..d76316a4c --- /dev/null +++ b/tests/libtracker-data/property-paths/negated-path-10.out @@ -0,0 +1,2 @@ +"Alice" +"Foo" diff --git a/tests/libtracker-data/property-paths/negated-path-10.rq b/tests/libtracker-data/property-paths/negated-path-10.rq new file mode 100644 index 000000000..4c8db4ab4 --- /dev/null +++ b/tests/libtracker-data/property-paths/negated-path-10.rq @@ -0,0 +1 @@ +select foaf:name(?a) { [ foaf:name "Bob" ] !(foaf:knows|^foaf:member|foaf:mbox) ?a . ?a a foaf:Agent } order by foaf:name(?a) diff --git a/tests/libtracker-data/property-paths/negated-path-11.out b/tests/libtracker-data/property-paths/negated-path-11.out new file mode 100644 index 000000000..09b6f23e7 --- /dev/null +++ b/tests/libtracker-data/property-paths/negated-path-11.out @@ -0,0 +1 @@ +"Bob" diff --git a/tests/libtracker-data/property-paths/negated-path-11.rq b/tests/libtracker-data/property-paths/negated-path-11.rq new file mode 100644 index 000000000..fca43d101 --- /dev/null +++ b/tests/libtracker-data/property-paths/negated-path-11.rq @@ -0,0 +1,2 @@ +# Only foaf:name is left +select ?a { [ foaf:name "Bob" ] !(nrl:modified|nrl:added|foaf:knows|foaf:member|foaf:mbox|a) ?a } order by ?a diff --git a/tests/libtracker-data/property-paths/negated-path-2.out b/tests/libtracker-data/property-paths/negated-path-2.out new file mode 100644 index 000000000..ef0350743 --- /dev/null +++ b/tests/libtracker-data/property-paths/negated-path-2.out @@ -0,0 +1 @@ +"Alice" diff --git a/tests/libtracker-data/property-paths/negated-path-2.rq b/tests/libtracker-data/property-paths/negated-path-2.rq new file mode 100644 index 000000000..4cca76cf5 --- /dev/null +++ b/tests/libtracker-data/property-paths/negated-path-2.rq @@ -0,0 +1 @@ +select foaf:name(?a) { [ foaf:name "Bob" ] !(foaf:member) ?a . ?a a foaf:Agent } order by foaf:name(?a) diff --git a/tests/libtracker-data/property-paths/negated-path-3.out b/tests/libtracker-data/property-paths/negated-path-3.out new file mode 100644 index 000000000..ef0350743 --- /dev/null +++ b/tests/libtracker-data/property-paths/negated-path-3.out @@ -0,0 +1 @@ +"Alice" diff --git a/tests/libtracker-data/property-paths/negated-path-3.rq b/tests/libtracker-data/property-paths/negated-path-3.rq new file mode 100644 index 000000000..284b86b7b --- /dev/null +++ b/tests/libtracker-data/property-paths/negated-path-3.rq @@ -0,0 +1 @@ +select foaf:name(?a) { [ foaf:name "Bob" ] !(foaf:member|foaf:mbox) ?a . ?a a foaf:Agent } order by foaf:name(?a) diff --git a/tests/libtracker-data/property-paths/negated-path-4.out b/tests/libtracker-data/property-paths/negated-path-4.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/libtracker-data/property-paths/negated-path-4.out diff --git a/tests/libtracker-data/property-paths/negated-path-4.rq b/tests/libtracker-data/property-paths/negated-path-4.rq new file mode 100644 index 000000000..6186ff4b4 --- /dev/null +++ b/tests/libtracker-data/property-paths/negated-path-4.rq @@ -0,0 +1 @@ +select foaf:name(?a) { [ foaf:name "Bob" ] !(foaf:member|foaf:knows) ?a . ?a a foaf:Agent } order by foaf:name(?a) diff --git a/tests/libtracker-data/property-paths/negated-path-5.out b/tests/libtracker-data/property-paths/negated-path-5.out new file mode 100644 index 000000000..ef0350743 --- /dev/null +++ b/tests/libtracker-data/property-paths/negated-path-5.out @@ -0,0 +1 @@ +"Alice" diff --git a/tests/libtracker-data/property-paths/negated-path-5.rq b/tests/libtracker-data/property-paths/negated-path-5.rq new file mode 100644 index 000000000..985b2a1f4 --- /dev/null +++ b/tests/libtracker-data/property-paths/negated-path-5.rq @@ -0,0 +1 @@ +select foaf:name(?a) { [ foaf:name "Bob" ] !^foaf:member ?a . ?a a foaf:Agent } order by foaf:name(?a) diff --git a/tests/libtracker-data/property-paths/negated-path-6.out b/tests/libtracker-data/property-paths/negated-path-6.out new file mode 100644 index 000000000..ef0350743 --- /dev/null +++ b/tests/libtracker-data/property-paths/negated-path-6.out @@ -0,0 +1 @@ +"Alice" diff --git a/tests/libtracker-data/property-paths/negated-path-6.rq b/tests/libtracker-data/property-paths/negated-path-6.rq new file mode 100644 index 000000000..e6c4b611b --- /dev/null +++ b/tests/libtracker-data/property-paths/negated-path-6.rq @@ -0,0 +1,2 @@ +# The existing inverse relation is '_:alice foaf:knows _:bob' +select foaf:name(?a) { [ foaf:name "Bob" ] !(^foaf:member) ?a . ?a a foaf:Agent } order by foaf:name(?a) diff --git a/tests/libtracker-data/property-paths/negated-path-7.out b/tests/libtracker-data/property-paths/negated-path-7.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/libtracker-data/property-paths/negated-path-7.out diff --git a/tests/libtracker-data/property-paths/negated-path-7.rq b/tests/libtracker-data/property-paths/negated-path-7.rq new file mode 100644 index 000000000..19a1859f5 --- /dev/null +++ b/tests/libtracker-data/property-paths/negated-path-7.rq @@ -0,0 +1,2 @@ +# The existing inverse relation is '_:alice foaf:knows _:bob' +select foaf:name(?a) { [ foaf:name "Bob" ] !(^foaf:knows) ?a . ?a a foaf:Agent } order by foaf:name(?a) diff --git a/tests/libtracker-data/property-paths/negated-path-8.out b/tests/libtracker-data/property-paths/negated-path-8.out new file mode 100644 index 000000000..ef0350743 --- /dev/null +++ b/tests/libtracker-data/property-paths/negated-path-8.out @@ -0,0 +1 @@ +"Alice" diff --git a/tests/libtracker-data/property-paths/negated-path-8.rq b/tests/libtracker-data/property-paths/negated-path-8.rq new file mode 100644 index 000000000..0419f90af --- /dev/null +++ b/tests/libtracker-data/property-paths/negated-path-8.rq @@ -0,0 +1 @@ +select foaf:name(?a) { ?a a foaf:Agent; !(^foaf:mbox|^foaf:member) [ foaf:name "Bob"] } order by foaf:name(?a) diff --git a/tests/libtracker-data/property-paths/negated-path-9.out b/tests/libtracker-data/property-paths/negated-path-9.out new file mode 100644 index 000000000..d76316a4c --- /dev/null +++ b/tests/libtracker-data/property-paths/negated-path-9.out @@ -0,0 +1,2 @@ +"Alice" +"Foo" diff --git a/tests/libtracker-data/property-paths/negated-path-9.rq b/tests/libtracker-data/property-paths/negated-path-9.rq new file mode 100644 index 000000000..9c406c07e --- /dev/null +++ b/tests/libtracker-data/property-paths/negated-path-9.rq @@ -0,0 +1 @@ +select foaf:name(?a) { [ foaf:name "Bob" ] !(foaf:knows|^foaf:member) ?a . ?a a foaf:Agent } order by foaf:name(?a) diff --git a/tests/libtracker-data/tracker-sparql-test.c b/tests/libtracker-data/tracker-sparql-test.c index 8dddd6a74..59bc73ccc 100644 --- a/tests/libtracker-data/tracker-sparql-test.c +++ b/tests/libtracker-data/tracker-sparql-test.c @@ -88,6 +88,7 @@ const TestInfo tests[] = { { "basic/predicate-variable-4", "basic/data-1", FALSE }, { "basic/urn-in-as", "basic/data-1", FALSE }, { "basic/codepoint-escaping", "basic/data-1", FALSE }, + { "basic/long-strings", "basic/data-1", FALSE }, { "bnode/query-1", "bnode/data", FALSE }, { "bnode/query-2", "bnode/data", FALSE }, { "bnode/query-3", "bnode/data", FALSE }, @@ -312,6 +313,17 @@ const TestInfo tests[] = { { "property-paths/alternative-path-1", "property-paths/data", FALSE }, { "property-paths/alternative-path-2", "property-paths/data", FALSE }, { "property-paths/alternative-path-3", "property-paths/data", FALSE }, + { "property-paths/negated-path-1", "property-paths/data", FALSE }, + { "property-paths/negated-path-2", "property-paths/data", FALSE }, + { "property-paths/negated-path-3", "property-paths/data", FALSE }, + { "property-paths/negated-path-4", "property-paths/data", FALSE }, + { "property-paths/negated-path-5", "property-paths/data", FALSE }, + { "property-paths/negated-path-6", "property-paths/data", FALSE }, + { "property-paths/negated-path-7", "property-paths/data", FALSE }, + { "property-paths/negated-path-8", "property-paths/data", FALSE }, + { "property-paths/negated-path-9", "property-paths/data", FALSE }, + { "property-paths/negated-path-10", "property-paths/data", FALSE }, + { "property-paths/negated-path-11", "property-paths/data", FALSE }, { "property-paths/mixed-inverse-and-sequence-1", "property-paths/data", FALSE }, { "property-paths/mixed-inverse-and-sequence-2", "property-paths/data", FALSE }, { "property-paths/mixed-inverse-and-sequence-3", "property-paths/data", FALSE }, |