Example #1
0
int
xmmsv_coll_compare (xmmsv_t *a, xmmsv_t *b)
{
	xmmsv_coll_type_t type;
	xmmsv_t *_a, *_b;

	type = xmmsv_coll_get_type (a);
	if (xmmsv_coll_get_type (b) != type) {
		return 0;
	}

	_a = xmmsv_coll_idlist_get (a);
	_b = xmmsv_coll_idlist_get (b);
	if (!xmmsv_compare (_a, _b)) {
		return 0;
	}

	_a = xmmsv_coll_attributes_get (a);
	_b = xmmsv_coll_attributes_get (b);
	if (!xmmsv_compare (_a, _b)) {
		return 0;
	}

	_a = xmmsv_coll_operands_get (a);
	_b = xmmsv_coll_operands_get (b);
	if (!xmmsv_compare (_a, _b)) {
		return 0;
	}

	return 1;
}
static void
query_append_operand (coll_query_t *query, xmms_coll_dag_t *dag, xmmsv_coll_t *coll)
{
	xmmsv_coll_t *op = NULL;
	gchar *target_name;
	gchar *target_ns;
	guint  target_nsid;

	if (!xmmsv_list_get_coll (xmmsv_coll_operands_get (coll), 0, &op)) {

		/* Ref'd coll not saved as operand, look for it */
		if (xmmsv_coll_attribute_get (coll, "reference", &target_name) &&
		    xmmsv_coll_attribute_get (coll, "namespace", &target_ns)) {

			target_nsid = xmms_collection_get_namespace_id (target_ns);
			op = xmms_collection_get_pointer (dag, target_name, target_nsid);
		}
	}

	/* Append reference operator */
	if (op != NULL) {
		xmms_collection_append_to_query (dag, op, query);

	/* Cannot find reference, append dummy TRUE */
	} else {
		query_append_string (query, "1");
	}
}
Example #3
0
	CollPtr PartyShuffle::getOperand() const
	{
		xmmsv_t *operands, *operand;

		// Find the operand
		operands = xmmsv_coll_operands_get( coll_ );
		if( !xmmsv_list_get( operands, 0, &operand ) ) {
			throw missing_operand_error( "No operand in this operator!" );
		}

		return CollResult::createColl( operand );
	}
