wininet: Trace more parameters to HTTP_GetCustomHeaderIndex.
[wine] / dlls / mshtml / htmltable.c
1 /*
2  * Copyright 2007 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <stdarg.h>
20
21 #define COBJMACROS
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "ole2.h"
27
28 #include "wine/debug.h"
29
30 #include "mshtml_private.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
33
34 struct HTMLTable {
35     HTMLElement element;
36
37     const IHTMLTableVtbl  *lpHTMLTableVtbl;
38
39     ConnectionPoint cp;
40     nsIDOMHTMLTableElement *nstable;
41 };
42
43 #define HTMLTABLE(x)  (&(x)->lpHTMLTableVtbl)
44
45 #define HTMLTABLE_THIS(iface) DEFINE_THIS(HTMLTable, HTMLTable, iface)
46
47 static HRESULT WINAPI HTMLTable_QueryInterface(IHTMLTable *iface,
48                                                          REFIID riid, void **ppv)
49 {
50     HTMLTable *This = HTMLTABLE_THIS(iface);
51
52     return IHTMLDOMNode_QueryInterface(HTMLDOMNODE(&This->element.node), riid, ppv);
53 }
54
55 static ULONG WINAPI HTMLTable_AddRef(IHTMLTable *iface)
56 {
57     HTMLTable *This = HTMLTABLE_THIS(iface);
58
59     return IHTMLDOMNode_AddRef(HTMLDOMNODE(&This->element.node));
60 }
61
62 static ULONG WINAPI HTMLTable_Release(IHTMLTable *iface)
63 {
64     HTMLTable *This = HTMLTABLE_THIS(iface);
65
66     return IHTMLDOMNode_Release(HTMLDOMNODE(&This->element.node));
67 }
68
69 static HRESULT WINAPI HTMLTable_GetTypeInfoCount(IHTMLTable *iface, UINT *pctinfo)
70 {
71     HTMLTable *This = HTMLTABLE_THIS(iface);
72     return IDispatchEx_GetTypeInfoCount(DISPATCHEX(&This->element.node.dispex), pctinfo);
73 }
74
75 static HRESULT WINAPI HTMLTable_GetTypeInfo(IHTMLTable *iface, UINT iTInfo,
76                                               LCID lcid, ITypeInfo **ppTInfo)
77 {
78     HTMLTable *This = HTMLTABLE_THIS(iface);
79     return IDispatchEx_GetTypeInfo(DISPATCHEX(&This->element.node.dispex), iTInfo, lcid, ppTInfo);
80 }
81
82 static HRESULT WINAPI HTMLTable_GetIDsOfNames(IHTMLTable *iface, REFIID riid,
83                                                 LPOLESTR *rgszNames, UINT cNames,
84                                                 LCID lcid, DISPID *rgDispId)
85 {
86     HTMLTable *This = HTMLTABLE_THIS(iface);
87     return IDispatchEx_GetIDsOfNames(DISPATCHEX(&This->element.node.dispex), riid, rgszNames, cNames, lcid, rgDispId);
88 }
89
90 static HRESULT WINAPI HTMLTable_Invoke(IHTMLTable *iface, DISPID dispIdMember,
91                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
92                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
93 {
94     HTMLTable *This = HTMLTABLE_THIS(iface);
95     return IDispatchEx_Invoke(DISPATCHEX(&This->element.node.dispex), dispIdMember, riid, lcid, wFlags, pDispParams,
96             pVarResult, pExcepInfo, puArgErr);
97 }
98
99 static HRESULT WINAPI HTMLTable_put_cols(IHTMLTable *iface, LONG v)
100 {
101     HTMLTable *This = HTMLTABLE_THIS(iface);
102     FIXME("(%p)->(%d)\n", This, v);
103     return E_NOTIMPL;
104 }
105
106 static HRESULT WINAPI HTMLTable_get_cols(IHTMLTable *iface, LONG *p)
107 {
108     HTMLTable *This = HTMLTABLE_THIS(iface);
109     FIXME("(%p)->(%p)\n", This, p);
110     return E_NOTIMPL;
111 }
112
113 static HRESULT WINAPI HTMLTable_put_border(IHTMLTable *iface, VARIANT v)
114 {
115     HTMLTable *This = HTMLTABLE_THIS(iface);
116     FIXME("(%p)->(v)\n", This);
117     return E_NOTIMPL;
118 }
119
120 static HRESULT WINAPI HTMLTable_get_border(IHTMLTable *iface, VARIANT *p)
121 {
122     HTMLTable *This = HTMLTABLE_THIS(iface);
123     FIXME("(%p)->(%p)\n", This, p);
124     return E_NOTIMPL;
125 }
126
127 static HRESULT WINAPI HTMLTable_put_frame(IHTMLTable *iface, BSTR v)
128 {
129     HTMLTable *This = HTMLTABLE_THIS(iface);
130     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
131     return E_NOTIMPL;
132 }
133
134 static HRESULT WINAPI HTMLTable_get_frame(IHTMLTable *iface, BSTR *p)
135 {
136     HTMLTable *This = HTMLTABLE_THIS(iface);
137     FIXME("(%p)->(%p)\n", This, p);
138     return E_NOTIMPL;
139 }
140
141 static HRESULT WINAPI HTMLTable_put_rules(IHTMLTable *iface, BSTR v)
142 {
143     HTMLTable *This = HTMLTABLE_THIS(iface);
144     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
145     return E_NOTIMPL;
146 }
147
148 static HRESULT WINAPI HTMLTable_get_rules(IHTMLTable *iface, BSTR *p)
149 {
150     HTMLTable *This = HTMLTABLE_THIS(iface);
151     FIXME("(%p)->(%p)\n", This, p);
152     return E_NOTIMPL;
153 }
154
155 static HRESULT WINAPI HTMLTable_put_cellSpacing(IHTMLTable *iface, VARIANT v)
156 {
157     HTMLTable *This = HTMLTABLE_THIS(iface);
158     FIXME("(%p)->(v)\n", This);
159     return E_NOTIMPL;
160 }
161
162 static HRESULT WINAPI HTMLTable_get_cellSpacing(IHTMLTable *iface, VARIANT *p)
163 {
164     HTMLTable *This = HTMLTABLE_THIS(iface);
165     FIXME("(%p)->(%p)\n", This, p);
166     return E_NOTIMPL;
167 }
168
169 static HRESULT WINAPI HTMLTable_put_cellPadding(IHTMLTable *iface, VARIANT v)
170 {
171     HTMLTable *This = HTMLTABLE_THIS(iface);
172     FIXME("(%p)->(v)\n", This);
173     return E_NOTIMPL;
174 }
175
176 static HRESULT WINAPI HTMLTable_get_cellPadding(IHTMLTable *iface, VARIANT *p)
177 {
178     HTMLTable *This = HTMLTABLE_THIS(iface);
179     FIXME("(%p)->(%p)\n", This, p);
180     return E_NOTIMPL;
181 }
182
183 static HRESULT WINAPI HTMLTable_put_background(IHTMLTable *iface, BSTR v)
184 {
185     HTMLTable *This = HTMLTABLE_THIS(iface);
186     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
187     return E_NOTIMPL;
188 }
189
190 static HRESULT WINAPI HTMLTable_get_background(IHTMLTable *iface, BSTR *p)
191 {
192     HTMLTable *This = HTMLTABLE_THIS(iface);
193     FIXME("(%p)->(%p)\n", This, p);
194     return E_NOTIMPL;
195 }
196
197 static HRESULT WINAPI HTMLTable_put_bgColor(IHTMLTable *iface, VARIANT v)
198 {
199     HTMLTable *This = HTMLTABLE_THIS(iface);
200     FIXME("(%p)->(v)\n", This);
201     return E_NOTIMPL;
202 }
203
204 static HRESULT WINAPI HTMLTable_get_bgColor(IHTMLTable *iface, VARIANT *p)
205 {
206     HTMLTable *This = HTMLTABLE_THIS(iface);
207     FIXME("(%p)->(%p)\n", This, p);
208     return E_NOTIMPL;
209 }
210
211 static HRESULT WINAPI HTMLTable_put_borderColor(IHTMLTable *iface, VARIANT v)
212 {
213     HTMLTable *This = HTMLTABLE_THIS(iface);
214     FIXME("(%p)->(v)\n", This);
215     return E_NOTIMPL;
216 }
217
218 static HRESULT WINAPI HTMLTable_get_borderColor(IHTMLTable *iface, VARIANT *p)
219 {
220     HTMLTable *This = HTMLTABLE_THIS(iface);
221     FIXME("(%p)->(%p)\n", This, p);
222     return E_NOTIMPL;
223 }
224
225 static HRESULT WINAPI HTMLTable_put_borderColorLight(IHTMLTable *iface, VARIANT v)
226 {
227     HTMLTable *This = HTMLTABLE_THIS(iface);
228     FIXME("(%p)->(v)\n", This);
229     return E_NOTIMPL;
230 }
231
232 static HRESULT WINAPI HTMLTable_get_borderColorLight(IHTMLTable *iface, VARIANT *p)
233 {
234     HTMLTable *This = HTMLTABLE_THIS(iface);
235     FIXME("(%p)->(%p)\n", This, p);
236     return E_NOTIMPL;
237 }
238
239 static HRESULT WINAPI HTMLTable_put_borderColorDark(IHTMLTable *iface, VARIANT v)
240 {
241     HTMLTable *This = HTMLTABLE_THIS(iface);
242     FIXME("(%p)->(v)\n", This);
243     return E_NOTIMPL;
244 }
245
246 static HRESULT WINAPI HTMLTable_get_borderColorDark(IHTMLTable *iface, VARIANT *p)
247 {
248     HTMLTable *This = HTMLTABLE_THIS(iface);
249     FIXME("(%p)->(%p)\n", This, p);
250     return E_NOTIMPL;
251 }
252
253 static HRESULT WINAPI HTMLTable_put_align(IHTMLTable *iface, BSTR v)
254 {
255     HTMLTable *This = HTMLTABLE_THIS(iface);
256     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
257     return E_NOTIMPL;
258 }
259
260 static HRESULT WINAPI HTMLTable_get_align(IHTMLTable *iface, BSTR *p)
261 {
262     HTMLTable *This = HTMLTABLE_THIS(iface);
263     FIXME("(%p)->(%p)\n", This, p);
264     return E_NOTIMPL;
265 }
266
267 static HRESULT WINAPI HTMLTable_refresh(IHTMLTable *iface)
268 {
269     HTMLTable *This = HTMLTABLE_THIS(iface);
270     FIXME("(%p)\n", This);
271     return E_NOTIMPL;
272 }
273
274 static HRESULT WINAPI HTMLTable_get_rows(IHTMLTable *iface, IHTMLElementCollection **p)
275 {
276     HTMLTable *This = HTMLTABLE_THIS(iface);
277     nsIDOMHTMLCollection *nscol;
278     nsresult nsres;
279
280     TRACE("(%p)->(%p)\n", This, p);
281
282     nsres = nsIDOMHTMLTableElement_GetRows(This->nstable, &nscol);
283     if(NS_FAILED(nsres)) {
284         ERR("GetRows failed: %08x\n", nsres);
285         return E_FAIL;
286     }
287
288     *p = create_collection_from_htmlcol(This->element.node.doc, (IUnknown*)HTMLTABLE(This), nscol);
289
290     nsIDOMHTMLCollection_Release(nscol);
291     return S_OK;
292 }
293
294 static HRESULT WINAPI HTMLTable_put_width(IHTMLTable *iface, VARIANT v)
295 {
296     HTMLTable *This = HTMLTABLE_THIS(iface);
297     FIXME("(%p)->(v)\n", This);
298     return E_NOTIMPL;
299 }
300
301 static HRESULT WINAPI HTMLTable_get_width(IHTMLTable *iface, VARIANT *p)
302 {
303     HTMLTable *This = HTMLTABLE_THIS(iface);
304     FIXME("(%p)->(%p)\n", This, p);
305     return E_NOTIMPL;
306 }
307
308 static HRESULT WINAPI HTMLTable_put_height(IHTMLTable *iface, VARIANT v)
309 {
310     HTMLTable *This = HTMLTABLE_THIS(iface);
311     FIXME("(%p)->(v)\n", This);
312     return E_NOTIMPL;
313 }
314
315 static HRESULT WINAPI HTMLTable_get_height(IHTMLTable *iface, VARIANT *p)
316 {
317     HTMLTable *This = HTMLTABLE_THIS(iface);
318     FIXME("(%p)->(%p)\n", This, p);
319     return E_NOTIMPL;
320 }
321
322 static HRESULT WINAPI HTMLTable_put_dataPageSize(IHTMLTable *iface, LONG v)
323 {
324     HTMLTable *This = HTMLTABLE_THIS(iface);
325     FIXME("(%p)->(%d)\n", This, v);
326     return E_NOTIMPL;
327 }
328
329 static HRESULT WINAPI HTMLTable_get_dataPageSize(IHTMLTable *iface, LONG *p)
330 {
331     HTMLTable *This = HTMLTABLE_THIS(iface);
332     FIXME("(%p)->(%p)\n", This, p);
333     return E_NOTIMPL;
334 }
335
336 static HRESULT WINAPI HTMLTable_nextPage(IHTMLTable *iface)
337 {
338     HTMLTable *This = HTMLTABLE_THIS(iface);
339     FIXME("(%p)\n", This);
340     return E_NOTIMPL;
341 }
342
343 static HRESULT WINAPI HTMLTable_previousPage(IHTMLTable *iface)
344 {
345     HTMLTable *This = HTMLTABLE_THIS(iface);
346     FIXME("(%p)\n", This);
347     return E_NOTIMPL;
348 }
349
350 static HRESULT WINAPI HTMLTable_get_tHead(IHTMLTable *iface, IHTMLTableSection **p)
351 {
352     HTMLTable *This = HTMLTABLE_THIS(iface);
353     FIXME("(%p)->(%p)\n", This, p);
354     return E_NOTIMPL;
355 }
356
357 static HRESULT WINAPI HTMLTable_get_tFoot(IHTMLTable *iface, IHTMLTableSection **p)
358 {
359     HTMLTable *This = HTMLTABLE_THIS(iface);
360     FIXME("(%p)->(%p)\n", This, p);
361     return E_NOTIMPL;
362 }
363
364 static HRESULT WINAPI HTMLTable_get_tBodies(IHTMLTable *iface, IHTMLElementCollection **p)
365 {
366     HTMLTable *This = HTMLTABLE_THIS(iface);
367     FIXME("(%p)->(%p)\n", This, p);
368     return E_NOTIMPL;
369 }
370
371 static HRESULT WINAPI HTMLTable_get_caption(IHTMLTable *iface, IHTMLTableCaption **p)
372 {
373     HTMLTable *This = HTMLTABLE_THIS(iface);
374     FIXME("(%p)->(%p)\n", This, p);
375     return E_NOTIMPL;
376 }
377
378 static HRESULT WINAPI HTMLTable_createTHead(IHTMLTable *iface, IDispatch **head)
379 {
380     HTMLTable *This = HTMLTABLE_THIS(iface);
381     FIXME("(%p)->(%p)\n", This, head);
382     return E_NOTIMPL;
383 }
384
385 static HRESULT WINAPI HTMLTable_deleteTHead(IHTMLTable *iface)
386 {
387     HTMLTable *This = HTMLTABLE_THIS(iface);
388     FIXME("(%p)\n", This);
389     return E_NOTIMPL;
390 }
391
392 static HRESULT WINAPI HTMLTable_createTFoot(IHTMLTable *iface, IDispatch **foot)
393 {
394     HTMLTable *This = HTMLTABLE_THIS(iface);
395     FIXME("(%p)->(%p)\n", This, foot);
396     return E_NOTIMPL;
397 }
398
399 static HRESULT WINAPI HTMLTable_deleteTFoot(IHTMLTable *iface)
400 {
401     HTMLTable *This = HTMLTABLE_THIS(iface);
402     FIXME("(%p)\n", This);
403     return E_NOTIMPL;
404 }
405
406 static HRESULT WINAPI HTMLTable_createCaption(IHTMLTable *iface, IHTMLTableCaption **caption)
407 {
408     HTMLTable *This = HTMLTABLE_THIS(iface);
409     FIXME("(%p)->(%p)\n", This, caption);
410     return E_NOTIMPL;
411 }
412
413 static HRESULT WINAPI HTMLTable_deleteCaption(IHTMLTable *iface)
414 {
415     HTMLTable *This = HTMLTABLE_THIS(iface);
416     FIXME("(%p)\n", This);
417     return E_NOTIMPL;
418 }
419
420 static HRESULT WINAPI HTMLTable_insertRow(IHTMLTable *iface, LONG index, IDispatch **row)
421 {
422     HTMLTable *This = HTMLTABLE_THIS(iface);
423     FIXME("(%p)->(%d %p)\n", This, index, row);
424     return E_NOTIMPL;
425 }
426
427 static HRESULT WINAPI HTMLTable_deleteRow(IHTMLTable *iface, LONG index)
428 {
429     HTMLTable *This = HTMLTABLE_THIS(iface);
430     FIXME("(%p)->(%d)\n", This, index);
431     return E_NOTIMPL;
432 }
433
434 static HRESULT WINAPI HTMLTable_get_readyState(IHTMLTable *iface, BSTR *p)
435 {
436     HTMLTable *This = HTMLTABLE_THIS(iface);
437     FIXME("(%p)->(%p)\n", This, p);
438     return E_NOTIMPL;
439 }
440
441 static HRESULT WINAPI HTMLTable_put_onreadystatechange(IHTMLTable *iface, VARIANT v)
442 {
443     HTMLTable *This = HTMLTABLE_THIS(iface);
444     FIXME("(%p)->(v)\n", This);
445     return E_NOTIMPL;
446 }
447
448 static HRESULT WINAPI HTMLTable_get_onreadystatechange(IHTMLTable *iface, VARIANT *p)
449 {
450     HTMLTable *This = HTMLTABLE_THIS(iface);
451     FIXME("(%p)->(%p)\n", This, p);
452     return E_NOTIMPL;
453 }
454
455 #undef HTMLTABLE_THIS
456
457 static const IHTMLTableVtbl HTMLTableVtbl = {
458     HTMLTable_QueryInterface,
459     HTMLTable_AddRef,
460     HTMLTable_Release,
461     HTMLTable_GetTypeInfoCount,
462     HTMLTable_GetTypeInfo,
463     HTMLTable_GetIDsOfNames,
464     HTMLTable_Invoke,
465     HTMLTable_put_cols,
466     HTMLTable_get_cols,
467     HTMLTable_put_border,
468     HTMLTable_get_border,
469     HTMLTable_put_frame,
470     HTMLTable_get_frame,
471     HTMLTable_put_rules,
472     HTMLTable_get_rules,
473     HTMLTable_put_cellSpacing,
474     HTMLTable_get_cellSpacing,
475     HTMLTable_put_cellPadding,
476     HTMLTable_get_cellPadding,
477     HTMLTable_put_background,
478     HTMLTable_get_background,
479     HTMLTable_put_bgColor,
480     HTMLTable_get_bgColor,
481     HTMLTable_put_borderColor,
482     HTMLTable_get_borderColor,
483     HTMLTable_put_borderColorLight,
484     HTMLTable_get_borderColorLight,
485     HTMLTable_put_borderColorDark,
486     HTMLTable_get_borderColorDark,
487     HTMLTable_put_align,
488     HTMLTable_get_align,
489     HTMLTable_refresh,
490     HTMLTable_get_rows,
491     HTMLTable_put_width,
492     HTMLTable_get_width,
493     HTMLTable_put_height,
494     HTMLTable_get_height,
495     HTMLTable_put_dataPageSize,
496     HTMLTable_get_dataPageSize,
497     HTMLTable_nextPage,
498     HTMLTable_previousPage,
499     HTMLTable_get_tHead,
500     HTMLTable_get_tFoot,
501     HTMLTable_get_tBodies,
502     HTMLTable_get_caption,
503     HTMLTable_createTHead,
504     HTMLTable_deleteTHead,
505     HTMLTable_createTFoot,
506     HTMLTable_deleteTFoot,
507     HTMLTable_createCaption,
508     HTMLTable_deleteCaption,
509     HTMLTable_insertRow,
510     HTMLTable_deleteRow,
511     HTMLTable_get_readyState,
512     HTMLTable_put_onreadystatechange,
513     HTMLTable_get_onreadystatechange
514 };
515
516 #define HTMLTABLE_NODE_THIS(iface) DEFINE_THIS2(HTMLTable, element.node, iface)
517
518 static HRESULT HTMLTable_QI(HTMLDOMNode *iface, REFIID riid, void **ppv)
519 {
520     HTMLTable *This = HTMLTABLE_NODE_THIS(iface);
521
522     *ppv = NULL;
523
524     if(IsEqualGUID(&IID_IUnknown, riid)) {
525         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
526         *ppv = HTMLTABLE(This);
527     }else if(IsEqualGUID(&IID_IDispatch, riid)) {
528         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
529         *ppv = HTMLTABLE(This);
530     }else if(IsEqualGUID(&IID_IHTMLTable, riid)) {
531         TRACE("(%p)->(IID_IHTMLTable %p)\n", This, ppv);
532         *ppv = HTMLTABLE(This);
533     }
534
535     if(*ppv) {
536         IUnknown_AddRef((IUnknown*)*ppv);
537         return S_OK;
538     }
539
540     return HTMLElement_QI(&This->element.node, riid, ppv);
541 }
542
543 static void HTMLTable_destructor(HTMLDOMNode *iface)
544 {
545     HTMLTable *This = HTMLTABLE_NODE_THIS(iface);
546
547     if(This->nstable)
548         nsIDOMHTMLTableElement_Release(This->nstable);
549
550     HTMLElement_destructor(&This->element.node);
551 }
552
553 #undef HTMLTABLE_NODE_THIS
554
555 static const NodeImplVtbl HTMLTableImplVtbl = {
556     HTMLTable_QI,
557     HTMLTable_destructor
558 };
559
560 static const tid_t HTMLTable_iface_tids[] = {
561     IHTMLDOMNode_tid,
562     IHTMLDOMNode2_tid,
563     IHTMLElement_tid,
564     IHTMLElement2_tid,
565     IHTMLElement3_tid,
566     IHTMLTable_tid,
567     0
568 };
569
570 static dispex_static_data_t HTMLTable_dispex = {
571     NULL,
572     DispHTMLTable_tid,
573     NULL,
574     HTMLTable_iface_tids
575 };
576
577 HTMLElement *HTMLTable_Create(HTMLDocumentNode *doc, nsIDOMHTMLElement *nselem)
578 {
579     HTMLTable *ret = heap_alloc_zero(sizeof(HTMLTable));
580     nsresult nsres;
581
582     ret->element.node.vtbl = &HTMLTableImplVtbl;
583     ret->lpHTMLTableVtbl = &HTMLTableVtbl;
584
585     HTMLElement_Init(&ret->element, doc, nselem, &HTMLTable_dispex);
586
587     ConnectionPoint_Init(&ret->cp, &ret->element.cp_container, &DIID_HTMLTableEvents, NULL);
588
589     nsres = nsIDOMHTMLElement_QueryInterface(nselem, &IID_nsIDOMHTMLTableElement, (void**)&ret->nstable);
590     if(NS_FAILED(nsres))
591         ERR("Could not get nsIDOMHTMLTableElement iface: %08x\n", nsres);
592
593     return &ret->element;
594 }