diff --git a/mednafen/tremor/bitwise.c b/mednafen/tremor/bitwise.c index 50c85df..08434ad 100644 --- a/mednafen/tremor/bitwise.c +++ b/mednafen/tremor/bitwise.c @@ -520,5 +520,3 @@ unsigned char *oggpack_get_buffer(oggpack_buffer *b){ unsigned char *oggpackB_get_buffer(oggpack_buffer *b){ return oggpack_get_buffer(b); } - -#undef BUFFER_INCREMENT diff --git a/mednafen/tremor/block.c b/mednafen/tremor/block.c index 9ba643f..198b553 100644 --- a/mednafen/tremor/block.c +++ b/mednafen/tremor/block.c @@ -15,7 +15,6 @@ ********************************************************************/ -#include #include #include #include "ogg.h" @@ -242,9 +241,10 @@ void vorbis_dsp_clear(vorbis_dsp_state *v){ if(v->pcm) { - for(i=0;ichannels;i++) - if(v->pcm[i]) - free(v->pcm[i]); + if(vi) + for(i=0;ichannels;i++) + if(v->pcm[i]) + free(v->pcm[i]); free(v->pcm); if(v->pcmret) free(v->pcmret); diff --git a/mednafen/tremor/floor0.c b/mednafen/tremor/floor0.c index 9721f6f..24f0b39 100644 --- a/mednafen/tremor/floor0.c +++ b/mednafen/tremor/floor0.c @@ -437,5 +437,3 @@ vorbis_func_floor floor0_exportbundle={ &floor0_unpack,&floor0_look,&floor0_free_info, &floor0_free_look,&floor0_inverse1,&floor0_inverse2 }; - - diff --git a/mednafen/tremor/info.c b/mednafen/tremor/info.c index 4dc39f9..7883f33 100644 --- a/mednafen/tremor/info.c +++ b/mednafen/tremor/info.c @@ -41,54 +41,6 @@ void vorbis_comment_init(vorbis_comment *vc){ memset(vc,0,sizeof(*vc)); } -/* This is more or less the same as strncasecmp - but that doesn't exist - * everywhere, and this is a fairly trivial function, so we include it */ -static int tagcompare(const char *s1, const char *s2, int n){ - int c=0; - while(c < n){ - if(toupper(s1[c]) != toupper(s2[c])) - return !0; - c++; - } - return 0; -} - -char *vorbis_comment_query(vorbis_comment *vc, char *tag, int count){ - long i; - int found = 0; - int taglen = strlen(tag)+1; /* +1 for the = we append */ - char *fulltag = (char *)alloca(taglen+ 1); - - strcpy(fulltag, tag); - strcat(fulltag, "="); - - for(i=0;icomments;i++){ - if(!tagcompare(vc->user_comments[i], fulltag, taglen)){ - if(count == found) - /* We return a pointer to the data, not a copy */ - return vc->user_comments[i] + taglen; - else - found++; - } - } - return NULL; /* didn't find anything */ -} - -int vorbis_comment_query_count(vorbis_comment *vc, char *tag){ - int i,count=0; - int taglen = strlen(tag)+1; /* +1 for the = we append */ - char *fulltag = (char *)alloca(taglen+1); - strcpy(fulltag,tag); - strcat(fulltag, "="); - - for(i=0;icomments;i++){ - if(!tagcompare(vc->user_comments[i], fulltag, taglen)) - count++; - } - - return count; -} - void vorbis_comment_clear(vorbis_comment *vc){ if(vc){ long i; diff --git a/mednafen/tremor/ivorbiscodec.h b/mednafen/tremor/ivorbiscodec.h index 2c2e72a..b446696 100644 --- a/mednafen/tremor/ivorbiscodec.h +++ b/mednafen/tremor/ivorbiscodec.h @@ -153,11 +153,6 @@ extern void vorbis_info_init(vorbis_info *vi); extern void vorbis_info_clear(vorbis_info *vi); extern int vorbis_info_blocksize(vorbis_info *vi,int zo); extern void vorbis_comment_init(vorbis_comment *vc); -extern void vorbis_comment_add(vorbis_comment *vc, char *comment); -extern void vorbis_comment_add_tag(vorbis_comment *vc, - char *tag, char *contents); -extern char *vorbis_comment_query(vorbis_comment *vc, char *tag, int count); -extern int vorbis_comment_query_count(vorbis_comment *vc, char *tag); extern void vorbis_comment_clear(vorbis_comment *vc); extern int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb); diff --git a/mednafen/tremor/ivorbisfile.h b/mednafen/tremor/ivorbisfile.h index b7c6957..48a70ca 100644 --- a/mednafen/tremor/ivorbisfile.h +++ b/mednafen/tremor/ivorbisfile.h @@ -23,7 +23,6 @@ extern "C" { #endif /* __cplusplus */ -#include #include "ivorbiscodec.h" #define CHUNKSIZE 1024 @@ -89,26 +88,14 @@ extern int ov_clear(OggVorbis_File *vf); extern int ov_open_callbacks(void *datasource, OggVorbis_File *vf, const char *initial, long ibytes, ov_callbacks callbacks); -extern long ov_bitrate(OggVorbis_File *vf,int i); -extern long ov_bitrate_instant(OggVorbis_File *vf); -extern long ov_serialnumber(OggVorbis_File *vf,int i); - -extern int64_t ov_raw_total(OggVorbis_File *vf,int i); extern int64_t ov_pcm_total(OggVorbis_File *vf,int i); extern int64_t ov_time_total(OggVorbis_File *vf,int i); extern int ov_raw_seek(OggVorbis_File *vf,int64_t pos); extern int ov_pcm_seek(OggVorbis_File *vf,int64_t pos); extern int ov_pcm_seek_page(OggVorbis_File *vf,int64_t pos); -extern int ov_time_seek(OggVorbis_File *vf,int64_t pos); -extern int ov_time_seek_page(OggVorbis_File *vf,int64_t pos); - -extern int64_t ov_raw_tell(OggVorbis_File *vf); -extern int64_t ov_pcm_tell(OggVorbis_File *vf); -extern int64_t ov_time_tell(OggVorbis_File *vf); extern vorbis_info *ov_info(OggVorbis_File *vf,int link); -extern vorbis_comment *ov_comment(OggVorbis_File *vf,int link); extern long ov_read(OggVorbis_File *vf,char *buffer,int length, int *bitstream); diff --git a/mednafen/tremor/mapping0.c b/mednafen/tremor/mapping0.c index 4da4865..1b7cb0c 100644 --- a/mednafen/tremor/mapping0.c +++ b/mednafen/tremor/mapping0.c @@ -16,7 +16,6 @@ ********************************************************************/ #include -#include #include #include #include "ogg.h" diff --git a/mednafen/tremor/misc.h b/mednafen/tremor/misc.h index 5b67031..fbc1570 100644 --- a/mednafen/tremor/misc.h +++ b/mednafen/tremor/misc.h @@ -180,7 +180,8 @@ static INLINE int32_t CLIP_TO_15(int32_t x) { static INLINE int32_t VFLOAT_MULT(int32_t a,int32_t ap, int32_t b,int32_t bp, int32_t *p){ - if(a && b){ + if(a && b) + { #ifndef _LOW_ACCURACY_ *p=ap+bp+32; return MULT32(a,b); @@ -188,8 +189,8 @@ static INLINE int32_t VFLOAT_MULT(int32_t a,int32_t ap, *p=ap+bp+31; return (a>>15)*(b>>16); #endif - }else - return 0; + } + return 0; } int _ilog(unsigned int); diff --git a/mednafen/tremor/sharedbook.c b/mednafen/tremor/sharedbook.c index d18792c..454638e 100644 --- a/mednafen/tremor/sharedbook.c +++ b/mednafen/tremor/sharedbook.c @@ -165,7 +165,8 @@ long _book_maptype1_quantvals(const static_codebook *b){ int bits=_ilog(b->entries); int vals=b->entries>>((bits-1)*(b->dim-1)/b->dim); - while(1){ + for(;;) + { long acc=1; long acc1=1; int i; @@ -173,14 +174,14 @@ long _book_maptype1_quantvals(const static_codebook *b){ acc*=vals; acc1*=vals+1; } - if(acc<=b->entries && acc1>b->entries){ + if(acc<=b->entries && acc1>b->entries) return(vals); - }else{ - if(acc>b->entries){ + else + { + if(acc>b->entries) vals--; - }else{ + else vals++; - } } } } diff --git a/mednafen/tremor/synthesis.c b/mednafen/tremor/synthesis.c index bb50b4f..975926a 100644 --- a/mednafen/tremor/synthesis.c +++ b/mednafen/tremor/synthesis.c @@ -16,7 +16,6 @@ ********************************************************************/ -#include #include "ogg.h" #include "ivorbiscodec.h" #include "codec_internal.h" diff --git a/mednafen/tremor/vorbisfile.c b/mednafen/tremor/vorbisfile.c index 0388160..43d3af8 100644 --- a/mednafen/tremor/vorbisfile.c +++ b/mednafen/tremor/vorbisfile.c @@ -27,6 +27,10 @@ #include "os.h" #include "misc.h" +#define VORBIS_SEEK_SET 0 +#define VORBIS_SEEK_CUR 1 +#define VORBIS_SEEK_END 2 + /* A 'chained bitstream' is a Vorbis bitstream that contains more than one logical bitstream arranged end to end (the only form of Ogg multiplexing allowed in a Vorbis bitstream; grouping [parallel @@ -85,7 +89,7 @@ static long _get_data(OggVorbis_File *vf){ static int _seek_helper(OggVorbis_File *vf,int64_t offset){ if(vf->datasource){ if(!(vf->callbacks.seek_func)|| - (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET) == -1) + (vf->callbacks.seek_func)(vf->datasource, offset, VORBIS_SEEK_SET) == -1) return OV_EREAD; vf->offset=offset; ogg_sync_reset(&vf->oy); @@ -112,7 +116,8 @@ static int _seek_helper(OggVorbis_File *vf,int64_t offset){ static int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og, int64_t boundary){ if(boundary>0)boundary+=vf->offset; - while(1){ + for(;;) + { long more; if(boundary>0 && vf->offset>=boundary)return(OV_FALSE); @@ -362,8 +367,8 @@ static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc, goto bail_header; } - while(1){ - + for(;;) + { i=0; while(i<2){ /* get a page loop */ @@ -430,7 +435,8 @@ static int64_t _initial_pcmoffset(OggVorbis_File *vf, vorbis_info *vi){ int result; int serialno = vf->os.serialno; - while(1){ + for(;;) + { ogg_packet op; if(_get_next_page(vf,&og,-1)<0) break; /* should not be possible unless the file is truncated/mangled */ @@ -634,7 +640,7 @@ static int _open_seekable2(OggVorbis_File *vf){ /* we can seek, so set out learning all about this file */ if(vf->callbacks.seek_func && vf->callbacks.tell_func){ - (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END); + (vf->callbacks.seek_func)(vf->datasource,0, VORBIS_SEEK_END); vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource); }else{ vf->offset=vf->end=-1; @@ -688,8 +694,8 @@ static int _fetch_and_process_packet(OggVorbis_File *vf, /* handle one packet. Try to fetch it from current stream state */ /* extract packets from page */ - while(1){ - + for(;;) + { if(vf->ready_state==STREAMSET){ int ret=_make_decode_ready(vf); if(ret<0)return ret; @@ -698,9 +704,10 @@ static int _fetch_and_process_packet(OggVorbis_File *vf, /* process a packet if we can. If the machine isn't loaded, neither is a page */ if(vf->ready_state==INITSET){ - while(1) { - ogg_packet op; - ogg_packet *op_ptr=(op_in?op_in:&op); + for(;;) + { + ogg_packet op; + ogg_packet *op_ptr=(op_in?op_in:&op); int result=ogg_stream_packetout(&vf->os,op_ptr); int64_t granulepos; @@ -772,7 +779,7 @@ static int _fetch_and_process_packet(OggVorbis_File *vf, if(vf->ready_state>=OPENED){ int64_t ret; - while(1){ + for(;;){ /* the loop is not strictly necessary, but there's no sense in doing the extra checks of the larger loop for the common case in a multiplexed bistream where the page is simply @@ -875,7 +882,7 @@ static int _fetch_and_process_packet(OggVorbis_File *vf, static int _ov_open1(void *f,OggVorbis_File *vf,const char *initial, long ibytes, ov_callbacks callbacks){ - int offsettest=((f && callbacks.seek_func)?callbacks.seek_func(f,0,SEEK_CUR):-1); + int offsettest=((f && callbacks.seek_func)?callbacks.seek_func(f,0, VORBIS_SEEK_CUR):-1); uint32_t *serialno_list=NULL; int serialno_list_size=0; int ret; @@ -933,23 +940,6 @@ static int _ov_open1(void *f,OggVorbis_File *vf,const char *initial, return(ret); } -static int _ov_open2(OggVorbis_File *vf){ - if(vf->ready_state != PARTOPEN) return OV_EINVAL; - vf->ready_state=OPENED; - if(vf->seekable){ - int ret=_open_seekable2(vf); - if(ret){ - vf->datasource=NULL; - ov_clear(vf); - } - return(ret); - }else - vf->ready_state=STREAMSET; - - return 0; -} - - /* clear out the OggVorbis_File struct */ int ov_clear(OggVorbis_File *vf){ if(vf){ @@ -994,97 +984,23 @@ int ov_open_callbacks(void *f,OggVorbis_File *vf, const char *initial,long ibytes,ov_callbacks callbacks){ int ret=_ov_open1(f,vf,initial,ibytes,callbacks); if(ret)return ret; - return _ov_open2(vf); -} - -/* returns the bitrate for a given logical bitstream or the entire - physical bitstream. If the file is open for random access, it will - find the *actual* average bitrate. If the file is streaming, it - returns the nominal bitrate (if set) else the average of the - upper/lower bounds (if set) else -1 (unset). - - If you want the actual bitrate field settings, get them from the - vorbis_info structs */ - -long ov_bitrate(OggVorbis_File *vf,int i){ - if(vf->ready_state=vf->links)return(OV_EINVAL); - if(!vf->seekable && i!=0)return(ov_bitrate(vf,0)); - if(i<0){ - int64_t bits=0; - int i; - for(i=0;ilinks;i++) - bits+=(vf->offsets[i+1]-vf->dataoffsets[i])*8; - /* This once read: return(rint(bits/ov_time_total(vf,-1))); - * gcc 3.x on x86 miscompiled this at optimisation level 2 and above, - * so this is slightly transformed to make it work. - */ - return(bits*1000/ov_time_total(vf,-1)); - }else{ - if(vf->seekable){ - /* return the actual bitrate */ - return((vf->offsets[i+1]-vf->dataoffsets[i])*8000/ov_time_total(vf,i)); - }else{ - /* return nominal if set */ - if(vf->vi[i].bitrate_nominal>0){ - return vf->vi[i].bitrate_nominal; - }else{ - if(vf->vi[i].bitrate_upper>0){ - if(vf->vi[i].bitrate_lower>0){ - return (vf->vi[i].bitrate_upper+vf->vi[i].bitrate_lower)/2; - }else{ - return vf->vi[i].bitrate_upper; - } - } - return(OV_FALSE); - } + if(vf->ready_state != PARTOPEN) + return OV_EINVAL; + vf->ready_state=OPENED; + if(vf->seekable) + { + int ret=_open_seekable2(vf); + if(ret) + { + vf->datasource=NULL; + ov_clear(vf); } + return(ret); } -} + else + vf->ready_state=STREAMSET; -/* returns the actual bitrate since last call. returns -1 if no - additional data to offer since last call (or at beginning of stream), - EINVAL if stream is only partially open -*/ -long ov_bitrate_instant(OggVorbis_File *vf){ - int link=(vf->seekable?vf->current_link:0); - long ret; - if(vf->ready_statesamptrack==0)return(OV_FALSE); - ret=vf->bittrack/vf->samptrack*vf->vi[link].rate; - vf->bittrack=0; - vf->samptrack=0; - return(ret); -} - -/* Guess */ -long ov_serialnumber(OggVorbis_File *vf,int i){ - if(i>=vf->links)return(ov_serialnumber(vf,vf->links-1)); - if(!vf->seekable && i>=0)return(ov_serialnumber(vf,-1)); - if(i<0){ - return(vf->current_serialno); - }else{ - return(vf->serialnos[i]); - } -} - -/* returns: total raw (compressed) length of content if i==-1 - raw (compressed) length of that logical bitstream for i==0 to n - OV_EINVAL if the stream is not seekable (we can't know the length) - or if stream is only partially open -*/ -int64_t ov_raw_total(OggVorbis_File *vf,int i){ - if(vf->ready_stateseekable || i>=vf->links)return(OV_EINVAL); - if(i<0){ - int64_t acc=0; - int i; - for(i=0;ilinks;i++) - acc+=ov_raw_total(vf,i); - return(acc); - }else{ - return(vf->offsets[i+1]-vf->offsets[i]); - } + return 0; } /* returns: total PCM length (samples) of content if i==-1 PCM length @@ -1120,9 +1036,8 @@ int64_t ov_time_total(OggVorbis_File *vf,int i){ for(i=0;ilinks;i++) acc+=ov_time_total(vf,i); return(acc); - }else{ - return(((int64_t)vf->pcmlengths[i*2+1])*1000/vf->vi[i].rate); } + return(((int64_t)vf->pcmlengths[i*2+1])*1000/vf->vi[i].rate); } /* seek to an offset relative to the *compressed* data. This also @@ -1169,7 +1084,7 @@ int ov_raw_seek(OggVorbis_File *vf,int64_t pos){ the shared vf->os stream state. We use the local state to scan, and the shared state as a buffer for later decode. - Unfortuantely, on the last page we still advance to last packet + Unfortunately, on the last page we still advance to last packet because the granulepos on the last page is not necessarily on a packet boundary, and we need to make sure the granpos is correct. @@ -1190,7 +1105,7 @@ int ov_raw_seek(OggVorbis_File *vf,int64_t pos){ return from not necessarily starting from the beginning */ - while(1){ + for(;;){ if(vf->ready_state>=STREAMSET){ /* snarf/scan a packet if we can */ int result=ogg_stream_packetout(&work_os,&op); @@ -1467,7 +1382,7 @@ int ov_pcm_seek_page(OggVorbis_File *vf,int64_t pos){ ogg_stream_pagein(&vf->os,&og); /* pull out all but last packet; the one with granulepos */ - while(1){ + for(;;){ result=ogg_stream_packetpeek(&vf->os,&op); if(result==0){ /* !!! the packet finishing this page originated on a @@ -1478,14 +1393,13 @@ int ov_pcm_seek_page(OggVorbis_File *vf,int64_t pos){ result=_seek_helper(vf,best); if(result<0) goto seek_error; - while(1){ + for(;;){ result=_get_prev_page(vf,&og); if(result<0) goto seek_error; if(ogg_page_serialno(&og)==vf->current_serialno && (ogg_page_granulepos(&og)>-1 || - !ogg_page_continued(&og))){ + !ogg_page_continued(&og))) return ov_raw_seek(vf,result); - } vf->offset=result; } } @@ -1532,7 +1446,7 @@ int ov_pcm_seek(OggVorbis_File *vf,int64_t pos){ /* discard leading packets we don't need for the lapping of the position we want; don't decode them */ - while(1){ + for(;;){ ogg_packet op; ogg_page og; @@ -1616,101 +1530,6 @@ int ov_pcm_seek(OggVorbis_File *vf,int64_t pos){ return 0; } -/* seek to a playback time relative to the decompressed pcm stream - returns zero on success, nonzero on failure */ -int ov_time_seek(OggVorbis_File *vf,int64_t milliseconds){ - /* translate time to PCM position and call ov_pcm_seek */ - - int link=-1; - int64_t pcm_total=0; - int64_t time_total=0; - - if(vf->ready_stateseekable)return(OV_ENOSEEK); - if(milliseconds<0)return(OV_EINVAL); - - /* which bitstream section does this time offset occur in? */ - for(link=0;linklinks;link++){ - int64_t addsec = ov_time_total(vf,link); - if(millisecondspcmlengths[link*2+1]; - } - - if(link==vf->links)return(OV_EINVAL); - - /* enough information to convert time offset to pcm offset */ - { - int64_t target=pcm_total+(milliseconds-time_total)*vf->vi[link].rate/1000; - return(ov_pcm_seek(vf,target)); - } -} - -/* page-granularity version of ov_time_seek - returns zero on success, nonzero on failure */ -int ov_time_seek_page(OggVorbis_File *vf,int64_t milliseconds){ - /* translate time to PCM position and call ov_pcm_seek */ - - int link=-1; - int64_t pcm_total=0; - int64_t time_total=0; - - if(vf->ready_stateseekable)return(OV_ENOSEEK); - if(milliseconds<0)return(OV_EINVAL); - - /* which bitstream section does this time offset occur in? */ - for(link=0;linklinks;link++){ - int64_t addsec = ov_time_total(vf,link); - if(millisecondspcmlengths[link*2+1]; - } - - if(link==vf->links)return(OV_EINVAL); - - /* enough information to convert time offset to pcm offset */ - { - int64_t target=pcm_total+(milliseconds-time_total)*vf->vi[link].rate/1000; - return(ov_pcm_seek_page(vf,target)); - } -} - -/* tell the current stream offset cursor. Note that seek followed by - tell will likely not give the set offset due to caching */ -int64_t ov_raw_tell(OggVorbis_File *vf){ - if(vf->ready_stateoffset); -} - -/* return PCM offset (sample) of next PCM sample to be read */ -int64_t ov_pcm_tell(OggVorbis_File *vf){ - if(vf->ready_statepcm_offset); -} - -/* return time offset (milliseconds) of next PCM sample to be read */ -int64_t ov_time_tell(OggVorbis_File *vf){ - int link=0; - int64_t pcm_total=0; - int64_t time_total=0; - - if(vf->ready_stateseekable){ - pcm_total=ov_pcm_total(vf,-1); - time_total=ov_time_total(vf,-1); - - /* which bitstream section does this time offset occur in? */ - for(link=vf->links-1;link>=0;link--){ - pcm_total-=vf->pcmlengths[link*2+1]; - time_total-=ov_time_total(vf,link); - if(vf->pcm_offset>=pcm_total)break; - } - } - - return(time_total+(1000*vf->pcm_offset-pcm_total)/vf->vi[link].rate); -} - /* link: -1) return the vorbis_info struct for the bitstream section currently being decoded 0-n) to request information for a specific bitstream section @@ -1736,24 +1555,6 @@ vorbis_info *ov_info(OggVorbis_File *vf,int link){ } } -/* grr, strong typing, grr, no templates/inheritence, grr */ -vorbis_comment *ov_comment(OggVorbis_File *vf,int link){ - if(vf->seekable){ - if(link<0) - if(vf->ready_state>=STREAMSET) - return vf->vc+vf->current_link; - else - return vf->vc; - else - if(link>=vf->links) - return NULL; - else - return vf->vc+link; - }else{ - return vf->vc; - } -} - /* up to this point, everything could more or less hide the multiple logical bitstream nature of chaining from the toplevel application if the toplevel application didn't particularly care. However, at @@ -1781,7 +1582,8 @@ vorbis_comment *ov_comment(OggVorbis_File *vf,int link){ *section) set to the logical bitstream number */ -long ov_read(OggVorbis_File *vf,char *buffer,int bytes_req,int *bitstream){ +long ov_read(OggVorbis_File *vf,char *buffer,int bytes_req,int *bitstream) +{ int i,j; int32_t **pcm; @@ -1789,7 +1591,8 @@ long ov_read(OggVorbis_File *vf,char *buffer,int bytes_req,int *bitstream){ if(vf->ready_stateready_state==INITSET){ samples=vorbis_synthesis_pcmout(&vf->vd,&pcm); if(samples)break; @@ -1803,11 +1606,10 @@ long ov_read(OggVorbis_File *vf,char *buffer,int bytes_req,int *bitstream){ if(ret<=0) return(ret); } - } - if(samples>0){ - + if(samples>0) + { /* yay! proceed to pack data into the byte buffer */ long channels=ov_info(vf,-1)->channels; @@ -1826,9 +1628,8 @@ long ov_read(OggVorbis_File *vf,char *buffer,int bytes_req,int *bitstream){ vorbis_synthesis_read(&vf->vd,samples); vf->pcm_offset+=samples; - if(bitstream)*bitstream=vf->current_link; + if(bitstream) *bitstream=vf->current_link; return(samples*2*channels); - }else{ - return(samples); } + return(samples); }