Example #4
0
void
configure_playlist (xmmsc_result_t *res, cli_infos_t *infos, gchar *playlist,
                    gint history, gint upcoming, xmmsv_coll_type_t type,
                    gchar *input)
{
	xmmsc_result_t *saveres;
	xmmsv_coll_t *coll;
	xmmsv_coll_t *newcoll;
	xmmsv_t *val;

	gboolean copied = FALSE;

	val = xmmsc_result_get_value (res);

	if (xmmsv_get_coll (val, &coll)) {
		if (type >= 0 && xmmsv_coll_get_type (coll) != type) {
			newcoll = coll_copy_retype (coll, type);
			coll = newcoll;
			copied = TRUE;
		}
		if (history >= 0) {
			coll_int_attribute_set (coll, "history", history);
		}
		if (upcoming >= 0) {
			coll_int_attribute_set (coll, "upcoming", upcoming);
		}
		if (input) {
			/* Replace previous operand. */
			newcoll = coll_make_reference (input, XMMS_COLLECTION_NS_COLLECTIONS);
			xmmsv_list_clear (xmmsv_coll_operands_get (coll));
			xmmsv_coll_add_operand (coll, newcoll);
			xmmsv_coll_unref (newcoll);
		}

		saveres = xmmsc_coll_save (infos->sync, coll, playlist,
		                           XMMS_COLLECTION_NS_PLAYLISTS);
		xmmsc_result_wait (saveres);
		done (saveres, infos);
	} else {
		g_printf (_("Cannot find the playlist to configure!\n"));
		cli_infos_loop_resume (infos);
	}

	if (copied) {
		xmmsv_coll_unref (coll);
	}

	xmmsc_result_unref (res);
}
static void
query_append_intersect_operand (coll_query_t *query, xmms_coll_dag_t *dag,
                                xmmsv_coll_t *coll)
{
	xmmsv_coll_t *op;
	xmmsv_t *tmp;

	if (xmmsv_list_get (xmmsv_coll_operands_get (coll), 0, &tmp)) {
		xmmsv_get_coll (tmp, &op);

		if (!operator_is_allmedia (op)) {
			query_append_string (query, " AND ");
			xmms_collection_append_to_query (dag, op, query);
		}
	}
}
Example #6
0
static VALUE
c_operands_each (VALUE self)
{
	RbCollection *coll = NULL;
	xmmsv_t *operands_list;
	VALUE tmp;

	tmp = rb_iv_get (self, "collection");
	Data_Get_Struct (tmp, RbCollection, coll);

	operands_list = xmmsv_coll_operands_get (coll->real);

	xmmsv_list_foreach (operands_list, operands_each, NULL);

	return self;
}
Example #7
0
xmmsv_coll_t *
xmmsv_coll_copy (xmmsv_coll_t *orig_coll)
{
	xmmsv_coll_t *new_coll, *coll_elem;
	xmmsv_list_iter_t *it;
	xmmsv_dict_iter_t *itd;
	xmmsv_t *v, *list, *dict;
	const char *key;
	int32_t i;
	const char *s;

	new_coll = xmmsv_coll_new (xmmsv_coll_get_type (orig_coll));

	list = xmmsv_coll_idlist_get (orig_coll);
	x_return_val_if_fail (xmmsv_get_list_iter (list, &it), NULL);
	while (xmmsv_list_iter_valid (it)) {
		xmmsv_list_iter_entry (it, &v);
		xmmsv_get_int (v, &i);
		xmmsv_coll_idlist_append (new_coll, i);
		xmmsv_list_iter_next (it);
	}
	xmmsv_list_iter_explicit_destroy (it);

	list = xmmsv_coll_operands_get (orig_coll);
	x_return_val_if_fail (xmmsv_get_list_iter (list, &it), NULL);
	while (xmmsv_list_iter_valid (it)) {
		xmmsv_list_iter_entry (it, &v);
		xmmsv_get_coll (v, &coll_elem);
		xmmsv_coll_add_operand (new_coll, xmmsv_coll_copy (coll_elem));
		xmmsv_list_iter_next (it);
	}
	xmmsv_list_iter_explicit_destroy (it);

	dict = xmmsv_coll_attributes_get (orig_coll);
	x_return_val_if_fail (xmmsv_get_dict_iter (dict, &itd), NULL);
	while (xmmsv_dict_iter_valid (itd)) {
		xmmsv_dict_iter_pair (itd, &key, &v);
		xmmsv_get_string (v, &s);
		xmmsv_coll_attribute_set (new_coll, key, s);
		xmmsv_dict_iter_next (itd);
	}
	xmmsv_dict_iter_explicit_destroy (itd);
	return new_coll;
}
Example #8
0
static void
pl_print_config (xmmsv_coll_t *coll, const char *name)
{
	xmmsv_coll_t *op;
	xmmsv_coll_type_t type;
	gchar *upcoming = NULL;
	gchar *history = NULL;
	gchar *input = NULL;
	gchar *input_ns = NULL;
	xmmsv_t *v;

	type = xmmsv_coll_get_type (coll);

	xmmsv_coll_attribute_get (coll, "upcoming", &upcoming);
	xmmsv_coll_attribute_get (coll, "history", &history);

	g_printf (_("name: %s\n"), name);

	switch (type) {
	case XMMS_COLLECTION_TYPE_IDLIST:
		g_printf (_("type: list\n"));
		break;
	case XMMS_COLLECTION_TYPE_QUEUE:
		g_printf (_("type: queue\n"));
		g_printf (_("history: %s\n"), history);
		break;
	case XMMS_COLLECTION_TYPE_PARTYSHUFFLE:
		if (xmmsv_list_get (xmmsv_coll_operands_get (coll), 0, &v) &&
		    xmmsv_get_coll (v, &op)) {
			xmmsv_coll_attribute_get (op, "reference", &input);
			xmmsv_coll_attribute_get (op, "namespace", &input_ns);
		}

		g_printf (_("type: pshuffle\n"));
		g_printf (_("history: %s\n"), history);
		g_printf (_("upcoming: %s\n"), upcoming);
		g_printf (_("input: %s/%s\n"), input_ns, input);
		break;
	default:
		g_printf (_("type: unknown!\n"));
		break;
	}
}
Example #9
0
static void
xmms_playlist_update_partyshuffle (xmms_playlist_t *playlist,
                                   const gchar *plname, xmmsv_coll_t *coll)
{
	gint history, upcoming, currpos, size;
	xmmsv_coll_t *src;
	xmmsv_t *tmp;

	XMMS_DBG ("PLAYLIST: Update partyshuffle.");

	if (!xmms_collection_get_int_attr (coll, "history", &history)) {
		history = 0;
	}

	if (!xmms_collection_get_int_attr (coll, "upcoming", &upcoming)) {
		upcoming = XMMS_DEFAULT_PARTYSHUFFLE_UPCOMING;
	}

	currpos = xmms_playlist_coll_get_currpos (coll);
	while (currpos > history) {
		/* Removing entries is fast enough to be processed at once. */
		xmms_playlist_remove_unlocked (playlist, plname, coll, 0, NULL);
		currpos = xmms_playlist_coll_get_currpos (coll);
	}

	g_return_if_fail(xmmsv_list_get (xmmsv_coll_operands_get (coll), 0, &tmp));
	g_return_if_fail(xmmsv_get_coll (tmp, &src));

	/* Since getting random media can be slow on huge medialibs, we refill only
	 * one entry at a time. This let other threads a chance to get the lock on
	 * the playlist object as soon as possible. */
	size = xmms_playlist_coll_get_size (coll);
	if (size < currpos + 1 + upcoming) {
		xmms_medialib_entry_t randentry;
		randentry = xmms_collection_get_random_media (playlist->colldag, src);
		if (randentry > 0) {
			xmms_playlist_add_entry_unlocked (playlist, plname, coll, randentry, NULL);
		}
	}
}
Example #10
0
static void
_xmms_coll_dump (xmmsv_t *coll, int indent)
{
	xmmsv_t *attributes, *operands, *idlist;
	const char *type_str;

	printf ("/* collection */ {\n");

	type_str = collection_type_string (xmmsv_coll_get_type (coll));
	_xmmsv_coll_dump_indent (indent + 1);
	printf ("'type': '%s'", type_str);

	attributes = xmmsv_coll_attributes_get (coll);
	if (xmmsv_dict_get_size (attributes)) {
		printf (",\n");
		_xmmsv_coll_dump_indent (indent + 1);
		printf ("'attributes': ");
		xmmsv_dump_indented (attributes, indent + 1);
	}
	operands = xmmsv_coll_operands_get (coll);
	if (xmmsv_list_get_size (operands)) {
		printf (",\n");
		_xmmsv_coll_dump_indent (indent + 1);
		printf ("'operands': ");
		xmmsv_dump_indented (operands, indent + 1);
	}
	idlist = xmmsv_coll_idlist_get (coll);
	if (xmmsv_list_get_size (idlist)) {
		printf (",\n");
		_xmmsv_coll_dump_indent (indent + 1);
		printf ("'idlist': ");
		xmmsv_dump_indented (idlist, indent + 1);
	}

	printf ("\n");
	_xmmsv_coll_dump_indent (indent);
	printf ("}");
}
Example #11
0
static xmmsv_t *
duplicate_coll_value (xmmsv_t *val)
{
	xmmsv_t *dup_val, *attributes, *operands, *idlist, *copy;

	dup_val = xmmsv_new_coll (xmmsv_coll_get_type (val));

	attributes = xmmsv_coll_attributes_get (val);
	copy = xmmsv_copy (attributes);
	xmmsv_coll_attributes_set (dup_val, copy);
	xmmsv_unref (copy);

	operands = xmmsv_coll_operands_get (val);
	copy = xmmsv_copy (operands);
	xmmsv_coll_operands_set (dup_val, copy);
	xmmsv_unref (copy);

	idlist = xmmsv_coll_idlist_get (val);
	copy = xmmsv_copy (idlist);
	xmmsv_coll_idlist_set (dup_val, copy);
	xmmsv_unref (copy);

	return dup_val;
}
Example #12
0
/* Recursively append conditions corresponding to the given collection to the query. */
static void
xmms_collection_append_to_query (xmms_coll_dag_t *dag, xmmsv_coll_t *coll,
                                 coll_query_t *query)
{
	xmmsv_coll_t *op;
	xmms_medialib_entry_t entry;
	gchar *attr1, *attr2, *attr3;
	gboolean case_sens;
	xmmsv_list_iter_t *iter;
	xmmsv_t *tmp;
	gboolean first;

	xmmsv_coll_type_t type = xmmsv_coll_get_type (coll);
	switch (type) {
	case XMMS_COLLECTION_TYPE_REFERENCE:
		if (!operator_is_allmedia (coll)) {
			query_append_operand (query, dag, coll);
		} else {
			/* FIXME: Hackish solution to append a ref to All Media */
			query_append_string (query, "1");
		}
		break;

	case XMMS_COLLECTION_TYPE_UNION:
	case XMMS_COLLECTION_TYPE_INTERSECTION:
		first = TRUE;
		query_append_string (query, "(");

		xmmsv_get_list_iter (xmmsv_coll_operands_get (coll), &iter);

		for (xmmsv_list_iter_first (iter);
		     xmmsv_list_iter_valid (iter);
		     xmmsv_list_iter_next (iter)) {
			if (first) {
				first = FALSE;
			} else {
				if (type == XMMS_COLLECTION_TYPE_UNION)
					query_append_string (query, " OR ");
				else
					query_append_string (query, " AND ");
			}
			xmmsv_list_iter_entry (iter, &tmp);
			xmmsv_get_coll (tmp, &op);
			xmms_collection_append_to_query (dag, op, query);
		}
		xmmsv_list_iter_explicit_destroy (iter);

		query_append_string (query, ")");
		break;

	case XMMS_COLLECTION_TYPE_COMPLEMENT:
		query_append_string (query, "NOT ");
		query_append_operand (query, dag, coll);
		break;

	case XMMS_COLLECTION_TYPE_HAS:
	case XMMS_COLLECTION_TYPE_EQUALS:
	case XMMS_COLLECTION_TYPE_MATCH:
	case XMMS_COLLECTION_TYPE_SMALLER:
	case XMMS_COLLECTION_TYPE_GREATER:
		xmmsv_coll_attribute_get (coll, "field", &attr1);
		xmmsv_coll_attribute_get (coll, "value", &attr2);
		xmmsv_coll_attribute_get (coll, "case-sensitive", &attr3);
		case_sens = (attr3 != NULL && strcmp (attr3, "true") == 0);

		query_append_string (query, "(");
		query_append_filter (query, type, attr1, attr2, case_sens);

		query_append_intersect_operand (query, dag, coll);
		query_append_string (query, ")");
		break;

	case XMMS_COLLECTION_TYPE_IDLIST:
	case XMMS_COLLECTION_TYPE_QUEUE:
	case XMMS_COLLECTION_TYPE_PARTYSHUFFLE:
		first = TRUE;
		query_append_string (query, "m0.id IN (");

		xmmsv_get_list_iter (xmmsv_coll_idlist_get (coll), &iter);
		for (xmmsv_list_iter_first (iter);
		     xmmsv_list_iter_valid (iter);
		     xmmsv_list_iter_next (iter)) {

			if (first) {
				first = FALSE;
			} else {
				query_append_string (query, ",");
			}

			xmmsv_list_iter_entry_int (iter, &entry);
			query_append_int (query, entry);
		}
		xmmsv_list_iter_explicit_destroy (iter);

		query_append_string (query, ")");
		break;

	/* invalid type */
	default:
		XMMS_DBG ("Cannot append invalid collection operator!");
		g_assert_not_reached ();
		break;
	}

}
Example #13
0
/* Dump the structure of the collection as a string
   (from src/clients/cli/cmd_coll.c) */
