-
Notifications
You must be signed in to change notification settings - Fork 174
Expand file tree
/
Copy pathsidecar.h
More file actions
550 lines (413 loc) · 25.1 KB
/
sidecar.h
File metadata and controls
550 lines (413 loc) · 25.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/
// SPDX-License-Identifier: Apache-2.0
#ifndef DDOG_SIDECAR_H
#define DDOG_SIDECAR_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include "common.h"
#if defined(_WIN32)
bool ddog_setup_crashtracking(const struct ddog_Endpoint *endpoint, ddog_crasht_Metadata metadata);
#endif
/**
* This creates Rust PlatformHandle<File> from supplied C std FILE object.
* This method takes the ownership of the underlying file descriptor.
*
* # Safety
* Caller must ensure the file descriptor associated with FILE pointer is open, and valid
* Caller must not close the FILE associated file descriptor after calling this function
*/
struct ddog_NativeFile ddog_ph_file_from(FILE *file);
struct ddog_NativeFile *ddog_ph_file_clone(const struct ddog_NativeFile *platform_handle);
void ddog_ph_file_drop(struct ddog_NativeFile ph);
ddog_MaybeError ddog_alloc_anon_shm_handle(uintptr_t size, struct ddog_ShmHandle **handle);
ddog_MaybeError ddog_alloc_anon_shm_handle_named(uintptr_t size,
struct ddog_ShmHandle **handle,
ddog_CharSlice name);
ddog_MaybeError ddog_map_shm(struct ddog_ShmHandle *handle,
struct ddog_MappedMem_ShmHandle **mapped,
void **pointer,
uintptr_t *size);
struct ddog_ShmHandle *ddog_unmap_shm(struct ddog_MappedMem_ShmHandle *mapped);
void ddog_drop_anon_shm_handle(struct ddog_ShmHandle*);
ddog_MaybeError ddog_create_agent_remote_config_writer(struct ddog_AgentRemoteConfigWriter_ShmHandle **writer,
struct ddog_ShmHandle **handle);
struct ddog_AgentRemoteConfigReader *ddog_agent_remote_config_reader_for_endpoint(const struct ddog_Endpoint *endpoint);
ddog_MaybeError ddog_agent_remote_config_reader_for_anon_shm(const struct ddog_ShmHandle *handle,
struct ddog_AgentRemoteConfigReader **reader);
void ddog_agent_remote_config_write(const struct ddog_AgentRemoteConfigWriter_ShmHandle *writer,
ddog_CharSlice data);
bool ddog_agent_remote_config_read(struct ddog_AgentRemoteConfigReader *reader,
ddog_CharSlice *data);
void ddog_agent_remote_config_reader_drop(struct ddog_AgentRemoteConfigReader*);
void ddog_agent_remote_config_writer_drop(struct ddog_AgentRemoteConfigWriter_ShmHandle*);
struct ddog_RemoteConfigReader *ddog_remote_config_reader_for_endpoint(const ddog_CharSlice *language,
const ddog_CharSlice *tracer_version,
const struct ddog_Endpoint *endpoint,
ddog_CharSlice service_name,
ddog_CharSlice env_name,
ddog_CharSlice app_version,
const struct ddog_Vec_Tag *tags);
/**
* # Safety
* Argument should point to a valid C string.
*/
struct ddog_RemoteConfigReader *ddog_remote_config_reader_for_path(const char *path);
char *ddog_remote_config_path(const struct ddog_ConfigInvariants *id,
const struct ddog_Arc_Target *target);
void ddog_remote_config_path_free(char *path);
bool ddog_remote_config_read(struct ddog_RemoteConfigReader *reader, ddog_CharSlice *data);
void ddog_remote_config_reader_drop(struct ddog_RemoteConfigReader*);
void ddog_sidecar_transport_drop(struct ddog_SidecarTransport*);
/**
* # Safety
* Caller must ensure the process is safe to fork, at the time when this method is called
*/
ddog_MaybeError ddog_sidecar_connect(struct ddog_SidecarTransport **connection);
ddog_MaybeError ddog_sidecar_connect_master(int32_t pid);
ddog_MaybeError ddog_sidecar_connect_worker(int32_t pid, struct ddog_SidecarTransport **connection);
ddog_MaybeError ddog_sidecar_shutdown_master_listener(void);
bool ddog_sidecar_is_master_listener_active(int32_t pid);
ddog_MaybeError ddog_sidecar_clear_inherited_listener(void);
ddog_MaybeError ddog_sidecar_ping(struct ddog_SidecarTransport **transport);
ddog_MaybeError ddog_sidecar_flush(struct ddog_SidecarTransport **transport,
struct ddog_SidecarFlushOptions options);
struct ddog_InstanceId *ddog_sidecar_instanceId_build(ddog_CharSlice session_id,
ddog_CharSlice runtime_id);
void ddog_sidecar_instanceId_drop(struct ddog_InstanceId *instance_id);
ddog_QueueId ddog_sidecar_queueId_generate(void);
struct ddog_RuntimeMetadata *ddog_sidecar_runtimeMeta_build(ddog_CharSlice language_name,
ddog_CharSlice language_version,
ddog_CharSlice tracer_version);
void ddog_sidecar_runtimeMeta_drop(struct ddog_RuntimeMetadata *meta);
/**
* Reports the runtime configuration to the telemetry.
*/
ddog_MaybeError ddog_sidecar_telemetry_enqueueConfig(struct ddog_SidecarTransport **transport,
const struct ddog_InstanceId *instance_id,
const ddog_QueueId *queue_id,
ddog_CharSlice config_key,
ddog_CharSlice config_value,
enum ddog_ConfigurationOrigin origin,
ddog_CharSlice config_id,
struct ddog_Option_U64 seq_id);
/**
* Reports an endpoint to the telemetry.
*/
ddog_MaybeError ddog_sidecar_telemetry_addEndpoint(struct ddog_SidecarTransport **transport,
const struct ddog_InstanceId *instance_id,
const ddog_QueueId *queue_id,
enum ddog_Method method,
ddog_CharSlice path,
ddog_CharSlice operation_name,
ddog_CharSlice resource_name);
/**
* Reports a dependency to the telemetry.
*/
ddog_MaybeError ddog_sidecar_telemetry_addDependency(struct ddog_SidecarTransport **transport,
const struct ddog_InstanceId *instance_id,
const ddog_QueueId *queue_id,
ddog_CharSlice dependency_name,
ddog_CharSlice dependency_version);
/**
* Reports an integration to the telemetry.
*/
ddog_MaybeError ddog_sidecar_telemetry_addIntegration(struct ddog_SidecarTransport **transport,
const struct ddog_InstanceId *instance_id,
const ddog_QueueId *queue_id,
ddog_CharSlice integration_name,
ddog_CharSlice integration_version,
bool integration_enabled);
/**
* Enqueues a list of actions to be performed.
*/
ddog_MaybeError ddog_sidecar_lifecycle_end(struct ddog_SidecarTransport **transport,
const struct ddog_InstanceId *instance_id,
const ddog_QueueId *queue_id);
/**
* Enqueues a list of actions to be performed.
*/
ddog_MaybeError ddog_sidecar_application_remove(struct ddog_SidecarTransport **transport,
const struct ddog_InstanceId *instance_id,
const ddog_QueueId *queue_id);
/**
* Flushes the telemetry data.
*/
ddog_MaybeError ddog_sidecar_telemetry_flush(struct ddog_SidecarTransport **transport,
const struct ddog_InstanceId *instance_id,
const ddog_QueueId *queue_id);
/**
* Returns whether the sidecar transport is closed or not.
*/
bool ddog_sidecar_is_closed(struct ddog_SidecarTransport **transport);
/**
* Sets the configuration for a session.
*/
ddog_MaybeError ddog_sidecar_session_set_config(struct ddog_SidecarTransport **transport,
ddog_CharSlice session_id,
const struct ddog_Endpoint *agent_endpoint,
const struct ddog_Endpoint *dogstatsd_endpoint,
ddog_CharSlice language,
ddog_CharSlice language_version,
ddog_CharSlice tracer_version,
uint32_t flush_interval_milliseconds,
uint32_t remote_config_poll_interval_millis,
uint32_t telemetry_heartbeat_interval_millis,
uint64_t telemetry_extended_heartbeat_interval_millis,
uintptr_t force_flush_size,
uintptr_t force_drop_size,
ddog_CharSlice log_level,
ddog_CharSlice log_path,
void *_remote_config_notify_function,
const enum ddog_RemoteConfigProduct *remote_config_products,
uintptr_t remote_config_products_count,
const enum ddog_RemoteConfigCapabilities *remote_config_capabilities,
uintptr_t remote_config_capabilities_count,
bool remote_config_enabled,
bool is_fork,
const struct ddog_Vec_Tag *process_tags,
ddog_CharSlice hostname,
ddog_CharSlice root_service);
/**
* Updates the process_tags for an existing session.
*/
ddog_MaybeError ddog_sidecar_session_set_process_tags(struct ddog_SidecarTransport **transport,
const struct ddog_Vec_Tag *process_tags);
/**
* Enqueues a telemetry log action to be processed internally.
* Non-blocking. Logs might be dropped if the internal queue is full.
*
* # Safety
* Pointers must be valid, strings must be null-terminated if not null.
*/
ddog_MaybeError ddog_sidecar_enqueue_telemetry_log(ddog_CharSlice session_id_ffi,
ddog_CharSlice runtime_id_ffi,
ddog_CharSlice service_name_ffi,
ddog_CharSlice env_name_ffi,
ddog_CharSlice identifier_ffi,
enum ddog_LogLevel level,
ddog_CharSlice message_ffi,
ddog_CharSlice *stack_trace_ffi,
ddog_CharSlice *tags_ffi,
bool is_sensitive);
/**
* Enqueues a telemetry point to be processed internally.
*
* # Safety
* Pointers must be valid, strings must be null-terminated if not null.
*/
ddog_MaybeError ddog_sidecar_enqueue_telemetry_point(ddog_CharSlice session_id_ffi,
ddog_CharSlice runtime_id_ffi,
ddog_CharSlice service_name_ffi,
ddog_CharSlice env_name_ffi,
ddog_CharSlice metric_name_ffi,
double value,
ddog_CharSlice *tags_ffi);
/**
* Registers a telemetry metric to be processed internally.
*
* # Safety
* Pointers must be valid, strings must be null-terminated if not null.
*/
ddog_MaybeError ddog_sidecar_enqueue_telemetry_metric(ddog_CharSlice session_id_ffi,
ddog_CharSlice runtime_id_ffi,
ddog_CharSlice service_name_ffi,
ddog_CharSlice env_name_ffi,
ddog_CharSlice metric_name_ffi,
enum ddog_MetricType metric_type,
enum ddog_MetricNamespace metric_namespace);
/**
* Sends a trace to the sidecar via shared memory.
*/
ddog_MaybeError ddog_sidecar_send_trace_v04_shm(struct ddog_SidecarTransport **transport,
const struct ddog_InstanceId *instance_id,
struct ddog_ShmHandle *shm_handle,
uintptr_t len,
const struct ddog_TracerHeaderTags *tracer_header_tags);
/**
* Sends a trace as bytes to the sidecar.
*/
ddog_MaybeError ddog_sidecar_send_trace_v04_bytes(struct ddog_SidecarTransport **transport,
const struct ddog_InstanceId *instance_id,
ddog_CharSlice data,
const struct ddog_TracerHeaderTags *tracer_header_tags);
ddog_MaybeError ddog_sidecar_send_debugger_data(struct ddog_SidecarTransport **transport,
const struct ddog_InstanceId *instance_id,
ddog_QueueId queue_id,
struct ddog_Vec_DebuggerPayload payloads);
ddog_MaybeError ddog_sidecar_send_debugger_datum(struct ddog_SidecarTransport **transport,
const struct ddog_InstanceId *instance_id,
ddog_QueueId queue_id,
struct ddog_DebuggerPayload *payload);
ddog_MaybeError ddog_sidecar_send_debugger_diagnostics(struct ddog_SidecarTransport **transport,
const struct ddog_InstanceId *instance_id,
ddog_QueueId queue_id,
struct ddog_DebuggerPayload diagnostics_payload);
ddog_MaybeError ddog_sidecar_set_universal_service_tags(struct ddog_SidecarTransport **transport,
const struct ddog_InstanceId *instance_id,
const ddog_QueueId *queue_id,
ddog_CharSlice service_name,
ddog_CharSlice env_name,
ddog_CharSlice app_version,
const struct ddog_Vec_Tag *global_tags,
enum ddog_DynamicInstrumentationConfigState dynamic_instrumentation_state);
ddog_MaybeError ddog_sidecar_set_request_config(struct ddog_SidecarTransport **transport,
const struct ddog_InstanceId *instance_id,
const ddog_QueueId *queue_id,
enum ddog_DynamicInstrumentationConfigState dynamic_instrumentation_state);
/**
* Dumps the current state of the sidecar.
*/
ddog_CharSlice ddog_sidecar_dump(struct ddog_SidecarTransport **transport);
/**
* Retrieves the current statistics of the sidecar.
*/
ddog_CharSlice ddog_sidecar_stats(struct ddog_SidecarTransport **transport);
/**
* Send a DogStatsD "count" metric.
*/
ddog_MaybeError ddog_sidecar_dogstatsd_count(struct ddog_SidecarTransport **transport,
const struct ddog_InstanceId *instance_id,
ddog_CharSlice metric,
int64_t value,
const struct ddog_Vec_Tag *tags);
/**
* Send a DogStatsD "distribution" metric.
*/
ddog_MaybeError ddog_sidecar_dogstatsd_distribution(struct ddog_SidecarTransport **transport,
const struct ddog_InstanceId *instance_id,
ddog_CharSlice metric,
double value,
const struct ddog_Vec_Tag *tags);
/**
* Send a DogStatsD "gauge" metric.
*/
ddog_MaybeError ddog_sidecar_dogstatsd_gauge(struct ddog_SidecarTransport **transport,
const struct ddog_InstanceId *instance_id,
ddog_CharSlice metric,
double value,
const struct ddog_Vec_Tag *tags);
/**
* Send a DogStatsD "histogram" metric.
*/
ddog_MaybeError ddog_sidecar_dogstatsd_histogram(struct ddog_SidecarTransport **transport,
const struct ddog_InstanceId *instance_id,
ddog_CharSlice metric,
double value,
const struct ddog_Vec_Tag *tags);
/**
* Send a DogStatsD "set" metric.
*/
ddog_MaybeError ddog_sidecar_dogstatsd_set(struct ddog_SidecarTransport **transport,
const struct ddog_InstanceId *instance_id,
ddog_CharSlice metric,
int64_t value,
const struct ddog_Vec_Tag *tags);
/**
* Sets x-datadog-test-session-token on all requests for the given session.
*/
ddog_MaybeError ddog_sidecar_set_test_session_token(struct ddog_SidecarTransport **transport,
ddog_CharSlice token);
/**
* This function creates a new transport using the provided callback function when the current
* transport is closed.
*
* # Arguments
*
* * `transport` - The transport used for communication.
* * `factory` - A C function that must return a pointer to "ddog_SidecarTransport"
*/
void ddog_sidecar_reconnect(struct ddog_SidecarTransport **transport,
struct ddog_SidecarTransport *(*factory)(void));
/**
* Return the path of the crashtracker unix domain socket.
*/
ddog_CharSlice ddog_sidecar_get_crashtracker_unix_socket_path(void);
/**
* Gets an agent info reader.
*/
struct ddog_AgentInfoReader *ddog_get_agent_info_reader(const struct ddog_Endpoint *endpoint);
/**
* Gets the current agent info environment (or empty if not existing)
*/
ddog_CharSlice ddog_get_agent_info_env(struct ddog_AgentInfoReader *reader, bool *changed);
/**
* Gets the container tags hash from agent info (or empty if not existing)
*/
ddog_CharSlice ddog_get_agent_info_container_tags_hash(struct ddog_AgentInfoReader *reader,
bool *changed);
void ddog_send_traces_to_sidecar(ddog_TracesBytes *traces,
struct ddog_SenderParameters *parameters);
/**
* Drops the agent info reader.
*/
void ddog_drop_agent_info_reader(struct ddog_AgentInfoReader*);
void ddog_sidecar_send_garbage(struct ddog_SidecarTransport **transport);
ddog_TracesBytes *ddog_get_traces(void);
void ddog_free_traces(ddog_TracesBytes *_traces);
uintptr_t ddog_get_traces_size(const ddog_TracesBytes *traces);
ddog_TraceBytes *ddog_get_trace(ddog_TracesBytes *traces, uintptr_t index);
ddog_TraceBytes *ddog_traces_new_trace(ddog_TracesBytes *traces);
uintptr_t ddog_get_trace_size(const ddog_TraceBytes *trace);
ddog_SpanBytes *ddog_get_span(ddog_TraceBytes *trace, uintptr_t index);
ddog_SpanBytes *ddog_trace_new_span(ddog_TraceBytes *trace);
ddog_SpanBytes *ddog_trace_new_span_with_capacities(ddog_TraceBytes *trace,
uintptr_t meta_size,
uintptr_t metrics_size);
ddog_CharSlice ddog_span_debug_log(const ddog_SpanBytes *span);
void ddog_free_charslice(ddog_CharSlice slice);
void ddog_set_span_service(ddog_SpanBytes *span, ddog_CharSlice slice);
ddog_CharSlice ddog_get_span_service(ddog_SpanBytes *span);
void ddog_set_span_name(ddog_SpanBytes *span, ddog_CharSlice slice);
ddog_CharSlice ddog_get_span_name(ddog_SpanBytes *span);
void ddog_set_span_resource(ddog_SpanBytes *span, ddog_CharSlice slice);
ddog_CharSlice ddog_get_span_resource(ddog_SpanBytes *span);
void ddog_set_span_type(ddog_SpanBytes *span, ddog_CharSlice slice);
ddog_CharSlice ddog_get_span_type(ddog_SpanBytes *span);
void ddog_set_span_trace_id(ddog_SpanBytes *span, uint64_t value);
uint64_t ddog_get_span_trace_id(ddog_SpanBytes *span);
void ddog_set_span_id(ddog_SpanBytes *span, uint64_t value);
uint64_t ddog_get_span_id(ddog_SpanBytes *span);
void ddog_set_span_parent_id(ddog_SpanBytes *span, uint64_t value);
uint64_t ddog_get_span_parent_id(ddog_SpanBytes *span);
void ddog_set_span_start(ddog_SpanBytes *span, int64_t value);
int64_t ddog_get_span_start(ddog_SpanBytes *span);
void ddog_set_span_duration(ddog_SpanBytes *span, int64_t value);
int64_t ddog_get_span_duration(ddog_SpanBytes *span);
void ddog_set_span_error(ddog_SpanBytes *span, int32_t value);
int32_t ddog_get_span_error(ddog_SpanBytes *span);
void ddog_add_span_meta(ddog_SpanBytes *span, ddog_CharSlice key, ddog_CharSlice value);
void ddog_del_span_meta(ddog_SpanBytes *span, ddog_CharSlice key);
ddog_CharSlice ddog_get_span_meta(ddog_SpanBytes *span, ddog_CharSlice key);
bool ddog_has_span_meta(ddog_SpanBytes *span, ddog_CharSlice key);
ddog_CharSlice *ddog_span_meta_get_keys(ddog_SpanBytes *span, uintptr_t *out_count);
void ddog_add_span_metrics(ddog_SpanBytes *span, ddog_CharSlice key, double val);
void ddog_del_span_metrics(ddog_SpanBytes *span, ddog_CharSlice key);
bool ddog_get_span_metrics(ddog_SpanBytes *span, ddog_CharSlice key, double *result);
bool ddog_has_span_metrics(ddog_SpanBytes *span, ddog_CharSlice key);
ddog_CharSlice *ddog_span_metrics_get_keys(ddog_SpanBytes *span, uintptr_t *out_count);
void ddog_add_span_meta_struct(ddog_SpanBytes *span, ddog_CharSlice key, ddog_CharSlice val);
void ddog_del_span_meta_struct(ddog_SpanBytes *span, ddog_CharSlice key);
ddog_CharSlice ddog_get_span_meta_struct(ddog_SpanBytes *span, ddog_CharSlice key);
bool ddog_has_span_meta_struct(ddog_SpanBytes *span, ddog_CharSlice key);
ddog_CharSlice *ddog_span_meta_struct_get_keys(ddog_SpanBytes *span, uintptr_t *out_count);
void ddog_span_free_keys_ptr(ddog_CharSlice *keys_ptr, uintptr_t count);
ddog_SpanLinkBytes *ddog_span_new_link(ddog_SpanBytes *span);
void ddog_set_link_tracestate(ddog_SpanLinkBytes *link, ddog_CharSlice slice);
void ddog_set_link_trace_id(ddog_SpanLinkBytes *link, uint64_t value);
void ddog_set_link_trace_id_high(ddog_SpanLinkBytes *link, uint64_t value);
void ddog_set_link_span_id(ddog_SpanLinkBytes *link, uint64_t value);
void ddog_set_link_flags(ddog_SpanLinkBytes *link, uint32_t value);
void ddog_add_link_attributes(ddog_SpanLinkBytes *link, ddog_CharSlice key, ddog_CharSlice val);
ddog_SpanEventBytes *ddog_span_new_event(ddog_SpanBytes *span);
void ddog_set_event_name(ddog_SpanEventBytes *event, ddog_CharSlice slice);
void ddog_set_event_time(ddog_SpanEventBytes *event, uint64_t val);
void ddog_add_event_attributes_str(ddog_SpanEventBytes *event,
ddog_CharSlice key,
ddog_CharSlice val);
void ddog_add_event_attributes_bool(ddog_SpanEventBytes *event, ddog_CharSlice key, bool val);
void ddog_add_event_attributes_int(ddog_SpanEventBytes *event, ddog_CharSlice key, int64_t val);
void ddog_add_event_attributes_float(ddog_SpanEventBytes *event, ddog_CharSlice key, double val);
ddog_CharSlice ddog_serialize_trace_into_charslice(ddog_TraceBytes *trace);
#endif /* DDOG_SIDECAR_H */