Roll BoringSSL.
[chromium-blink-merge.git] / remoting / base / dispatch_win.h
blobccf56727533c7adc6b5fd97e02940b23383b35be
1 // This file was GENERATED by command:
2 // pump.py dispatch_win.h.pump
3 // DO NOT EDIT BY HAND!!!
5 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
6 // Use of this source code is governed by a BSD-style license that can be
7 // found in the LICENSE file.
9 #ifndef REMOTING_BASE_IDISPATCH_DRIVER_WIN_H_
10 #define REMOTING_BASE_IDISPATCH_DRIVER_WIN_H_
12 #include <oaidl.h>
14 #include "base/basictypes.h"
15 #include "base/template_util.h"
16 #include "base/win/scoped_variant.h"
18 namespace remoting {
20 namespace dispatch {
22 namespace internal {
24 // A helper wrapper for |VARIANTARG| that is used to pass parameters to and from
25 // IDispatch::Invoke(). The latter accepts parameters as an array of
26 // |VARIANTARG| structures. The calling convention of IDispatch::Invoke() is:
27 // - [in] parameters are initialized and freed if needed by the caller.
28 // - [out] parameters are initialized by IDispatch::Invoke(). It is up to
29 // the caller to free leakable variants (such as VT_DISPATCH).
30 // - [in] [out] parameters are combination of both: the caller initializes
31 // them before the call and the callee assigns new values correctly
32 // freeing leakable variants.
34 // Using |ScopedVariantArg| instead of naked |VARIANTARG| ensures that
35 // the resources allocated during the call will be properly freed. It also
36 // provides wrapping methods that convert between C++ types and VARIANTs.
37 // At the moment the only supported parameter type is |VARIANT| (or
38 // |VARIANTARG|).
40 // It must be possible to cast a pointer to an array of |ScopedVariantArg| to
41 // a pointer to an array of |VARIANTARG| structures.
42 class ScopedVariantArg : public VARIANTARG {
43 public:
44 ScopedVariantArg() {
45 vt = VT_EMPTY;
48 ~ScopedVariantArg() {
49 VariantClear(this);
52 // Wrap() routines pack the input parameters into VARIANTARG structures so
53 // that they can be passed to IDispatch::Invoke.
55 HRESULT Wrap(const VARIANT& param) {
56 DCHECK(vt == VT_EMPTY);
57 return VariantCopy(this, &param);
60 HRESULT Wrap(VARIANT* const & param) {
61 DCHECK(vt == VT_EMPTY);
63 // Make the input value of an [in] [out] parameter visible to
64 // IDispatch::Invoke().
66 // N.B. We treat both [out] and [in] [out] parameters as [in] [out]. In
67 // other words the caller is always responsible for initializing and freeing
68 // [out] and [in] [out] parameters.
69 Swap(param);
70 return S_OK;
73 // Unwrap() routines unpack the output parameters from VARIANTARG structures
74 // to the locations specified by the caller.
76 void Unwrap(const VARIANT& param_out) {
77 // Do nothing for an [in] parameter.
80 void Unwrap(VARIANT* const & param_out) {
81 // Return the output value of an [in] [out] parameter to the caller.
82 Swap(param_out);
85 private:
86 // Exchanges the value (and ownership) of the passed VARIANT with the one
87 // wrapped by |ScopedVariantArg|.
88 void Swap(VARIANT* other) {
89 VARIANT temp = *other;
90 *other = *this;
91 *static_cast<VARIANTARG*>(this) = temp;
94 DISALLOW_COPY_AND_ASSIGN(ScopedVariantArg);
97 // Make sure the layouts of |VARIANTARG| and |ScopedVariantArg| are identical.
98 COMPILE_ASSERT(sizeof(ScopedVariantArg) == sizeof(VARIANTARG),
99 scoped_variant_arg_should_not_add_data_members);
101 } // namespace internal
103 // Invoke() is a convenience wrapper for IDispatch::Invoke. It takes care of
104 // calling the desired method by its ID and implements logic for passing
105 // a variable number of in/out parameters to the called method.
107 // The calling convention is:
108 // - [in] parameters are passsed as a constant reference or by value.
109 // - [out] and [in] [out] parameters are passed by pointer. The pointed value
110 // is overwritten when the function returns. The pointed-to value must
111 // be initialized before the call, and will be replaced when it returns.
112 // [out] parameters may be initialized to VT_EMPTY.
114 // Current limitations:
115 // - more than 7 parameters are not supported.
116 // - the method ID cannot be cached and reused.
117 // - VARIANT is the only supported parameter type at the moment.
119 HRESULT Invoke(IDispatch* object,
120 LPCOLESTR const_name,
121 WORD flags,
122 VARIANT* const & result_out) {
123 // Retrieve the ID of the method to be called.
124 DISPID disp_id;
125 LPOLESTR name = const_cast<LPOLESTR>(const_name);
126 HRESULT hr = object->GetIDsOfNames(
127 IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &disp_id);
128 if (FAILED(hr))
129 return hr;
131 // Request the return value if asked by the caller.
132 internal::ScopedVariantArg result;
133 VARIANT* disp_result = NULL;
134 if (result_out != NULL)
135 disp_result = &result;
138 // Invoke the method passing the parameters via the DISPPARAMS structure.
139 // DISPATCH_PROPERTYPUT and DISPATCH_PROPERTYPUTREF require the parameter of
140 // the property setter to be named, so |cNamedArgs| and |rgdispidNamedArgs|
141 // structure members should be initialized.
142 DISPPARAMS disp_params = { NULL, NULL, 0, 0 };
143 DISPID dispid_named = DISPID_PROPERTYPUT;
144 if (flags == DISPATCH_PROPERTYPUT || flags == DISPATCH_PROPERTYPUTREF) {
145 disp_params.cNamedArgs = 1;
146 disp_params.rgdispidNamedArgs = &dispid_named;
149 hr = object->Invoke(disp_id, IID_NULL, LOCALE_USER_DEFAULT, flags,
150 &disp_params, disp_result, NULL, NULL);
151 if (FAILED(hr))
152 return hr;
155 // Unwrap the return value.
156 if (result_out != NULL) {
157 result.Unwrap(result_out);
160 return S_OK;
163 template <typename P1>
164 HRESULT Invoke(IDispatch* object,
165 LPCOLESTR const_name,
166 WORD flags,
167 const P1& p1,
168 VARIANT* const & result_out) {
169 // Retrieve the ID of the method to be called.
170 DISPID disp_id;
171 LPOLESTR name = const_cast<LPOLESTR>(const_name);
172 HRESULT hr = object->GetIDsOfNames(
173 IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &disp_id);
174 if (FAILED(hr))
175 return hr;
177 // Request the return value if asked by the caller.
178 internal::ScopedVariantArg result;
179 VARIANT* disp_result = NULL;
180 if (result_out != NULL)
181 disp_result = &result;
183 // Wrap the parameters into an array of VARIANT structures.
184 internal::ScopedVariantArg disp_args[1];
185 hr = disp_args[1 - 1].Wrap(p1);
186 if (FAILED(hr))
187 return hr;
189 // Invoke the method passing the parameters via the DISPPARAMS structure.
190 // DISPATCH_PROPERTYPUT and DISPATCH_PROPERTYPUTREF require the parameter of
191 // the property setter to be named, so |cNamedArgs| and |rgdispidNamedArgs|
192 // structure members should be initialized.
193 DISPPARAMS disp_params = { disp_args, NULL, 1, 0 };
194 DISPID dispid_named = DISPID_PROPERTYPUT;
195 if (flags == DISPATCH_PROPERTYPUT || flags == DISPATCH_PROPERTYPUTREF) {
196 disp_params.cNamedArgs = 1;
197 disp_params.rgdispidNamedArgs = &dispid_named;
200 hr = object->Invoke(disp_id, IID_NULL, LOCALE_USER_DEFAULT, flags,
201 &disp_params, disp_result, NULL, NULL);
202 if (FAILED(hr))
203 return hr;
205 // Unwrap the parameters.
206 disp_args[1 - 1].Unwrap(p1);
208 // Unwrap the return value.
209 if (result_out != NULL) {
210 result.Unwrap(result_out);
213 return S_OK;
216 template <typename P1, typename P2>
217 HRESULT Invoke(IDispatch* object,
218 LPCOLESTR const_name,
219 WORD flags,
220 const P1& p1,
221 const P2& p2,
222 VARIANT* const & result_out) {
223 // Retrieve the ID of the method to be called.
224 DISPID disp_id;
225 LPOLESTR name = const_cast<LPOLESTR>(const_name);
226 HRESULT hr = object->GetIDsOfNames(
227 IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &disp_id);
228 if (FAILED(hr))
229 return hr;
231 // Request the return value if asked by the caller.
232 internal::ScopedVariantArg result;
233 VARIANT* disp_result = NULL;
234 if (result_out != NULL)
235 disp_result = &result;
237 // Wrap the parameters into an array of VARIANT structures.
238 internal::ScopedVariantArg disp_args[2];
239 hr = disp_args[2 - 1].Wrap(p1);
240 if (FAILED(hr))
241 return hr;
242 hr = disp_args[2 - 2].Wrap(p2);
243 if (FAILED(hr))
244 return hr;
246 // Invoke the method passing the parameters via the DISPPARAMS structure.
247 // DISPATCH_PROPERTYPUT and DISPATCH_PROPERTYPUTREF require the parameter of
248 // the property setter to be named, so |cNamedArgs| and |rgdispidNamedArgs|
249 // structure members should be initialized.
250 DISPPARAMS disp_params = { disp_args, NULL, 2, 0 };
251 DISPID dispid_named = DISPID_PROPERTYPUT;
252 if (flags == DISPATCH_PROPERTYPUT || flags == DISPATCH_PROPERTYPUTREF) {
253 disp_params.cNamedArgs = 1;
254 disp_params.rgdispidNamedArgs = &dispid_named;
257 hr = object->Invoke(disp_id, IID_NULL, LOCALE_USER_DEFAULT, flags,
258 &disp_params, disp_result, NULL, NULL);
259 if (FAILED(hr))
260 return hr;
262 // Unwrap the parameters.
263 disp_args[2 - 1].Unwrap(p1);
264 disp_args[2 - 2].Unwrap(p2);
266 // Unwrap the return value.
267 if (result_out != NULL) {
268 result.Unwrap(result_out);
271 return S_OK;
274 template <typename P1, typename P2, typename P3>
275 HRESULT Invoke(IDispatch* object,
276 LPCOLESTR const_name,
277 WORD flags,
278 const P1& p1,
279 const P2& p2,
280 const P3& p3,
281 VARIANT* const & result_out) {
282 // Retrieve the ID of the method to be called.
283 DISPID disp_id;
284 LPOLESTR name = const_cast<LPOLESTR>(const_name);
285 HRESULT hr = object->GetIDsOfNames(
286 IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &disp_id);
287 if (FAILED(hr))
288 return hr;
290 // Request the return value if asked by the caller.
291 internal::ScopedVariantArg result;
292 VARIANT* disp_result = NULL;
293 if (result_out != NULL)
294 disp_result = &result;
296 // Wrap the parameters into an array of VARIANT structures.
297 internal::ScopedVariantArg disp_args[3];
298 hr = disp_args[3 - 1].Wrap(p1);
299 if (FAILED(hr))
300 return hr;
301 hr = disp_args[3 - 2].Wrap(p2);
302 if (FAILED(hr))
303 return hr;
304 hr = disp_args[3 - 3].Wrap(p3);
305 if (FAILED(hr))
306 return hr;
308 // Invoke the method passing the parameters via the DISPPARAMS structure.
309 // DISPATCH_PROPERTYPUT and DISPATCH_PROPERTYPUTREF require the parameter of
310 // the property setter to be named, so |cNamedArgs| and |rgdispidNamedArgs|
311 // structure members should be initialized.
312 DISPPARAMS disp_params = { disp_args, NULL, 3, 0 };
313 DISPID dispid_named = DISPID_PROPERTYPUT;
314 if (flags == DISPATCH_PROPERTYPUT || flags == DISPATCH_PROPERTYPUTREF) {
315 disp_params.cNamedArgs = 1;
316 disp_params.rgdispidNamedArgs = &dispid_named;
319 hr = object->Invoke(disp_id, IID_NULL, LOCALE_USER_DEFAULT, flags,
320 &disp_params, disp_result, NULL, NULL);
321 if (FAILED(hr))
322 return hr;
324 // Unwrap the parameters.
325 disp_args[3 - 1].Unwrap(p1);
326 disp_args[3 - 2].Unwrap(p2);
327 disp_args[3 - 3].Unwrap(p3);
329 // Unwrap the return value.
330 if (result_out != NULL) {
331 result.Unwrap(result_out);
334 return S_OK;
337 template <typename P1, typename P2, typename P3, typename P4>
338 HRESULT Invoke(IDispatch* object,
339 LPCOLESTR const_name,
340 WORD flags,
341 const P1& p1,
342 const P2& p2,
343 const P3& p3,
344 const P4& p4,
345 VARIANT* const & result_out) {
346 // Retrieve the ID of the method to be called.
347 DISPID disp_id;
348 LPOLESTR name = const_cast<LPOLESTR>(const_name);
349 HRESULT hr = object->GetIDsOfNames(
350 IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &disp_id);
351 if (FAILED(hr))
352 return hr;
354 // Request the return value if asked by the caller.
355 internal::ScopedVariantArg result;
356 VARIANT* disp_result = NULL;
357 if (result_out != NULL)
358 disp_result = &result;
360 // Wrap the parameters into an array of VARIANT structures.
361 internal::ScopedVariantArg disp_args[4];
362 hr = disp_args[4 - 1].Wrap(p1);
363 if (FAILED(hr))
364 return hr;
365 hr = disp_args[4 - 2].Wrap(p2);
366 if (FAILED(hr))
367 return hr;
368 hr = disp_args[4 - 3].Wrap(p3);
369 if (FAILED(hr))
370 return hr;
371 hr = disp_args[4 - 4].Wrap(p4);
372 if (FAILED(hr))
373 return hr;
375 // Invoke the method passing the parameters via the DISPPARAMS structure.
376 // DISPATCH_PROPERTYPUT and DISPATCH_PROPERTYPUTREF require the parameter of
377 // the property setter to be named, so |cNamedArgs| and |rgdispidNamedArgs|
378 // structure members should be initialized.
379 DISPPARAMS disp_params = { disp_args, NULL, 4, 0 };
380 DISPID dispid_named = DISPID_PROPERTYPUT;
381 if (flags == DISPATCH_PROPERTYPUT || flags == DISPATCH_PROPERTYPUTREF) {
382 disp_params.cNamedArgs = 1;
383 disp_params.rgdispidNamedArgs = &dispid_named;
386 hr = object->Invoke(disp_id, IID_NULL, LOCALE_USER_DEFAULT, flags,
387 &disp_params, disp_result, NULL, NULL);
388 if (FAILED(hr))
389 return hr;
391 // Unwrap the parameters.
392 disp_args[4 - 1].Unwrap(p1);
393 disp_args[4 - 2].Unwrap(p2);
394 disp_args[4 - 3].Unwrap(p3);
395 disp_args[4 - 4].Unwrap(p4);
397 // Unwrap the return value.
398 if (result_out != NULL) {
399 result.Unwrap(result_out);
402 return S_OK;
405 template <typename P1, typename P2, typename P3, typename P4, typename P5>
406 HRESULT Invoke(IDispatch* object,
407 LPCOLESTR const_name,
408 WORD flags,
409 const P1& p1,
410 const P2& p2,
411 const P3& p3,
412 const P4& p4,
413 const P5& p5,
414 VARIANT* const & result_out) {
415 // Retrieve the ID of the method to be called.
416 DISPID disp_id;
417 LPOLESTR name = const_cast<LPOLESTR>(const_name);
418 HRESULT hr = object->GetIDsOfNames(
419 IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &disp_id);
420 if (FAILED(hr))
421 return hr;
423 // Request the return value if asked by the caller.
424 internal::ScopedVariantArg result;
425 VARIANT* disp_result = NULL;
426 if (result_out != NULL)
427 disp_result = &result;
429 // Wrap the parameters into an array of VARIANT structures.
430 internal::ScopedVariantArg disp_args[5];
431 hr = disp_args[5 - 1].Wrap(p1);
432 if (FAILED(hr))
433 return hr;
434 hr = disp_args[5 - 2].Wrap(p2);
435 if (FAILED(hr))
436 return hr;
437 hr = disp_args[5 - 3].Wrap(p3);
438 if (FAILED(hr))
439 return hr;
440 hr = disp_args[5 - 4].Wrap(p4);
441 if (FAILED(hr))
442 return hr;
443 hr = disp_args[5 - 5].Wrap(p5);
444 if (FAILED(hr))
445 return hr;
447 // Invoke the method passing the parameters via the DISPPARAMS structure.
448 // DISPATCH_PROPERTYPUT and DISPATCH_PROPERTYPUTREF require the parameter of
449 // the property setter to be named, so |cNamedArgs| and |rgdispidNamedArgs|
450 // structure members should be initialized.
451 DISPPARAMS disp_params = { disp_args, NULL, 5, 0 };
452 DISPID dispid_named = DISPID_PROPERTYPUT;
453 if (flags == DISPATCH_PROPERTYPUT || flags == DISPATCH_PROPERTYPUTREF) {
454 disp_params.cNamedArgs = 1;
455 disp_params.rgdispidNamedArgs = &dispid_named;
458 hr = object->Invoke(disp_id, IID_NULL, LOCALE_USER_DEFAULT, flags,
459 &disp_params, disp_result, NULL, NULL);
460 if (FAILED(hr))
461 return hr;
463 // Unwrap the parameters.
464 disp_args[5 - 1].Unwrap(p1);
465 disp_args[5 - 2].Unwrap(p2);
466 disp_args[5 - 3].Unwrap(p3);
467 disp_args[5 - 4].Unwrap(p4);
468 disp_args[5 - 5].Unwrap(p5);
470 // Unwrap the return value.
471 if (result_out != NULL) {
472 result.Unwrap(result_out);
475 return S_OK;
478 template <typename P1, typename P2, typename P3, typename P4, typename P5,
479 typename P6>
480 HRESULT Invoke(IDispatch* object,
481 LPCOLESTR const_name,
482 WORD flags,
483 const P1& p1,
484 const P2& p2,
485 const P3& p3,
486 const P4& p4,
487 const P5& p5,
488 const P6& p6,
489 VARIANT* const & result_out) {
490 // Retrieve the ID of the method to be called.
491 DISPID disp_id;
492 LPOLESTR name = const_cast<LPOLESTR>(const_name);
493 HRESULT hr = object->GetIDsOfNames(
494 IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &disp_id);
495 if (FAILED(hr))
496 return hr;
498 // Request the return value if asked by the caller.
499 internal::ScopedVariantArg result;
500 VARIANT* disp_result = NULL;
501 if (result_out != NULL)
502 disp_result = &result;
504 // Wrap the parameters into an array of VARIANT structures.
505 internal::ScopedVariantArg disp_args[6];
506 hr = disp_args[6 - 1].Wrap(p1);
507 if (FAILED(hr))
508 return hr;
509 hr = disp_args[6 - 2].Wrap(p2);
510 if (FAILED(hr))
511 return hr;
512 hr = disp_args[6 - 3].Wrap(p3);
513 if (FAILED(hr))
514 return hr;
515 hr = disp_args[6 - 4].Wrap(p4);
516 if (FAILED(hr))
517 return hr;
518 hr = disp_args[6 - 5].Wrap(p5);
519 if (FAILED(hr))
520 return hr;
521 hr = disp_args[6 - 6].Wrap(p6);
522 if (FAILED(hr))
523 return hr;
525 // Invoke the method passing the parameters via the DISPPARAMS structure.
526 // DISPATCH_PROPERTYPUT and DISPATCH_PROPERTYPUTREF require the parameter of
527 // the property setter to be named, so |cNamedArgs| and |rgdispidNamedArgs|
528 // structure members should be initialized.
529 DISPPARAMS disp_params = { disp_args, NULL, 6, 0 };
530 DISPID dispid_named = DISPID_PROPERTYPUT;
531 if (flags == DISPATCH_PROPERTYPUT || flags == DISPATCH_PROPERTYPUTREF) {
532 disp_params.cNamedArgs = 1;
533 disp_params.rgdispidNamedArgs = &dispid_named;
536 hr = object->Invoke(disp_id, IID_NULL, LOCALE_USER_DEFAULT, flags,
537 &disp_params, disp_result, NULL, NULL);
538 if (FAILED(hr))
539 return hr;
541 // Unwrap the parameters.
542 disp_args[6 - 1].Unwrap(p1);
543 disp_args[6 - 2].Unwrap(p2);
544 disp_args[6 - 3].Unwrap(p3);
545 disp_args[6 - 4].Unwrap(p4);
546 disp_args[6 - 5].Unwrap(p5);
547 disp_args[6 - 6].Unwrap(p6);
549 // Unwrap the return value.
550 if (result_out != NULL) {
551 result.Unwrap(result_out);
554 return S_OK;
557 template <typename P1, typename P2, typename P3, typename P4, typename P5,
558 typename P6, typename P7>
559 HRESULT Invoke(IDispatch* object,
560 LPCOLESTR const_name,
561 WORD flags,
562 const P1& p1,
563 const P2& p2,
564 const P3& p3,
565 const P4& p4,
566 const P5& p5,
567 const P6& p6,
568 const P7& p7,
569 VARIANT* const & result_out) {
570 // Retrieve the ID of the method to be called.
571 DISPID disp_id;
572 LPOLESTR name = const_cast<LPOLESTR>(const_name);
573 HRESULT hr = object->GetIDsOfNames(
574 IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &disp_id);
575 if (FAILED(hr))
576 return hr;
578 // Request the return value if asked by the caller.
579 internal::ScopedVariantArg result;
580 VARIANT* disp_result = NULL;
581 if (result_out != NULL)
582 disp_result = &result;
584 // Wrap the parameters into an array of VARIANT structures.
585 internal::ScopedVariantArg disp_args[7];
586 hr = disp_args[7 - 1].Wrap(p1);
587 if (FAILED(hr))
588 return hr;
589 hr = disp_args[7 - 2].Wrap(p2);
590 if (FAILED(hr))
591 return hr;
592 hr = disp_args[7 - 3].Wrap(p3);
593 if (FAILED(hr))
594 return hr;
595 hr = disp_args[7 - 4].Wrap(p4);
596 if (FAILED(hr))
597 return hr;
598 hr = disp_args[7 - 5].Wrap(p5);
599 if (FAILED(hr))
600 return hr;
601 hr = disp_args[7 - 6].Wrap(p6);
602 if (FAILED(hr))
603 return hr;
604 hr = disp_args[7 - 7].Wrap(p7);
605 if (FAILED(hr))
606 return hr;
608 // Invoke the method passing the parameters via the DISPPARAMS structure.
609 // DISPATCH_PROPERTYPUT and DISPATCH_PROPERTYPUTREF require the parameter of
610 // the property setter to be named, so |cNamedArgs| and |rgdispidNamedArgs|
611 // structure members should be initialized.
612 DISPPARAMS disp_params = { disp_args, NULL, 7, 0 };
613 DISPID dispid_named = DISPID_PROPERTYPUT;
614 if (flags == DISPATCH_PROPERTYPUT || flags == DISPATCH_PROPERTYPUTREF) {
615 disp_params.cNamedArgs = 1;
616 disp_params.rgdispidNamedArgs = &dispid_named;
619 hr = object->Invoke(disp_id, IID_NULL, LOCALE_USER_DEFAULT, flags,
620 &disp_params, disp_result, NULL, NULL);
621 if (FAILED(hr))
622 return hr;
624 // Unwrap the parameters.
625 disp_args[7 - 1].Unwrap(p1);
626 disp_args[7 - 2].Unwrap(p2);
627 disp_args[7 - 3].Unwrap(p3);
628 disp_args[7 - 4].Unwrap(p4);
629 disp_args[7 - 5].Unwrap(p5);
630 disp_args[7 - 6].Unwrap(p6);
631 disp_args[7 - 7].Unwrap(p7);
633 // Unwrap the return value.
634 if (result_out != NULL) {
635 result.Unwrap(result_out);
638 return S_OK;
641 } // namespace dispatch
643 } // namespace remoting
645 #endif // REMOTING_BASE_IDISPATCH_DRIVER_WIN_H_