static void
coll_dump (xmmsv_coll_t *coll, guint level)
{
	gint i;
	gchar *indent;

	gchar *attr1;
	gchar *attr2;
	xmmsv_coll_t *operand;
	GString *idlist_str;

	indent = g_malloc ((level * 2) + 1);
	for (i = 0; i < level * 2; ++i) {
		indent[i] = ' ';
	}
	indent[i] = '\0';

	/* type */
	switch (xmmsc_coll_get_type (coll)) {
	case XMMS_COLLECTION_TYPE_REFERENCE:
		xmmsc_coll_attribute_get (coll, "reference", &attr1);
		print_info ("%sReference: '%s'", indent, attr1);
		break;

	case XMMS_COLLECTION_TYPE_UNION:
		print_info ("%sUnion:", indent);
		coll_dump_list (xmmsv_coll_operands_get (coll), level + 1);
		break;

	case XMMS_COLLECTION_TYPE_INTERSECTION:
		print_info ("%sIntersection:", indent);
		coll_dump_list (xmmsv_coll_operands_get (coll), level + 1);
		break;

	case XMMS_COLLECTION_TYPE_COMPLEMENT:
		print_info ("%sComplement:", indent);
		coll_dump_list (xmmsv_coll_operands_get (coll), level + 1);
		break;

	case XMMS_COLLECTION_TYPE_EQUALS:
		xmmsc_coll_attribute_get (coll, "field",  &attr1);
		xmmsc_coll_attribute_get (coll, "value", &attr2);
		print_info ("%sEquals ('%s', '%s') for:", indent, attr1, attr2);
		coll_dump_list (xmmsv_coll_operands_get (coll), level + 1);
		break;

	case XMMS_COLLECTION_TYPE_HAS:
		xmmsc_coll_attribute_get (coll, "field",  &attr1);
		print_info ("%sHas ('%s') for:", indent, attr1);
		coll_dump_list (xmmsv_coll_operands_get (coll), level + 1);
		break;

	case XMMS_COLLECTION_TYPE_MATCH:
		xmmsc_coll_attribute_get (coll, "field",  &attr1);
		xmmsc_coll_attribute_get (coll, "value", &attr2);
		print_info ("%sMatch ('%s', '%s') for:", indent, attr1, attr2);
		coll_dump_list (xmmsv_coll_operands_get (coll), level + 1);
		break;

	case XMMS_COLLECTION_TYPE_SMALLER:
		xmmsc_coll_attribute_get (coll, "field",  &attr1);
		xmmsc_coll_attribute_get (coll, "value", &attr2);
		print_info ("%sSmaller ('%s', '%s') for:", indent, attr1, attr2);
		coll_dump_list (xmmsv_coll_operands_get (coll), level + 1);
		break;

	case XMMS_COLLECTION_TYPE_GREATER:
		xmmsc_coll_attribute_get (coll, "field",  &attr1);
		xmmsc_coll_attribute_get (coll, "value", &attr2);
		print_info ("%sGreater ('%s', '%s') for:", indent, attr1, attr2);
		coll_dump_list (xmmsv_coll_operands_get (coll), level + 1);
		break;

	case XMMS_COLLECTION_TYPE_IDLIST:
		idlist_str = coll_idlist_to_string (coll);
		print_info ("%sIdlist: %s", indent, idlist_str->str);
		g_string_free (idlist_str, TRUE);
		break;

	case XMMS_COLLECTION_TYPE_QUEUE:
		idlist_str = coll_idlist_to_string (coll);
		print_info ("%sQueue: %s", indent, idlist_str->str);
		g_string_free (idlist_str, TRUE);
		break;

	case XMMS_COLLECTION_TYPE_PARTYSHUFFLE:
		idlist_str = coll_idlist_to_string (coll);
		print_info ("%sParty Shuffle: %s from :", indent, idlist_str->str);
		g_string_free (idlist_str, TRUE);
		coll_dump_list (xmmsv_coll_operands_get (coll), level + 1);
		break;

	default:
		print_info ("%sUnknown Operator!", indent);
		break;
	}
}
Example #14
0
	void OperandIterator::initIterator()
	{
		xmmsv_t *operands( xmmsv_coll_operands_get( coll_.coll_ ) );
		xmmsv_get_list_iter( operands, &oper_it_ );
	}
