Пример #1
0
MpdData * magnatune_db_get_genre_list()
{
    MpdData *list = NULL;
    int i,r;

    char *query = sqlite3_mprintf("SELECT genre from 'genres' group by genre");
    sqlite3_stmt *stmt = NULL;
    const char *tail;
    GTimer *timer = g_timer_new();
    r = sqlite3_prepare_v2(magnatune_sqlhandle, query, -1,  &stmt,  &tail);
    if(r ==SQLITE_OK) {
        while((r = sqlite3_step(stmt)) == SQLITE_ROW)
        {
            list = mpd_new_data_struct_append(list);
            list->type = MPD_DATA_TYPE_TAG;
            list->tag_type = MPD_TAG_ITEM_GENRE;
            list->tag = g_strdup(sqlite3_column_text(stmt,0));
        }
    }

    sqlite3_finalize(stmt);
    sqlite3_free(query);
    g_debug("%f s elapsed getting genres\n", g_timer_elapsed(timer,NULL));
    g_timer_reset(timer);
    list = misc_mpddata_remove_duplicate_songs(list); 
    g_debug("%f s elapsed unique genres list\n", g_timer_elapsed(timer,NULL));
    g_timer_destroy(timer);
    return list;
}
Пример #2
0
MpdData * magnatune_db_search_title(const gchar *title)
{

    MpdData *list = NULL;
    char *query = NULL;
    sqlite3_stmt *stmt = NULL;
    const char *tail;
    int r = 0;
        query =  sqlite3_mprintf("SELECT songs.albumname,duration,number,desc,mp3 from 'songs' "
        "WHERE songs.desc LIKE '%%%%%q%%%%'",title);
    r=sqlite3_prepare_v2(magnatune_sqlhandle, query, -1,  &stmt,  &tail);
    if(r ==SQLITE_OK) {
        while((r = sqlite3_step(stmt)) == SQLITE_ROW)
        {
            gchar *temp = gmpc_easy_download_uri_escape(sqlite3_column_text(stmt,4));
            list = mpd_new_data_struct_append(list);
            list->type = MPD_DATA_TYPE_SONG;
            list->song = mpd_newSong();
            list->song->album = g_strdup(sqlite3_column_text(stmt,0));
            list->song->artist = __magnatune_get_artist_name(list->song->album);
            list->song->genre = __magnatune_get_genre_name(list->song->album);
            list->song->title= g_strdup(sqlite3_column_text(stmt,3));
            list->song->track = g_strdup(sqlite3_column_text(stmt,2));
            list->song->time = sqlite3_column_int(stmt,1);
            list->song->file = magnatune_get_url(temp);
            g_free(temp);
        }
    }
    sqlite3_finalize(stmt);
    sqlite3_free(query);
    return list;
}
Пример #3
0
MpdData * mpd_database_get_artists(MpdObj *mi)
{
	char *string = NULL;
	MpdData *data = NULL;
	if(!mpd_check_connected(mi))
	{
		debug_printf(DEBUG_WARNING,"not connected\n");
		return NULL;
	}
	if(mpd_lock_conn(mi))
	{
		debug_printf(DEBUG_ERROR,"lock failed\n");
		return NULL;
	}

	mpd_sendListCommand(mi->connection,MPD_TABLE_ARTIST,NULL);
	while (( string = mpd_getNextArtist(mi->connection)) != NULL)
	{
		data = mpd_new_data_struct_append(data);
		data->type = MPD_DATA_TYPE_TAG;
		data->tag_type = MPD_TAG_ITEM_ARTIST;
		data->tag = string;
	}
	mpd_finishCommand(mi->connection);

	/* unlock */
	mpd_unlock_conn(mi);
	if(data == NULL)
	{
		return NULL;
	}
	data = mpd_misc_sort_tag_list(data);
	return mpd_data_get_first(data);
}
Пример #4
0
MpdData * mpd_server_get_output_devices(MpdObj *mi)
{
    mpd_OutputEntity *output = NULL;
    MpdData *data = NULL;
    if(!mpd_check_connected(mi))
    {
        debug_printf(DEBUG_WARNING,"not connected\n");
        return NULL;
    }
    /* TODO: Check version */
    if(mpd_lock_conn(mi))
    {
        debug_printf(DEBUG_ERROR,"lock failed\n");
        return NULL;
    }

    mpd_sendOutputsCommand(mi->connection);
    while (( output = mpd_getNextOutput(mi->connection)) != NULL)
    {	
        data = mpd_new_data_struct_append(data);
        data->type = MPD_DATA_TYPE_OUTPUT_DEV; 
        data->output_dev = output;
    }
    mpd_finishCommand(mi->connection);

    /* unlock */
    mpd_unlock_conn(mi);
    if(data == NULL) 
    {
        return NULL;
    }
    return mpd_data_get_first(data);
}
Пример #5
0
MpdData *mpd_database_get_playlist_content(MpdObj *mi,char *playlist)
{
	MpdData *data = NULL;
	mpd_InfoEntity *ent = NULL;
	if(!mpd_check_connected(mi))
	{
		debug_printf(DEBUG_WARNING,"not connected\n");
		return NULL;
	}
	if(!mpd_server_check_version(mi, 0,12,0))
	{
		debug_printf(DEBUG_WARNING, "only works with mpd higher then 0.12.0");
		return NULL;
	}
	if(mpd_server_check_command_allowed(mi, "listplaylistinfo") != MPD_SERVER_COMMAND_ALLOWED)
	{
		debug_printf(DEBUG_WARNING, "Listing playlist content not supported or allowed");
		return NULL;
	}
	if(mpd_lock_conn(mi))
	{
		debug_printf(DEBUG_WARNING,"lock failed\n");
		return NULL;
	}
	mpd_sendListPlaylistInfoCommand(mi->connection, playlist);
	while (( ent = mpd_getNextInfoEntity(mi->connection)) != NULL)
	{
		data = mpd_new_data_struct_append( data );
		if(ent->type == MPD_INFO_ENTITY_TYPE_DIRECTORY)
		{
			data->type = MPD_DATA_TYPE_DIRECTORY;
			data->directory = ent->info.directory->path;
			ent->info.directory->path = NULL;
		}
		else if (ent->type == MPD_INFO_ENTITY_TYPE_SONG)
		{
			data->type = MPD_DATA_TYPE_SONG;
			data->song = ent->info.song;
			ent->info.song = NULL;
		}
		else if (ent->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE)
		{
			data->type = MPD_DATA_TYPE_PLAYLIST;
			data->playlist = ent->info.playlistFile->path;
			ent->info.playlistFile->path = NULL;
		}

		mpd_freeInfoEntity(ent);
	}
	mpd_finishCommand(mi->connection);

	/* unlock */
	mpd_unlock_conn(mi);
	if(data == NULL)
	{
		return NULL;
	}
	return mpd_data_get_first(data);
}
Пример #6
0
MpdData * mpd_database_get_directory(MpdObj *mi,char *path)
{
	MpdData *data = NULL;
	mpd_InfoEntity *ent = NULL;
	if(!mpd_check_connected(mi))
	{
		debug_printf(DEBUG_WARNING,"not connected\n");
		return NULL;
	}
	if(path == NULL)
	{
		path = "/";
	}
	if(mpd_lock_conn(mi))
	{
		debug_printf(DEBUG_WARNING,"lock failed\n");
		return NULL;
	}

	mpd_sendLsInfoCommand(mi->connection,path);
	while (( ent = mpd_getNextInfoEntity(mi->connection)) != NULL)
	{
		data = mpd_new_data_struct_append(data);
		if(ent->type == MPD_INFO_ENTITY_TYPE_DIRECTORY)
		{
			data->type = MPD_DATA_TYPE_DIRECTORY;
			data->directory = ent->info.directory->path;
			ent->info.directory->path = NULL;
		}
		else if (ent->type == MPD_INFO_ENTITY_TYPE_SONG)
		{
			data->type = MPD_DATA_TYPE_SONG;
			data->song = ent->info.song;
			ent->info.song = NULL;
		}
		else if (ent->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE)
		{
			data->type = MPD_DATA_TYPE_PLAYLIST;
			data->playlist = ent->info.playlistFile->path;
			ent->info.playlistFile->path = NULL;
		}

		mpd_freeInfoEntity(ent);
	}
	mpd_finishCommand(mi->connection);

	/* unlock */
	mpd_unlock_conn(mi);
	if(data == NULL)
	{
		return NULL;
	}
	return mpd_data_get_first(data);
}
Пример #7
0
MpdData * mpd_playlist_get_changes_posid(MpdObj *mi,int old_playlist_id)
{
	MpdData *data = NULL;
	mpd_InfoEntity *ent = NULL;
	debug_printf(DEBUG_INFO, "Fetching using new plchangesposid command");
	if(!mpd_check_connected(mi))
	{
		debug_printf(DEBUG_WARNING,"not connected\n");
		return NULL;
	}
	if(mpd_lock_conn(mi))
	{
		debug_printf(DEBUG_WARNING,"lock failed\n");
		return NULL;
	}

	if(old_playlist_id == -1)
	{
		debug_printf(DEBUG_INFO,"get fresh playlist\n");
		mpd_sendPlChangesPosIdCommand (mi->connection, 0);
/*		mpd_sendPlaylistIdCommand(mi->connection, -1); */
	}
	else
	{
		mpd_sendPlChangesPosIdCommand (mi->connection, old_playlist_id);
	}

	while (( ent = mpd_getNextInfoEntity(mi->connection)) != NULL)
	{
		if(ent->type == MPD_INFO_ENTITY_TYPE_SONG)
		{
			data = mpd_new_data_struct_append(data);
			data->type = MPD_DATA_TYPE_SONG;
			data->song = ent->info.song;
			ent->info.song = NULL;
		}
		mpd_freeInfoEntity(ent);
	}
	mpd_finishCommand(mi->connection);

	/* unlock */
	if(mpd_unlock_conn(mi))
	{
		debug_printf(DEBUG_WARNING,"mpd_playlist_get_changes: unlock failed.\n");
		mpd_data_free(data);
		return NULL;
	}
	if(data == NULL)
	{
		return NULL;
	}
	return mpd_data_get_first(data);
}
Пример #8
0
MpdData * mpd_playlist_search_commit(MpdObj *mi)
{
	mpd_InfoEntity *ent = NULL;
	MpdData *data = NULL;
	if(!mpd_check_connected(mi))
	{
		debug_printf(DEBUG_WARNING,"not connected\n");
		return NULL;
	}
	if(mi->search_type < MPD_SEARCH_TYPE_PLAYLIST_FIND )
	{
		debug_printf(DEBUG_ERROR, "no or wrong search in progress to commit");
		return NULL;
	}
	if(mpd_lock_conn(mi))
	{
		debug_printf(DEBUG_ERROR,"lock failed\n");
		return NULL;
	}
	mpd_commitSearch(mi->connection);
	while (( ent = mpd_getNextInfoEntity(mi->connection)) != NULL)
	{
		if(ent->type == MPD_INFO_ENTITY_TYPE_SONG)
		{
			data = mpd_new_data_struct_append(data);
			data->type = MPD_DATA_TYPE_SONG;
			data->song = ent->info.song;
			ent->info.song = NULL;
		}
		mpd_freeInfoEntity(ent);
	}
	mpd_finishCommand(mi->connection);
	/*
	 * reset search type
	 */
	mi->search_type = MPD_SEARCH_TYPE_NONE;
	mi->search_field = MPD_TAG_ITEM_ARTIST;
	/* unlock */
	if(mpd_unlock_conn(mi))
	{
		debug_printf(DEBUG_ERROR, "Failed to unlock connection");
		if(data)mpd_data_free(data);
		return NULL;
	}
	if(data == NULL)
	{
		return NULL;
	}
	return mpd_data_get_first(data);
}
Пример #9
0
MpdData * mpd_playlist_get_song_from_pos_range(MpdObj *mi, int start, int stop)
{
    MpdData *data = NULL;
    int i;
	mpd_InfoEntity *ent = NULL;
	if(!mpd_check_connected(mi))
	{
		debug_printf(DEBUG_ERROR, "Not Connected\n");
		return NULL;
	}
	if(mpd_status_check(mi) != MPD_OK)
	{
		debug_printf(DEBUG_ERROR,"Failed grabbing status\n");
		return NULL;
	}

	if(mpd_lock_conn(mi))
	{
		return NULL;
	}
    /* Don't check outside playlist length */
    if(!(stop < mi->status->playlistLength)) {
        stop = mi->status->playlistLength -1;
    }
    mpd_sendCommandListBegin(mi->connection);
    for(i=start; i <= stop; i++){
        mpd_sendPlaylistInfoCommand(mi->connection, i);
    }
	mpd_sendCommandListEnd(mi->connection);
	while (( ent = mpd_getNextInfoEntity(mi->connection)) != NULL)
	{
		if(ent->type == MPD_INFO_ENTITY_TYPE_SONG)
		{
			data = mpd_new_data_struct_append(data);
			data->type = MPD_DATA_TYPE_SONG;
			data->song = ent->info.song;
			ent->info.song = NULL;
		}
		mpd_freeInfoEntity(ent);
	}
	mpd_finishCommand(mi->connection);

	if(mpd_unlock_conn(mi))
	{
		/*TODO free entity. for now this can never happen */
		return NULL;
	}
    return data;
}
Пример #10
0
static MpdData *__magnatune_get_data_album(const char *album, gboolean exact)
{
    MpdData *list = NULL;
    char *query = NULL;
    sqlite3_stmt *stmt = NULL;
    const char *tail;
    int r = 0;
    GTimer *timer = g_timer_new();
    if(exact)
    {
        query =  sqlite3_mprintf("SELECT songs.albumname,duration,number,desc,mp3 from 'songs' " 
        "WHERE songs.albumname=%Q",album);
    }else{
        query =  sqlite3_mprintf("SELECT songs.albumname,duration,number,desc,mp3 from 'songs' "
        "WHERE songs.albumname LIKE '%%%%%q%%%%'",album);
    }
    r=sqlite3_prepare_v2(magnatune_sqlhandle, query, -1,  &stmt,  &tail);
    if(r ==SQLITE_OK) {
        while((r = sqlite3_step(stmt)) == SQLITE_ROW)
        {
            gchar *temp = gmpc_easy_download_uri_escape(sqlite3_column_text(stmt,4));
            list = mpd_new_data_struct_append(list);
            list->type = MPD_DATA_TYPE_SONG;
            list->song = mpd_newSong();
            list->song->album = g_strdup(sqlite3_column_text(stmt,0));
            list->song->artist = __magnatune_get_artist_name(list->song->album);
            list->song->genre = __magnatune_get_genre_name(list->song->album);
            list->song->title= g_strdup(sqlite3_column_text(stmt,3));
            list->song->track = g_strdup(sqlite3_column_text(stmt,2));
            list->song->time = sqlite3_column_int(stmt,1);
            list->song->file = magnatune_get_url(temp);
            g_free(temp);
        }
    }
    else{
        g_warning("Sqlite error: %s\n", tail);
    }
    sqlite3_finalize(stmt);
    sqlite3_free(query);
    g_debug("%f s elapsed getting album songs\n", g_timer_elapsed(timer,NULL));
    g_timer_destroy(timer);
    return list;
}
Пример #11
0
MpdData * mpd_database_get_directory_recursive(MpdObj *mi, const char *path)
{
	MpdData *data = NULL;
	mpd_InfoEntity *ent = NULL;
	if(!mpd_check_connected(mi))
	{
		debug_printf(DEBUG_WARNING,"not connected\n");
		return NULL;
	}
	if(path == '\0' || path[0] == '\0')
	{
		debug_printf(DEBUG_ERROR, "argumant invalid\n");
		return NULL;
	}
	if(mpd_lock_conn(mi))
	{
		debug_printf(DEBUG_ERROR,"lock failed\n");
		return NULL;
	}
	mpd_sendListallInfoCommand(mi->connection,path); 
	while (( ent = mpd_getNextInfoEntity(mi->connection)) != NULL)
	{

		if (ent->type == MPD_INFO_ENTITY_TYPE_SONG)
		{
			data = mpd_new_data_struct_append(data);
			data->type = MPD_DATA_TYPE_SONG;
			data->song = ent->info.song;
			ent->info.song = NULL;
		}
		mpd_freeInfoEntity(ent);
	}
	mpd_finishCommand(mi->connection);

	/* unlock */
	mpd_unlock_conn(mi);
	if(data == NULL)
	{
		return NULL;
	}
	return mpd_data_get_first(data);
}
Пример #12
0
MpdData * magnatune_db_get_artist_list(char *wanted_genre)
{
    MpdData *list = NULL;
    int r;
    /** check if there is data */
    char *query = sqlite3_mprintf("SELECT albumname from 'genres' WHERE genre=%Q", wanted_genre);
    sqlite3_stmt *stmt = NULL;
    const char *tail;
    GTimer *timer = g_timer_new();
    r = sqlite3_prepare_v2(magnatune_sqlhandle, query, -1,  &stmt,  &tail);
    if(r ==SQLITE_OK) {
        while((r = sqlite3_step(stmt)) == SQLITE_ROW)
        {
            sqlite3_stmt *stmt2 = NULL;
            const char *tail2;
            char *query2 = sqlite3_mprintf("SELECT artist from 'albums' WHERE albumname=%Q", sqlite3_column_text(stmt,0));
            int r2 = sqlite3_prepare_v2(magnatune_sqlhandle, query2, -1,  &stmt2,  &tail2);
            if(r2 ==SQLITE_OK) {
                while((r2 = sqlite3_step(stmt2)) == SQLITE_ROW)
                {
                    list = mpd_new_data_struct_append(list);
                    list->type = MPD_DATA_TYPE_TAG;
                    list->tag_type = MPD_TAG_ITEM_ARTIST;
                    list->tag = g_strdup(sqlite3_column_text(stmt2,0));
                }
            }
            sqlite3_finalize(stmt2);
            sqlite3_free(query2);
        }
    }
    sqlite3_finalize(stmt);
    sqlite3_free(query);
    g_debug("%f s elapsed getting genres\n", g_timer_elapsed(timer,NULL));
    g_timer_reset(timer);
    list = misc_mpddata_remove_duplicate_songs(list);

    g_debug("%f s elapsed unique artist list\n", g_timer_elapsed(timer,NULL));
    g_timer_destroy(timer);
    return list;
}
Пример #13
0
/* should be called mpd_database_find */
MpdData * mpd_database_find(MpdObj *mi, int table, char *string, int exact)
{
	MpdData *data = NULL;
/*	MpdData *artist = NULL;
	MpdData *album = NULL;
*/	mpd_InfoEntity *ent = NULL;
	if(!mpd_check_connected(mi))
	{
		debug_printf(DEBUG_WARNING,"not connected\n");
		return NULL;
	}
	if(mpd_lock_conn(mi))
	{
		debug_printf(DEBUG_WARNING,"lock failed\n");
		return NULL;
	}
	if(exact)
	{
		mpd_sendFindCommand(mi->connection,table,string);
	}
	else
	{
		mpd_sendSearchCommand(mi->connection, table,string);
	}
	while (( ent = mpd_getNextInfoEntity(mi->connection)) != NULL)
	{
		data = mpd_new_data_struct_append(data);
		/* mpd_sendSearch|Find only returns songs */
		/*
		if(ent->type == MPD_INFO_ENTITY_TYPE_DIRECTORY)
		{
			data->type = MPD_DATA_TYPE_DIRECTORY;
			data->directory = ent->info.directory->path;
			ent->info.directory->path = NULL;
		}
		else*/ if (ent->type == MPD_INFO_ENTITY_TYPE_SONG)
		{
			data->type = MPD_DATA_TYPE_SONG;
			data->song = ent->info.song;
			ent->info.song = NULL;
			/* This is something the client can and should do */
/*			if(data->song->artist != NULL)
			{
				int found = FALSE;
				if(artist != NULL)
				{
					MpdData *fartist = mpd_data_get_first(artist);
					do{
						if( (fartist->type == MPD_DATA_TYPE_TAG) && (fartist->tag_type == MPD_TAG_ITEM_ARTIST))
						{
							if(fartist->tag == NULL)
							{
								printf("crap this should'nt be \n");
							}
							if(!strcmp(fartist->tag, data->song->artist))
							{
								found = TRUE;
							}
						}
						fartist = mpd_data_get_next_real(fartist, FALSE);
					}while(fartist && !found);
				}
				if(!found)
				{
					artist= mpd_new_data_struct_append(artist);
					artist->type = MPD_DATA_TYPE_TAG;
					artist->tag_type = MPD_TAG_ITEM_ARTIST;
					artist->tag = strdup(data->song->artist);
				}
			}
			if(data->song->album != NULL)
			{
				int found = FALSE;
				if(album != NULL)
				{
					MpdData *falbum = mpd_data_get_first(album);
					do{
						if( (falbum->type == MPD_DATA_TYPE_TAG) && (falbum->tag_type == MPD_TAG_ITEM_ALBUM))
						{
							if(falbum->tag == NULL)
							{
								printf("crap this should'nt be \n");
							}
							if(!strcmp(falbum->tag, data->song->album))
							{
								found = TRUE;
							}
						}
						falbum = mpd_data_get_next_real(falbum, FALSE);
					}while(falbum && !found);
				}
				if(!found)
				{
					album = mpd_new_data_struct_append(album);
					album->type = MPD_DATA_TYPE_TAG;
					album->tag_type = MPD_TAG_ITEM_ALBUM;
					album->tag = strdup(data->song->album);
				}
			}
*/
		}
		/*
		else if (ent->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE)
		{
			data->type = MPD_DATA_TYPE_PLAYLIST;
			data->playlist = ent->info.playlistFile->path;
			ent->info.playlistFile->path = NULL;
		}
		*/

		mpd_freeInfoEntity(ent);
	}
	mpd_finishCommand(mi->connection);

	/* unlock */
	mpd_unlock_conn(mi);
	if(data == NULL)
	{
		return NULL;
	}
	data = mpd_data_get_first(data);
	/* prepend the album then artists*/
/*	if(album != NULL)
	{
		if(data){
			data  = mpd_data_concatenate( album, data);
		}else{
			data = album;
		}
	}
	if(artist != NULL)
	{
		if(data) {
			album = mpd_data_concatenate( artist, data );
		}else{
			data = artist;
		}
	}                                                     	
*/
	return mpd_data_get_first(data);
}
Пример #14
0
MpdData *mpd_database_token_find(MpdObj *mi , char *string)
{
	MpdData *data = NULL;
	mpd_InfoEntity *ent = NULL;
	regex_t ** strdata = NULL;
	if(!mpd_check_connected(mi))
	{
		debug_printf(DEBUG_WARNING,"not connected\n");
		return NULL;
	}
	if(mpd_lock_conn(mi))
	{
		debug_printf(DEBUG_ERROR,"lock failed\n");
		return NULL;
	}

	if(string == NULL || !strlen(string) )
	{
		debug_printf(DEBUG_INFO, "no string found");
		mpd_unlock_conn(mi);
		return NULL;
	}
	else{
		strdata = mpd_misc_tokenize(string);
	}
	if(strdata == NULL)
	{
		mpd_unlock_conn(mi);
		debug_printf(DEBUG_INFO, "no split string found");
		return NULL;
	}

	mpd_sendListallInfoCommand(mi->connection, "/");
	while (( ent = mpd_getNextInfoEntity(mi->connection)) != NULL)
	{
		if (ent->type == MPD_INFO_ENTITY_TYPE_SONG)
		{
			int i = 0;
			int match = 0;
			int loop = 1;
			for(i=0; strdata[i] != NULL && loop; i++)
			{
				match = 0;
				if(ent->info.song->file && !regexec(strdata[i],ent->info.song->file, 0, NULL, 0))
				{
					match = 1;
				}
				else if(ent->info.song->artist && !regexec(strdata[i],ent->info.song->artist, 0, NULL, 0))
				{
					match = 1;
				}
				else if(ent->info.song->title && !regexec(strdata[i],ent->info.song->title, 0, NULL, 0)) 
				{
					match = 1;
				}
				else if(ent->info.song->album && !regexec(strdata[i],ent->info.song->album, 0, NULL, 0))
				{
					match = 1;
				}
				if(!match)
				{
					loop = 0;
				}
			}

			if(match)
			{
				data = mpd_new_data_struct_append(data);
				data->type = MPD_DATA_TYPE_SONG;
				/*
				data->song = mpd_songDup(ent->info.song);
				*/
				data->song = ent->info.song;
				ent->info.song = NULL;
			}
		}
		mpd_freeInfoEntity(ent);
	}
	mpd_finishCommand(mi->connection);
	mpd_misc_tokens_free(strdata);




	mpd_unlock_conn(mi);
	if(data == NULL)
	{
		return NULL;
	}
	return mpd_data_get_first(data);
}