dbf-halloween2015

annotate libs/vorbis/codebook.c @ 3:c37fe5d8a4ed

windows port
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 01 Nov 2015 06:04:28 +0200
parents
children
rev   line source
nuclear@1 1 /********************************************************************
nuclear@1 2 * *
nuclear@1 3 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
nuclear@1 4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
nuclear@1 5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
nuclear@1 6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
nuclear@1 7 * *
nuclear@1 8 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
nuclear@1 9 * by the Xiph.Org Foundation http://www.xiph.org/ *
nuclear@1 10 * *
nuclear@1 11 ********************************************************************
nuclear@1 12
nuclear@1 13 function: basic codebook pack/unpack/code/decode operations
nuclear@1 14 last mod: $Id: codebook.c 18183 2012-02-03 20:51:27Z xiphmont $
nuclear@1 15
nuclear@1 16 ********************************************************************/
nuclear@1 17
nuclear@1 18 #include <stdlib.h>
nuclear@1 19 #include <string.h>
nuclear@1 20 #include <math.h>
nuclear@1 21 #include <ogg/ogg.h>
nuclear@1 22 #include "vorbis/codec.h"
nuclear@1 23 #include "codebook.h"
nuclear@1 24 #include "scales.h"
nuclear@1 25 #include "misc.h"
nuclear@1 26 #include "os.h"
nuclear@1 27
nuclear@1 28 /* packs the given codebook into the bitstream **************************/
nuclear@1 29
nuclear@1 30 int vorbis_staticbook_pack(const static_codebook *c,oggpack_buffer *opb){
nuclear@1 31 long i,j;
nuclear@1 32 int ordered=0;
nuclear@1 33
nuclear@1 34 /* first the basic parameters */
nuclear@1 35 oggpack_write(opb,0x564342,24);
nuclear@1 36 oggpack_write(opb,c->dim,16);
nuclear@1 37 oggpack_write(opb,c->entries,24);
nuclear@1 38
nuclear@1 39 /* pack the codewords. There are two packings; length ordered and
nuclear@1 40 length random. Decide between the two now. */
nuclear@1 41
nuclear@1 42 for(i=1;i<c->entries;i++)
nuclear@1 43 if(c->lengthlist[i-1]==0 || c->lengthlist[i]<c->lengthlist[i-1])break;
nuclear@1 44 if(i==c->entries)ordered=1;
nuclear@1 45
nuclear@1 46 if(ordered){
nuclear@1 47 /* length ordered. We only need to say how many codewords of
nuclear@1 48 each length. The actual codewords are generated
nuclear@1 49 deterministically */
nuclear@1 50
nuclear@1 51 long count=0;
nuclear@1 52 oggpack_write(opb,1,1); /* ordered */
nuclear@1 53 oggpack_write(opb,c->lengthlist[0]-1,5); /* 1 to 32 */
nuclear@1 54
nuclear@1 55 for(i=1;i<c->entries;i++){
nuclear@1 56 long this=c->lengthlist[i];
nuclear@1 57 long last=c->lengthlist[i-1];
nuclear@1 58 if(this>last){
nuclear@1 59 for(j=last;j<this;j++){
nuclear@1 60 oggpack_write(opb,i-count,_ilog(c->entries-count));
nuclear@1 61 count=i;
nuclear@1 62 }
nuclear@1 63 }
nuclear@1 64 }
nuclear@1 65 oggpack_write(opb,i-count,_ilog(c->entries-count));
nuclear@1 66
nuclear@1 67 }else{
nuclear@1 68 /* length random. Again, we don't code the codeword itself, just
nuclear@1 69 the length. This time, though, we have to encode each length */
nuclear@1 70 oggpack_write(opb,0,1); /* unordered */
nuclear@1 71
nuclear@1 72 /* algortihmic mapping has use for 'unused entries', which we tag
nuclear@1 73 here. The algorithmic mapping happens as usual, but the unused
nuclear@1 74 entry has no codeword. */
nuclear@1 75 for(i=0;i<c->entries;i++)
nuclear@1 76 if(c->lengthlist[i]==0)break;
nuclear@1 77
nuclear@1 78 if(i==c->entries){
nuclear@1 79 oggpack_write(opb,0,1); /* no unused entries */
nuclear@1 80 for(i=0;i<c->entries;i++)
nuclear@1 81 oggpack_write(opb,c->lengthlist[i]-1,5);
nuclear@1 82 }else{
nuclear@1 83 oggpack_write(opb,1,1); /* we have unused entries; thus we tag */
nuclear@1 84 for(i=0;i<c->entries;i++){
nuclear@1 85 if(c->lengthlist[i]==0){
nuclear@1 86 oggpack_write(opb,0,1);
nuclear@1 87 }else{
nuclear@1 88 oggpack_write(opb,1,1);
nuclear@1 89 oggpack_write(opb,c->lengthlist[i]-1,5);
nuclear@1 90 }
nuclear@1 91 }
nuclear@1 92 }
nuclear@1 93 }
nuclear@1 94
nuclear@1 95 /* is the entry number the desired return value, or do we have a
nuclear@1 96 mapping? If we have a mapping, what type? */
nuclear@1 97 oggpack_write(opb,c->maptype,4);
nuclear@1 98 switch(c->maptype){
nuclear@1 99 case 0:
nuclear@1 100 /* no mapping */
nuclear@1 101 break;
nuclear@1 102 case 1:case 2:
nuclear@1 103 /* implicitly populated value mapping */
nuclear@1 104 /* explicitly populated value mapping */
nuclear@1 105
nuclear@1 106 if(!c->quantlist){
nuclear@1 107 /* no quantlist? error */
nuclear@1 108 return(-1);
nuclear@1 109 }
nuclear@1 110
nuclear@1 111 /* values that define the dequantization */
nuclear@1 112 oggpack_write(opb,c->q_min,32);
nuclear@1 113 oggpack_write(opb,c->q_delta,32);
nuclear@1 114 oggpack_write(opb,c->q_quant-1,4);
nuclear@1 115 oggpack_write(opb,c->q_sequencep,1);
nuclear@1 116
nuclear@1 117 {
nuclear@1 118 int quantvals;
nuclear@1 119 switch(c->maptype){
nuclear@1 120 case 1:
nuclear@1 121 /* a single column of (c->entries/c->dim) quantized values for
nuclear@1 122 building a full value list algorithmically (square lattice) */
nuclear@1 123 quantvals=_book_maptype1_quantvals(c);
nuclear@1 124 break;
nuclear@1 125 case 2:
nuclear@1 126 /* every value (c->entries*c->dim total) specified explicitly */
nuclear@1 127 quantvals=c->entries*c->dim;
nuclear@1 128 break;
nuclear@1 129 default: /* NOT_REACHABLE */
nuclear@1 130 quantvals=-1;
nuclear@1 131 }
nuclear@1 132
nuclear@1 133 /* quantized values */
nuclear@1 134 for(i=0;i<quantvals;i++)
nuclear@1 135 oggpack_write(opb,labs(c->quantlist[i]),c->q_quant);
nuclear@1 136
nuclear@1 137 }
nuclear@1 138 break;
nuclear@1 139 default:
nuclear@1 140 /* error case; we don't have any other map types now */
nuclear@1 141 return(-1);
nuclear@1 142 }
nuclear@1 143
nuclear@1 144 return(0);
nuclear@1 145 }
nuclear@1 146
nuclear@1 147 /* unpacks a codebook from the packet buffer into the codebook struct,
nuclear@1 148 readies the codebook auxiliary structures for decode *************/
nuclear@1 149 static_codebook *vorbis_staticbook_unpack(oggpack_buffer *opb){
nuclear@1 150 long i,j;
nuclear@1 151 static_codebook *s=_ogg_calloc(1,sizeof(*s));
nuclear@1 152 s->allocedp=1;
nuclear@1 153
nuclear@1 154 /* make sure alignment is correct */
nuclear@1 155 if(oggpack_read(opb,24)!=0x564342)goto _eofout;
nuclear@1 156
nuclear@1 157 /* first the basic parameters */
nuclear@1 158 s->dim=oggpack_read(opb,16);
nuclear@1 159 s->entries=oggpack_read(opb,24);
nuclear@1 160 if(s->entries==-1)goto _eofout;
nuclear@1 161
nuclear@1 162 if(_ilog(s->dim)+_ilog(s->entries)>24)goto _eofout;
nuclear@1 163
nuclear@1 164 /* codeword ordering.... length ordered or unordered? */
nuclear@1 165 switch((int)oggpack_read(opb,1)){
nuclear@1 166 case 0:{
nuclear@1 167 long unused;
nuclear@1 168 /* allocated but unused entries? */
nuclear@1 169 unused=oggpack_read(opb,1);
nuclear@1 170 if((s->entries*(unused?1:5)+7)>>3>opb->storage-oggpack_bytes(opb))
nuclear@1 171 goto _eofout;
nuclear@1 172 /* unordered */
nuclear@1 173 s->lengthlist=_ogg_malloc(sizeof(*s->lengthlist)*s->entries);
nuclear@1 174
nuclear@1 175 /* allocated but unused entries? */
nuclear@1 176 if(unused){
nuclear@1 177 /* yes, unused entries */
nuclear@1 178
nuclear@1 179 for(i=0;i<s->entries;i++){
nuclear@1 180 if(oggpack_read(opb,1)){
nuclear@1 181 long num=oggpack_read(opb,5);
nuclear@1 182 if(num==-1)goto _eofout;
nuclear@1 183 s->lengthlist[i]=num+1;
nuclear@1 184 }else
nuclear@1 185 s->lengthlist[i]=0;
nuclear@1 186 }
nuclear@1 187 }else{
nuclear@1 188 /* all entries used; no tagging */
nuclear@1 189 for(i=0;i<s->entries;i++){
nuclear@1 190 long num=oggpack_read(opb,5);
nuclear@1 191 if(num==-1)goto _eofout;
nuclear@1 192 s->lengthlist[i]=num+1;
nuclear@1 193 }
nuclear@1 194 }
nuclear@1 195
nuclear@1 196 break;
nuclear@1 197 }
nuclear@1 198 case 1:
nuclear@1 199 /* ordered */
nuclear@1 200 {
nuclear@1 201 long length=oggpack_read(opb,5)+1;
nuclear@1 202 if(length==0)goto _eofout;
nuclear@1 203 s->lengthlist=_ogg_malloc(sizeof(*s->lengthlist)*s->entries);
nuclear@1 204
nuclear@1 205 for(i=0;i<s->entries;){
nuclear@1 206 long num=oggpack_read(opb,_ilog(s->entries-i));
nuclear@1 207 if(num==-1)goto _eofout;
nuclear@1 208 if(length>32 || num>s->entries-i ||
nuclear@1 209 (num>0 && (num-1)>>(length-1)>1)){
nuclear@1 210 goto _errout;
nuclear@1 211 }
nuclear@1 212 if(length>32)goto _errout;
nuclear@1 213 for(j=0;j<num;j++,i++)
nuclear@1 214 s->lengthlist[i]=length;
nuclear@1 215 length++;
nuclear@1 216 }
nuclear@1 217 }
nuclear@1 218 break;
nuclear@1 219 default:
nuclear@1 220 /* EOF */
nuclear@1 221 goto _eofout;
nuclear@1 222 }
nuclear@1 223
nuclear@1 224 /* Do we have a mapping to unpack? */
nuclear@1 225 switch((s->maptype=oggpack_read(opb,4))){
nuclear@1 226 case 0:
nuclear@1 227 /* no mapping */
nuclear@1 228 break;
nuclear@1 229 case 1: case 2:
nuclear@1 230 /* implicitly populated value mapping */
nuclear@1 231 /* explicitly populated value mapping */
nuclear@1 232
nuclear@1 233 s->q_min=oggpack_read(opb,32);
nuclear@1 234 s->q_delta=oggpack_read(opb,32);
nuclear@1 235 s->q_quant=oggpack_read(opb,4)+1;
nuclear@1 236 s->q_sequencep=oggpack_read(opb,1);
nuclear@1 237 if(s->q_sequencep==-1)goto _eofout;
nuclear@1 238
nuclear@1 239 {
nuclear@1 240 int quantvals=0;
nuclear@1 241 switch(s->maptype){
nuclear@1 242 case 1:
nuclear@1 243 quantvals=(s->dim==0?0:_book_maptype1_quantvals(s));
nuclear@1 244 break;
nuclear@1 245 case 2:
nuclear@1 246 quantvals=s->entries*s->dim;
nuclear@1 247 break;
nuclear@1 248 }
nuclear@1 249
nuclear@1 250 /* quantized values */
nuclear@1 251 if(((quantvals*s->q_quant+7)>>3)>opb->storage-oggpack_bytes(opb))
nuclear@1 252 goto _eofout;
nuclear@1 253 s->quantlist=_ogg_malloc(sizeof(*s->quantlist)*quantvals);
nuclear@1 254 for(i=0;i<quantvals;i++)
nuclear@1 255 s->quantlist[i]=oggpack_read(opb,s->q_quant);
nuclear@1 256
nuclear@1 257 if(quantvals&&s->quantlist[quantvals-1]==-1)goto _eofout;
nuclear@1 258 }
nuclear@1 259 break;
nuclear@1 260 default:
nuclear@1 261 goto _errout;
nuclear@1 262 }
nuclear@1 263
nuclear@1 264 /* all set */
nuclear@1 265 return(s);
nuclear@1 266
nuclear@1 267 _errout:
nuclear@1 268 _eofout:
nuclear@1 269 vorbis_staticbook_destroy(s);
nuclear@1 270 return(NULL);
nuclear@1 271 }
nuclear@1 272
nuclear@1 273 /* returns the number of bits ************************************************/
nuclear@1 274 int vorbis_book_encode(codebook *book, int a, oggpack_buffer *b){
nuclear@1 275 if(a<0 || a>=book->c->entries)return(0);
nuclear@1 276 oggpack_write(b,book->codelist[a],book->c->lengthlist[a]);
nuclear@1 277 return(book->c->lengthlist[a]);
nuclear@1 278 }
nuclear@1 279
nuclear@1 280 /* the 'eliminate the decode tree' optimization actually requires the
nuclear@1 281 codewords to be MSb first, not LSb. This is an annoying inelegancy
nuclear@1 282 (and one of the first places where carefully thought out design
nuclear@1 283 turned out to be wrong; Vorbis II and future Ogg codecs should go
nuclear@1 284 to an MSb bitpacker), but not actually the huge hit it appears to
nuclear@1 285 be. The first-stage decode table catches most words so that
nuclear@1 286 bitreverse is not in the main execution path. */
nuclear@1 287
nuclear@1 288 static ogg_uint32_t bitreverse(ogg_uint32_t x){
nuclear@1 289 x= ((x>>16)&0x0000ffff) | ((x<<16)&0xffff0000);
nuclear@1 290 x= ((x>> 8)&0x00ff00ff) | ((x<< 8)&0xff00ff00);
nuclear@1 291 x= ((x>> 4)&0x0f0f0f0f) | ((x<< 4)&0xf0f0f0f0);
nuclear@1 292 x= ((x>> 2)&0x33333333) | ((x<< 2)&0xcccccccc);
nuclear@1 293 return((x>> 1)&0x55555555) | ((x<< 1)&0xaaaaaaaa);
nuclear@1 294 }
nuclear@1 295
nuclear@1 296 STIN long decode_packed_entry_number(codebook *book, oggpack_buffer *b){
nuclear@1 297 int read=book->dec_maxlength;
nuclear@1 298 long lo,hi;
nuclear@1 299 long lok = oggpack_look(b,book->dec_firsttablen);
nuclear@1 300
nuclear@1 301 if (lok >= 0) {
nuclear@1 302 long entry = book->dec_firsttable[lok];
nuclear@1 303 if(entry&0x80000000UL){
nuclear@1 304 lo=(entry>>15)&0x7fff;
nuclear@1 305 hi=book->used_entries-(entry&0x7fff);
nuclear@1 306 }else{
nuclear@1 307 oggpack_adv(b, book->dec_codelengths[entry-1]);
nuclear@1 308 return(entry-1);
nuclear@1 309 }
nuclear@1 310 }else{
nuclear@1 311 lo=0;
nuclear@1 312 hi=book->used_entries;
nuclear@1 313 }
nuclear@1 314
nuclear@1 315 lok = oggpack_look(b, read);
nuclear@1 316
nuclear@1 317 while(lok<0 && read>1)
nuclear@1 318 lok = oggpack_look(b, --read);
nuclear@1 319 if(lok<0)return -1;
nuclear@1 320
nuclear@1 321 /* bisect search for the codeword in the ordered list */
nuclear@1 322 {
nuclear@1 323 ogg_uint32_t testword=bitreverse((ogg_uint32_t)lok);
nuclear@1 324
nuclear@1 325 while(hi-lo>1){
nuclear@1 326 long p=(hi-lo)>>1;
nuclear@1 327 long test=book->codelist[lo+p]>testword;
nuclear@1 328 lo+=p&(test-1);
nuclear@1 329 hi-=p&(-test);
nuclear@1 330 }
nuclear@1 331
nuclear@1 332 if(book->dec_codelengths[lo]<=read){
nuclear@1 333 oggpack_adv(b, book->dec_codelengths[lo]);
nuclear@1 334 return(lo);
nuclear@1 335 }
nuclear@1 336 }
nuclear@1 337
nuclear@1 338 oggpack_adv(b, read);
nuclear@1 339
nuclear@1 340 return(-1);
nuclear@1 341 }
nuclear@1 342
nuclear@1 343 /* Decode side is specced and easier, because we don't need to find
nuclear@1 344 matches using different criteria; we simply read and map. There are
nuclear@1 345 two things we need to do 'depending':
nuclear@1 346
nuclear@1 347 We may need to support interleave. We don't really, but it's
nuclear@1 348 convenient to do it here rather than rebuild the vector later.
nuclear@1 349
nuclear@1 350 Cascades may be additive or multiplicitive; this is not inherent in
nuclear@1 351 the codebook, but set in the code using the codebook. Like
nuclear@1 352 interleaving, it's easiest to do it here.
nuclear@1 353 addmul==0 -> declarative (set the value)
nuclear@1 354 addmul==1 -> additive
nuclear@1 355 addmul==2 -> multiplicitive */
nuclear@1 356
nuclear@1 357 /* returns the [original, not compacted] entry number or -1 on eof *********/
nuclear@1 358 long vorbis_book_decode(codebook *book, oggpack_buffer *b){
nuclear@1 359 if(book->used_entries>0){
nuclear@1 360 long packed_entry=decode_packed_entry_number(book,b);
nuclear@1 361 if(packed_entry>=0)
nuclear@1 362 return(book->dec_index[packed_entry]);
nuclear@1 363 }
nuclear@1 364
nuclear@1 365 /* if there's no dec_index, the codebook unpacking isn't collapsed */
nuclear@1 366 return(-1);
nuclear@1 367 }
nuclear@1 368
nuclear@1 369 /* returns 0 on OK or -1 on eof *************************************/
nuclear@1 370 /* decode vector / dim granularity gaurding is done in the upper layer */
nuclear@1 371 long vorbis_book_decodevs_add(codebook *book,float *a,oggpack_buffer *b,int n){
nuclear@1 372 if(book->used_entries>0){
nuclear@1 373 int step=n/book->dim;
nuclear@1 374 long *entry = alloca(sizeof(*entry)*step);
nuclear@1 375 float **t = alloca(sizeof(*t)*step);
nuclear@1 376 int i,j,o;
nuclear@1 377
nuclear@1 378 for (i = 0; i < step; i++) {
nuclear@1 379 entry[i]=decode_packed_entry_number(book,b);
nuclear@1 380 if(entry[i]==-1)return(-1);
nuclear@1 381 t[i] = book->valuelist+entry[i]*book->dim;
nuclear@1 382 }
nuclear@1 383 for(i=0,o=0;i<book->dim;i++,o+=step)
nuclear@1 384 for (j=0;j<step;j++)
nuclear@1 385 a[o+j]+=t[j][i];
nuclear@1 386 }
nuclear@1 387 return(0);
nuclear@1 388 }
nuclear@1 389
nuclear@1 390 /* decode vector / dim granularity gaurding is done in the upper layer */
nuclear@1 391 long vorbis_book_decodev_add(codebook *book,float *a,oggpack_buffer *b,int n){
nuclear@1 392 if(book->used_entries>0){
nuclear@1 393 int i,j,entry;
nuclear@1 394 float *t;
nuclear@1 395
nuclear@1 396 if(book->dim>8){
nuclear@1 397 for(i=0;i<n;){
nuclear@1 398 entry = decode_packed_entry_number(book,b);
nuclear@1 399 if(entry==-1)return(-1);
nuclear@1 400 t = book->valuelist+entry*book->dim;
nuclear@1 401 for (j=0;j<book->dim;)
nuclear@1 402 a[i++]+=t[j++];
nuclear@1 403 }
nuclear@1 404 }else{
nuclear@1 405 for(i=0;i<n;){
nuclear@1 406 entry = decode_packed_entry_number(book,b);
nuclear@1 407 if(entry==-1)return(-1);
nuclear@1 408 t = book->valuelist+entry*book->dim;
nuclear@1 409 j=0;
nuclear@1 410 switch((int)book->dim){
nuclear@1 411 case 8:
nuclear@1 412 a[i++]+=t[j++];
nuclear@1 413 case 7:
nuclear@1 414 a[i++]+=t[j++];
nuclear@1 415 case 6:
nuclear@1 416 a[i++]+=t[j++];
nuclear@1 417 case 5:
nuclear@1 418 a[i++]+=t[j++];
nuclear@1 419 case 4:
nuclear@1 420 a[i++]+=t[j++];
nuclear@1 421 case 3:
nuclear@1 422 a[i++]+=t[j++];
nuclear@1 423 case 2:
nuclear@1 424 a[i++]+=t[j++];
nuclear@1 425 case 1:
nuclear@1 426 a[i++]+=t[j++];
nuclear@1 427 case 0:
nuclear@1 428 break;
nuclear@1 429 }
nuclear@1 430 }
nuclear@1 431 }
nuclear@1 432 }
nuclear@1 433 return(0);
nuclear@1 434 }
nuclear@1 435
nuclear@1 436 /* unlike the others, we guard against n not being an integer number
nuclear@1 437 of <dim> internally rather than in the upper layer (called only by
nuclear@1 438 floor0) */
nuclear@1 439 long vorbis_book_decodev_set(codebook *book,float *a,oggpack_buffer *b,int n){
nuclear@1 440 if(book->used_entries>0){
nuclear@1 441 int i,j,entry;
nuclear@1 442 float *t;
nuclear@1 443
nuclear@1 444 for(i=0;i<n;){
nuclear@1 445 entry = decode_packed_entry_number(book,b);
nuclear@1 446 if(entry==-1)return(-1);
nuclear@1 447 t = book->valuelist+entry*book->dim;
nuclear@1 448 for (j=0;i<n && j<book->dim;){
nuclear@1 449 a[i++]=t[j++];
nuclear@1 450 }
nuclear@1 451 }
nuclear@1 452 }else{
nuclear@1 453 int i;
nuclear@1 454
nuclear@1 455 for(i=0;i<n;){
nuclear@1 456 a[i++]=0.f;
nuclear@1 457 }
nuclear@1 458 }
nuclear@1 459 return(0);
nuclear@1 460 }
nuclear@1 461
nuclear@1 462 long vorbis_book_decodevv_add(codebook *book,float **a,long offset,int ch,
nuclear@1 463 oggpack_buffer *b,int n){
nuclear@1 464
nuclear@1 465 long i,j,entry;
nuclear@1 466 int chptr=0;
nuclear@1 467 if(book->used_entries>0){
nuclear@1 468 for(i=offset/ch;i<(offset+n)/ch;){
nuclear@1 469 entry = decode_packed_entry_number(book,b);
nuclear@1 470 if(entry==-1)return(-1);
nuclear@1 471 {
nuclear@1 472 const float *t = book->valuelist+entry*book->dim;
nuclear@1 473 for (j=0;j<book->dim;j++){
nuclear@1 474 a[chptr++][i]+=t[j];
nuclear@1 475 if(chptr==ch){
nuclear@1 476 chptr=0;
nuclear@1 477 i++;
nuclear@1 478 }
nuclear@1 479 }
nuclear@1 480 }
nuclear@1 481 }
nuclear@1 482 }
nuclear@1 483 return(0);
nuclear@1 484 }