Example #15
0
static bool
_internal_put_on_bb_collection (xmmsv_t *bb, xmmsv_coll_t *coll)
{
	xmmsv_list_iter_t *it;
	xmmsv_t *v, *attrs;
	int n;
	uint32_t ret;
	int32_t entry;
	xmmsv_coll_t *op;

	if (!bb || !coll) {
		return false;
	}

	/* push type */
	if (!xmmsv_bitbuffer_put_bits (bb, 32, xmmsv_coll_get_type (coll)))
		return false;

	/* attribute counter and values */
	attrs = xmmsv_coll_attributes_get (coll);
	n = 0;

	xmmsv_dict_foreach (attrs, _internal_put_on_bb_count_coll_attr, &n);
	if (!xmmsv_bitbuffer_put_bits (bb, 32, n))
		return false;

	/* needs error checking! */
	xmmsv_dict_foreach (attrs, _internal_put_on_bb_append_coll_attr, bb);

	attrs = NULL; /* no unref needed. */

	/* idlist counter and content */
	xmmsv_bitbuffer_put_bits (bb, 32, xmmsv_coll_idlist_get_size (coll));

	xmmsv_get_list_iter (xmmsv_coll_idlist_get (coll), &it);
	for (xmmsv_list_iter_first (it);
	     xmmsv_list_iter_valid (it);
	     xmmsv_list_iter_next (it)) {

		if (!xmmsv_list_iter_entry_int (it, &entry)) {
			x_api_error ("Non integer in idlist", 0);
		}
		xmmsv_bitbuffer_put_bits (bb, 32, entry);
	}
	xmmsv_list_iter_explicit_destroy (it);

	/* operands counter and objects */
	n = 0;
	if (xmmsv_coll_get_type (coll) != XMMS_COLLECTION_TYPE_REFERENCE) {
		n = xmmsv_list_get_size (xmmsv_coll_operands_get (coll));
	}

	ret = xmmsv_bitbuffer_pos (bb);
	xmmsv_bitbuffer_put_bits (bb, 32, n);

	if (n > 0) {
		xmmsv_get_list_iter (xmmsv_coll_operands_get (coll), &it);

		while (xmmsv_list_iter_entry (it, &v)) {
			if (!xmmsv_get_coll (v, &op)) {
				x_api_error ("Non collection operand", 0);
			}

			_internal_put_on_bb_int32 (bb, XMMSV_TYPE_COLL);

			ret = _internal_put_on_bb_collection (bb, op);
			xmmsv_list_iter_next (it);
		}
	}

	return ret;
}
Example #16
0
/** Write the given operator to the database under the given id.
 *
 * @param session  The medialib session connected to the DB.
 * @param collid  The id under which to save the collection.
 * @param coll  The structure of the collection to save.
 * @return  The next free collection id.
 */
