Commit 9b7640b8 authored by Benjamin Otte's avatar Benjamin Otte

styleproperty: Make _gtk_style_property_parse_value() return a CssValue

Also split out initial/inherit handling into a custom GtkCssValue class.
parent 718ceaec
......@@ -431,6 +431,8 @@ gtk_private_h_sources = \
gtkcssimageprivate.h \
gtkcssimageurlprivate.h \
gtkcssimagewin32private.h \
gtkcssinheritvalueprivate.h \
gtkcssinitialvalueprivate.h \
gtkcsslookupprivate.h \
gtkcssmatcherprivate.h \
gtkcssparserprivate.h \
......@@ -629,6 +631,8 @@ gtk_base_c_sources = \
gtkcssimagelinear.c \
gtkcssimageurl.c \
gtkcssimagewin32.c \
gtkcssinheritvalue.c \
gtkcssinitialvalue.c \
gtkcsslookup.c \
gtkcssmatcher.c \
gtkcssparser.c \
......
......@@ -21,9 +21,9 @@
#include "gtkcsscomputedvaluesprivate.h"
#include "gtkcssinheritvalueprivate.h"
#include "gtkcssinitialvalueprivate.h"
#include "gtkcssstylepropertyprivate.h"
#include "gtkcsstypesprivate.h"
#include "gtkprivatetypebuiltins.h"
G_DEFINE_TYPE (GtkCssComputedValues, _gtk_css_computed_values, G_TYPE_OBJECT)
......@@ -101,26 +101,19 @@ _gtk_css_computed_values_compute_value (GtkCssComputedValues *values,
*/
if (specified != NULL)
{
if (_gtk_css_value_is_special (specified))
if (_gtk_css_value_is_inherit (specified))
{
switch (_gtk_css_value_get_special_kind (specified))
{
case GTK_CSS_INHERIT:
/* 3) if the value of the winning declaration is ‘inherit’,
* the inherited value (see below) becomes the specified value.
*/
specified = NULL;
break;
case GTK_CSS_INITIAL:
/* if the value of the winning declaration is ‘initial’,
* the initial value (see below) becomes the specified value.
*/
specified = _gtk_css_style_property_get_initial_value (prop);
break;
default:
/* This is part of (2) above */
break;
}
/* 3) if the value of the winning declaration is ‘inherit’,
* the inherited value (see below) becomes the specified value.
*/
specified = NULL;
}
else if (_gtk_css_value_is_initial (specified))
{
/* if the value of the winning declaration is ‘initial’,
* the initial value (see below) becomes the specified value.
*/
specified = _gtk_css_style_property_get_initial_value (prop);
}
/* 2) If the cascading process (described below) yields a winning
......
......@@ -28,13 +28,14 @@
G_DEFINE_TYPE (GtkCssCustomProperty, _gtk_css_custom_property, GTK_TYPE_CSS_STYLE_PROPERTY)
static gboolean
static GtkCssValue *
gtk_css_custom_property_parse_value (GtkStyleProperty *property,
GValue *value,
GtkCssParser *parser,
GFile *base)
{
GtkCssCustomProperty *custom = GTK_CSS_CUSTOM_PROPERTY (property);
GValue value = G_VALUE_INIT;
GtkCssValue *result;
gboolean success;
if (custom->property_parse_func)
......@@ -42,12 +43,12 @@ gtk_css_custom_property_parse_value (GtkStyleProperty *property,
GError *error = NULL;
char *value_str;
g_value_init (value, _gtk_style_property_get_value_type (property));
g_value_init (&value, _gtk_style_property_get_value_type (property));
value_str = _gtk_css_parser_read_value (parser);
if (value_str != NULL)
{
success = (* custom->property_parse_func) (value_str, value, &error);
success = (* custom->property_parse_func) (value_str, &value, &error);
g_free (value_str);
}
else
......@@ -56,15 +57,21 @@ gtk_css_custom_property_parse_value (GtkStyleProperty *property,
else
{
GtkCssStyleProperty *style = GTK_CSS_STYLE_PROPERTY (property);
g_value_init (value, _gtk_css_style_property_get_specified_type (style));
g_value_init (&value, _gtk_css_style_property_get_specified_type (style));
success = _gtk_css_style_parse_value (value, parser, base);
success = _gtk_css_style_parse_value (&value, parser, base);
}
if (!success)
g_value_unset (value);
{
g_value_unset (&value);
return NULL;
}
return success;
result = _gtk_css_value_new_from_gvalue (&value);
g_value_unset (&value);
return result;
}
static void
......
/* GTK - The GIMP Toolkit
* Copyright (C) 2011 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gtkcssinheritvalueprivate.h"
struct _GtkCssValue {
GTK_CSS_VALUE_BASE
};
static void
gtk_css_value_inherit_free (GtkCssValue *value)
{
/* Can only happen if the unique value gets unreffed too often */
g_assert_not_reached ();
}
static void
gtk_css_value_inherit_print (const GtkCssValue *value,
GString *string)
{
g_string_append (string, "inherit");
}
static const GtkCssValueClass GTK_CSS_VALUE_INHERIT = {
gtk_css_value_inherit_free,
gtk_css_value_inherit_print
};
static GtkCssValue inherit = { &GTK_CSS_VALUE_INHERIT, 1 };
GtkCssValue *
_gtk_css_inherit_value_new (void)
{
return _gtk_css_value_ref (&inherit);
}
gboolean
_gtk_css_value_is_inherit (const GtkCssValue *value)
{
g_return_val_if_fail (value != NULL, FALSE);
return value == &inherit;
}
/*
* Copyright © 2012 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Alexander Larsson <alexl@gnome.org>
*/
#ifndef __GTK_CSS_INHERIT_VALUE_PRIVATE_H__
#define __GTK_CSS_INHERIT_VALUE_PRIVATE_H__
#include "gtkcssvalueprivate.h"
G_BEGIN_DECLS
GtkCssValue * _gtk_css_inherit_value_new (void);
gboolean _gtk_css_value_is_inherit (const GtkCssValue *value);
G_END_DECLS
#endif /* __GTK_CSS_INHERIT_VALUE_PRIVATE_H__ */
/* GTK - The GIMP Toolkit
* Copyright (C) 2011 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gtkcssinitialvalueprivate.h"
struct _GtkCssValue {
GTK_CSS_VALUE_BASE
};
static void
gtk_css_value_initial_free (GtkCssValue *value)
{
/* Can only happen if the unique value gets unreffed too often */
g_assert_not_reached ();
}
static void
gtk_css_value_initial_print (const GtkCssValue *value,
GString *string)
{
g_string_append (string, "initial");
}
static const GtkCssValueClass GTK_CSS_VALUE_INITIAL = {
gtk_css_value_initial_free,
gtk_css_value_initial_print
};
static GtkCssValue initial = { &GTK_CSS_VALUE_INITIAL, 1 };
GtkCssValue *
_gtk_css_initial_value_new (void)
{
return _gtk_css_value_ref (&initial);
}
gboolean
_gtk_css_value_is_initial (const GtkCssValue *value)
{
g_return_val_if_fail (value != NULL, FALSE);
return value == &initial;
}
/*
* Copyright © 2012 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Alexander Larsson <alexl@gnome.org>
*/
#ifndef __GTK_CSS_INITIAL_VALUE_PRIVATE_H__
#define __GTK_CSS_INITIAL_VALUE_PRIVATE_H__
#include "gtkcssvalueprivate.h"
G_BEGIN_DECLS
GtkCssValue * _gtk_css_initial_value_new (void);
gboolean _gtk_css_value_is_initial (const GtkCssValue *value);
G_END_DECLS
#endif /* __GTK_CSS_INITIAL_VALUE_PRIVATE_H__ */
......@@ -26,6 +26,7 @@
#include "gtkcssproviderprivate.h"
#include "gtkbitmaskprivate.h"
#include "gtkcssarrayvalueprivate.h"
#include "gtkcssstylefuncsprivate.h"
#include "gtkcssparserprivate.h"
#include "gtkcsssectionprivate.h"
......@@ -1249,7 +1250,7 @@ gtk_css_ruleset_add_style (GtkCssRuleset *ruleset,
static void
gtk_css_ruleset_add (GtkCssRuleset *ruleset,
GtkCssStyleProperty *property,
const GValue *value,
GtkCssValue *value,
GtkCssSection *section)
{
guint i;
......@@ -1284,7 +1285,7 @@ gtk_css_ruleset_add (GtkCssRuleset *ruleset,
ruleset->styles[i].property = property;
}
ruleset->styles[i].value = _gtk_css_value_new_from_gvalue (value);
ruleset->styles[i].value = value;
if (gtk_keep_css_sections)
ruleset->styles[i].section = gtk_css_section_ref (section);
else
......@@ -2190,66 +2191,65 @@ parse_declaration (GtkCssScanner *scanner,
if (property)
{
GValue value = { 0, };
GtkCssValue *value;
g_free (name);
gtk_css_scanner_push_section (scanner, GTK_CSS_SECTION_VALUE);
if (_gtk_style_property_parse_value (property,
&value,
scanner->parser,
gtk_css_scanner_get_base_url (scanner)))
value = _gtk_style_property_parse_value (property,
scanner->parser,
gtk_css_scanner_get_base_url (scanner));
if (value == NULL)
{
if (_gtk_css_parser_begins_with (scanner->parser, ';') ||
_gtk_css_parser_begins_with (scanner->parser, '}') ||
_gtk_css_parser_is_eof (scanner->parser))
{
if (GTK_IS_CSS_SHORTHAND_PROPERTY (property))
{
GtkCssShorthandProperty *shorthand = GTK_CSS_SHORTHAND_PROPERTY (property);
GArray *array = g_value_get_boxed (&value);
guint i;
for (i = 0; i < _gtk_css_shorthand_property_get_n_subproperties (shorthand); i++)
{
GtkCssStyleProperty *child = _gtk_css_shorthand_property_get_subproperty (shorthand, i);
const GValue *sub = &g_array_index (array, GValue, i);
gtk_css_ruleset_add (ruleset, child, sub, scanner->section);
}
}
else if (GTK_IS_CSS_STYLE_PROPERTY (property))
{
gtk_css_ruleset_add (ruleset, GTK_CSS_STYLE_PROPERTY (property), &value, scanner->section);
}
else
{
g_assert_not_reached ();
}
g_value_unset (&value);
}
else
{
gtk_css_provider_error_literal (scanner->provider,
scanner,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
"Junk at end of value");
_gtk_css_parser_resync (scanner->parser, TRUE, '}');
gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_VALUE);
gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_DECLARATION);
return;
}
_gtk_css_parser_resync (scanner->parser, TRUE, '}');
gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_VALUE);
gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_DECLARATION);
return;
}
else
if (!_gtk_css_parser_begins_with (scanner->parser, ';') &&
!_gtk_css_parser_begins_with (scanner->parser, '}') &&
!_gtk_css_parser_is_eof (scanner->parser))
{
gtk_css_provider_error_literal (scanner->provider,
scanner,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
"Junk at end of value");
_gtk_css_parser_resync (scanner->parser, TRUE, '}');
gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_VALUE);
gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_DECLARATION);
return;
}
if (GTK_IS_CSS_SHORTHAND_PROPERTY (property))
{
GtkCssShorthandProperty *shorthand = GTK_CSS_SHORTHAND_PROPERTY (property);
guint i;
for (i = 0; i < _gtk_css_shorthand_property_get_n_subproperties (shorthand); i++)
{
GtkCssStyleProperty *child = _gtk_css_shorthand_property_get_subproperty (shorthand, i);
GtkCssValue *sub = _gtk_css_array_value_get_nth (value, i);
gtk_css_ruleset_add (ruleset, child, _gtk_css_value_ref (sub), scanner->section);
}
_gtk_css_value_unref (value);
}
else if (GTK_IS_CSS_STYLE_PROPERTY (property))
{
gtk_css_ruleset_add (ruleset, GTK_CSS_STYLE_PROPERTY (property), value, scanner->section);
}
else
{
g_assert_not_reached ();
_gtk_css_value_unref (value);
}
gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_VALUE);
}
else if (name[0] == '-')
......
......@@ -21,10 +21,11 @@
#include "gtkcssshorthandpropertyprivate.h"
#include "gtkcssarrayvalueprivate.h"
#include "gtkcssinheritvalueprivate.h"
#include "gtkcssinitialvalueprivate.h"
#include "gtkcssstylefuncsprivate.h"
#include "gtkcsstypesprivate.h"
#include "gtkintl.h"
#include "gtkprivatetypebuiltins.h"
enum {
PROP_0,
......@@ -83,26 +84,17 @@ _gtk_css_shorthand_property_query (GtkStyleProperty *property,
return shorthand->query (shorthand, value, query_func, query_data);
}
static void
gtk_css_shorthand_property_unset_value (gpointer value)
{
if (G_IS_VALUE (value))
g_value_unset (value);
}
static gboolean
static GtkCssValue *
gtk_css_shorthand_property_parse_value (GtkStyleProperty *property,
GValue *value,
GtkCssParser *parser,
GFile *base)
{
GtkCssShorthandProperty *shorthand = GTK_CSS_SHORTHAND_PROPERTY (property);
GArray *array;
GtkCssValue **data;
GtkCssValue *result;
guint i;
array = g_array_new (FALSE, TRUE, sizeof (GValue));
g_array_set_clear_func (array, gtk_css_shorthand_property_unset_value);
g_array_set_size (array, shorthand->subproperties->len);
data = g_new0 (GtkCssValue *, shorthand->subproperties->len);
if (_gtk_css_parser_try (parser, "initial", TRUE))
{
......@@ -111,9 +103,7 @@ gtk_css_shorthand_property_parse_value (GtkStyleProperty *property,
*/
for (i = 0; i < shorthand->subproperties->len; i++)
{
GValue *val = &g_array_index (array, GValue, i);
g_value_init (val, GTK_TYPE_CSS_SPECIAL_VALUE);
g_value_set_enum (val, GTK_CSS_INITIAL);
data[i] = _gtk_css_initial_value_new ();
}
}
else if (_gtk_css_parser_try (parser, "inherit", TRUE))
......@@ -126,15 +116,18 @@ gtk_css_shorthand_property_parse_value (GtkStyleProperty *property,
*/
for (i = 0; i < shorthand->subproperties->len; i++)
{
GValue *val = &g_array_index (array, GValue, i);
g_value_init (val, GTK_TYPE_CSS_SPECIAL_VALUE);
g_value_set_enum (val, GTK_CSS_INHERIT);
data[i] = _gtk_css_inherit_value_new ();
}
}
else if (!shorthand->parse (shorthand, (GValue *) array->data, parser, base))
else if (!shorthand->parse (shorthand, data, parser, base))
{
g_array_free (array, TRUE);
return FALSE;
for (i = 0; i < shorthand->subproperties->len; i++)
{
if (data[i] != NULL)
_gtk_css_value_unref (data[i]);
}
g_free (data);
return NULL;
}
/* All values that aren't set by the parse func are set to their
......@@ -142,16 +135,14 @@ gtk_css_shorthand_property_parse_value (GtkStyleProperty *property,
* XXX: Is the default always initial or can it be inherit? */
for (i = 0; i < shorthand->subproperties->len; i++)
{
GValue *val = &g_array_index (array, GValue, i);
if (G_IS_VALUE (val))
continue;
g_value_init (val, GTK_TYPE_CSS_SPECIAL_VALUE);
g_value_set_enum (val, GTK_CSS_INITIAL);
if (data[i] == NULL)
data[i] = _gtk_css_initial_value_new ();
}
g_value_init (value, G_TYPE_ARRAY);
g_value_take_boxed (value, array);
return TRUE;
result = _gtk_css_array_value_new (data, shorthand->subproperties->len);
g_free (data);
return result;
}
static void
......
......@@ -49,10 +49,10 @@ value_is_done_parsing (GtkCssParser *parser)
}
static gboolean
parse_four_numbers (GtkCssShorthandProperty *shorthand,
GValue *values,
GtkCssParser *parser,
GtkCssNumberParseFlags flags)
parse_four_numbers (GtkCssShorthandProperty *shorthand,
GtkCssValue **values,
GtkCssParser *parser,
GtkCssNumberParseFlags flags)
{
GtkCssNumber numbers[4];
guint i;
......@@ -81,18 +81,17 @@ parse_four_numbers (GtkCssShorthandProperty *shorthand,
for (i = 0; i < 4; i++)
{
g_value_init (&values[i], GTK_TYPE_CSS_NUMBER);
g_value_set_boxed (&values[i], &numbers[i]);
values[i] = _gtk_css_value_new_from_number (&numbers[i]);
}
return TRUE;
}
static gboolean
parse_margin (GtkCssShorthandProperty *shorthand,
GValue *values,
GtkCssParser *parser,
GFile *base)
parse_margin (GtkCssShorthandProperty *shorthand,
GtkCssValue **values,
GtkCssParser *parser,
GFile *base)
{
return parse_four_numbers (shorthand,
values,
......@@ -102,10 +101,10 @@ parse_margin (GtkCssShorthandProperty *shorthand,
}
static gboolean
parse_padding (GtkCssShorthandProperty *shorthand,
GValue *values,
GtkCssParser *parser,
GFile *base)
parse_padding (GtkCssShorthandProperty *shorthand,
GtkCssValue **values,
GtkCssParser *parser,
GFile *base)
{
return parse_four_numbers (shorthand,
values,
......@@ -116,10 +115,10 @@ parse_padding (GtkCssShorthandProperty *shorthand,
}
static gboolean
parse_border_width (GtkCssShorthandProperty *shorthand,
GValue *values,
GtkCssParser *parser,
GFile *base)
parse_border_width (GtkCssShorthandProperty *shorthand,
GtkCssValue **values,
GtkCssParser *parser,
GFile *base)
{
return parse_four_numbers (shorthand,
values,
......@@ -130,10 +129,10 @@ parse_border_width (GtkCssShorthandProperty *shorthand,
}
static gboolean
parse_border_radius (GtkCssShorthandProperty *shorthand,
GValue *values,
GtkCssParser *parser,
GFile *base)
parse_border_radius (GtkCssShorthandProperty *shorthand,
GtkCssValue **values,
GtkCssParser *parser,
GFile *base)
{
GtkCssBorderCornerRadius borders[4];
guint i;
......@@ -195,18 +194,17 @@ parse_border_radius (GtkCssShorthandProperty *shorthand,
for (i = 0; i < G_N_ELEMENTS (borders); i++)
{
g_value_init (&values[i], GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
g_value_set_boxed (&values[i], &borders[i]);
values[i] = _gtk_css_value_new_from_border_corner_radius (&borders[i]);
}
return TRUE;
}
static gboolean
parse_border_color (GtkCssShorthandProperty *shorthand,
GValue *values,
GtkCssParser *parser,
GFile *base)
parse_border_color (GtkCssShorthandProperty *shorthand,
GtkCssValue **values,
GtkCssParser *parser,
GFile *base)
{
GtkSymbolicColor *symbolic;
guint i;
......@@ -224,8 +222,7 @@ parse_border_color (GtkCssShorthandProperty *shorthand,
return FALSE;
}
g_value_init (&values[i], GTK_TYPE_SYMBOLIC_COLOR);
g_value_set_boxed (&values[i], symbolic);
values[i] = _gtk_css_value_new_take_symbolic_color (symbolic);
if (value_is_done_parsing (parser))
break;
......@@ -233,18 +230,17 @@ parse_border_color (GtkCssShorthandProperty *shorthand,
for (i++; i < 4; i++)
{
g_value_init (&values[i], G_VALUE_TYPE (&values[(i - 1) >> 1]));
g_value_copy (&values[(i - 1) >> 1], &values[i]);
values[i] = _gtk_css_value_ref (values[(i - 1) >> 1]);
}
return TRUE;
}
static gboolean
parse_border_style (GtkCssShorthandProperty *shorthand,
GValue *values,
GtkCssParser *parser,
GFile *base)
parse_border_style (GtkCssShorthandProperty *shorthand,
GtkCssValue **values,
GtkCssParser *parser,
GFile *base)
{
GtkBorderStyle styles[4];
guint i;
......@@ -266,19 +262,19 @@ parse_border_style (GtkCssShorthandProperty *shorthand,
for (i = 0; i < G_N_ELEMENTS (styles); i++)
{
g_value_init (&values[i], GTK_TYPE_BORDER_STYLE);
g_value_set_enum (&values[i], styles[i]);
values[i] = _gtk_css_value_new_from_enum (GTK_TYPE_BORDER_STYLE, styles[i]);
}
return TRUE;
}
static gboolean
parse_border_image (GtkCssShorthandProperty *shorthand,
GValue *values,
GtkCssParser *parser,
GFile *base)
parse_border_image (GtkCssShorthandProperty *shorthand,
GtkCssValue **values,
GtkCssParser *parser,
GFile *base)
{
GValue value = G_VALUE_INIT;
GtkCssImage *image;
if (_gtk_css_parser_try (parser, "none", TRUE))
......@@ -289,44 +285,49 @@ parse_border_image (GtkCssShorthandProperty *shorthand,
if (!image)
return FALSE;
}
g_value_init (&values[0], GTK_TYPE_CSS_IMAGE);
g_value_set_object (&values[0], image);
values[0] = _gtk_css_value_new_take_image (image);
if (value_is_done_parsing (parser))
return TRUE;
g_value_init (&values[1], GTK_TYPE_BORDER);
if (!_gtk_css_style_parse_value (&values[1], parser, base))
g_value_init (&value, GTK_TYPE_BORDER);
if (!_gtk_css_style_parse_value (&value, parser, base))
return FALSE;
values[1] = _gtk_css_value_new_from_gvalue (&value);
g_value_unset (&value);
if (_gtk_css_parser_try (parser, "/", TRUE))