static guint
xmms_collection_dbwrite_operator (xmms_medialib_session_t *session,
                                  guint collid, xmmsv_coll_t *coll)
{
	gchar query[128];
	guint *idlist;
	gint i;
	xmmsv_coll_t *op;
	xmmsv_t *attrs;
	gint newid, nextid;
	coll_dbwrite_t dbwrite_infos = { session, collid, 0 };

	/* Write operator */
	g_snprintf (query, sizeof (query),
	            "INSERT INTO CollectionOperators VALUES(%d, %d)",
	            collid, xmmsv_coll_get_type (coll));

	xmms_medialib_select (session, query, NULL);

	/* Write attributes */
	attrs = xmmsv_coll_attributes_get (coll);
	xmmsv_dict_foreach (attrs, dbwrite_coll_attributes, &dbwrite_infos);
	attrs = NULL; /* no unref needed. */

	/* Write idlist */
	idlist = xmmsv_coll_get_idlist (coll);
	for (i = 0; idlist[i] != 0; i++) {
		g_snprintf (query, sizeof (query),
		            "INSERT INTO CollectionIdlists VALUES(%d, %d, %d)",
		            collid, i, idlist[i]);

		xmms_medialib_select (session, query, NULL);
	}

	/* Save operands and connections (don't recurse in ref operand) */
	newid = collid + 1;
	if (xmmsv_coll_get_type (coll) != XMMS_COLLECTION_TYPE_REFERENCE) {
		xmmsv_t *tmp;
		xmmsv_list_iter_t *iter;

		xmmsv_get_list_iter (xmmsv_coll_operands_get (coll), &iter);

		for (xmmsv_list_iter_first (iter);
		     xmmsv_list_iter_valid (iter);
		     xmmsv_list_iter_next (iter)) {

			xmmsv_list_iter_entry (iter, &tmp);
			xmmsv_get_coll (tmp, &op);

			nextid = xmms_collection_dbwrite_operator (session, newid, op);
			g_snprintf (query, sizeof (query),
			            "INSERT INTO CollectionConnections VALUES(%d, %d)",
			            newid, collid);
			xmms_medialib_select (session, query, NULL);
			newid = nextid;
		}
		xmmsv_list_iter_explicit_destroy (iter);
	}

	/* return next available id */
	return newid;
}