Mercurial > pidgin.yaz
comparison libgaim/plugin.h @ 14192:60b1bc8dbf37
[gaim-migrate @ 16863]
Renamed 'core' to 'libgaim'
committer: Tailor Script <tailor@pidgin.im>
author | Evan Schoenberg <evan.s@dreskin.net> |
---|---|
date | Sat, 19 Aug 2006 01:50:10 +0000 |
parents | |
children | 7d6bd7a4994f |
comparison
equal
deleted
inserted
replaced
14191:009db0b357b5 | 14192:60b1bc8dbf37 |
---|---|
1 /** | |
2 * @file plugin.h Plugin API | |
3 * @ingroup core | |
4 * | |
5 * gaim | |
6 * | |
7 * Gaim is the legal property of its developers, whose names are too numerous | |
8 * to list here. Please refer to the COPYRIGHT file distributed with this | |
9 * source distribution. | |
10 * | |
11 * This program is free software; you can redistribute it and/or modify | |
12 * it under the terms of the GNU General Public License as published by | |
13 * the Free Software Foundation; either version 2 of the License, or | |
14 * (at your option) any later version. | |
15 * | |
16 * This program is distributed in the hope that it will be useful, | |
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 * GNU General Public License for more details. | |
20 * | |
21 * You should have received a copy of the GNU General Public License | |
22 * along with this program; if not, write to the Free Software | |
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
24 */ | |
25 #ifndef _GAIM_PLUGIN_H_ | |
26 #define _GAIM_PLUGIN_H_ | |
27 | |
28 #include <glib/glist.h> | |
29 #include <gmodule.h> | |
30 #include "signals.h" | |
31 #include "value.h" | |
32 | |
33 typedef struct _GaimPlugin GaimPlugin; | |
34 typedef struct _GaimPluginInfo GaimPluginInfo; | |
35 typedef struct _GaimPluginUiInfo GaimPluginUiInfo; | |
36 typedef struct _GaimPluginLoaderInfo GaimPluginLoaderInfo; | |
37 | |
38 typedef struct _GaimPluginAction GaimPluginAction; | |
39 | |
40 typedef int GaimPluginPriority; /**< Plugin priority. */ | |
41 | |
42 #include "pluginpref.h" | |
43 | |
44 /** | |
45 * Plugin types. | |
46 */ | |
47 typedef enum | |
48 { | |
49 GAIM_PLUGIN_UNKNOWN = -1, /**< Unknown type. */ | |
50 GAIM_PLUGIN_STANDARD = 0, /**< Standard plugin. */ | |
51 GAIM_PLUGIN_LOADER, /**< Loader plugin. */ | |
52 GAIM_PLUGIN_PROTOCOL /**< Protocol plugin. */ | |
53 | |
54 } GaimPluginType; | |
55 | |
56 #define GAIM_PRIORITY_DEFAULT 0 | |
57 #define GAIM_PRIORITY_HIGHEST 9999 | |
58 #define GAIM_PRIORITY_LOWEST -9999 | |
59 | |
60 #define GAIM_PLUGIN_FLAG_INVISIBLE 0x01 | |
61 | |
62 #define GAIM_PLUGIN_MAGIC 5 /* once we hit 6.0.0 I think we can remove this */ | |
63 | |
64 /** | |
65 * Detailed information about a plugin. | |
66 * | |
67 * This is used in the version 2.0 API and up. | |
68 */ | |
69 /* TODO We need to figure out exactly what parts of this are required. The | |
70 * dependent plugin unloading stuff was causing crashes with perl and tcl | |
71 * plugins because they didn't set ids and the dependency code was requiring | |
72 * them. Then we need to actually make sure that plugins have all the right | |
73 * parts before loading them. */ | |
74 struct _GaimPluginInfo | |
75 { | |
76 unsigned int magic; | |
77 unsigned int major_version; | |
78 unsigned int minor_version; | |
79 GaimPluginType type; | |
80 char *ui_requirement; | |
81 unsigned long flags; | |
82 GList *dependencies; | |
83 GaimPluginPriority priority; | |
84 | |
85 char *id; | |
86 char *name; | |
87 char *version; | |
88 char *summary; | |
89 char *description; | |
90 char *author; | |
91 char *homepage; | |
92 | |
93 /** | |
94 * If a plugin defines a 'load' function, and it returns FALSE, | |
95 * then the plugin will not be loaded. | |
96 */ | |
97 gboolean (*load)(GaimPlugin *plugin); | |
98 gboolean (*unload)(GaimPlugin *plugin); | |
99 void (*destroy)(GaimPlugin *plugin); | |
100 | |
101 void *ui_info; /**< Used only by UI-specific plugins to build a preference screen with a custom UI */ | |
102 void *extra_info; | |
103 GaimPluginUiInfo *prefs_info; /**< Used by any plugin to display preferences. If #ui_info has been specified, this will be ignored. */ | |
104 GList *(*actions)(GaimPlugin *plugin, gpointer context); | |
105 }; | |
106 | |
107 /** | |
108 * Extra information for loader plugins. | |
109 */ | |
110 struct _GaimPluginLoaderInfo | |
111 { | |
112 GList *exts; | |
113 | |
114 gboolean (*probe)(GaimPlugin *plugin); | |
115 gboolean (*load)(GaimPlugin *plugin); | |
116 gboolean (*unload)(GaimPlugin *plugin); | |
117 void (*destroy)(GaimPlugin *plugin); | |
118 }; | |
119 | |
120 /** | |
121 * A plugin handle. | |
122 */ | |
123 struct _GaimPlugin | |
124 { | |
125 gboolean native_plugin; /**< Native C plugin. */ | |
126 gboolean loaded; /**< The loaded state. */ | |
127 void *handle; /**< The module handle. */ | |
128 char *path; /**< The path to the plugin. */ | |
129 GaimPluginInfo *info; /**< The plugin information. */ | |
130 char *error; | |
131 void *ipc_data; /**< IPC data. */ | |
132 void *extra; /**< Plugin-specific data. */ | |
133 gboolean unloadable; /**< Unloadable */ | |
134 GList *dependent_plugins; /**< Plugins depending on this */ | |
135 }; | |
136 | |
137 #define GAIM_PLUGIN_LOADER_INFO(plugin) \ | |
138 ((GaimPluginLoaderInfo *)(plugin)->info->extra_info) | |
139 | |
140 struct _GaimPluginUiInfo { | |
141 GaimPluginPrefFrame *(*get_plugin_pref_frame)(GaimPlugin *plugin); | |
142 | |
143 int page_num; /**< Reserved */ | |
144 GaimPluginPrefFrame *frame; /**< Reserved */ | |
145 }; | |
146 | |
147 #define GAIM_PLUGIN_HAS_PREF_FRAME(plugin) \ | |
148 ((plugin)->info != NULL && (plugin)->info->prefs_info != NULL) | |
149 | |
150 #define GAIM_PLUGIN_UI_INFO(plugin) \ | |
151 ((GaimPluginUiInfo*)(plugin)->info->prefs_info) | |
152 | |
153 | |
154 /** | |
155 * The structure used in the actions member of GaimPluginInfo | |
156 */ | |
157 struct _GaimPluginAction { | |
158 char *label; | |
159 void (*callback)(GaimPluginAction *); | |
160 | |
161 /** set to the owning plugin */ | |
162 GaimPlugin *plugin; | |
163 | |
164 /** NULL for plugin actions menu, set to the GaimConnection for | |
165 account actions menu */ | |
166 gpointer context; | |
167 }; | |
168 | |
169 #define GAIM_PLUGIN_HAS_ACTIONS(plugin) \ | |
170 ((plugin)->info != NULL && (plugin)->info->actions != NULL) | |
171 | |
172 #define GAIM_PLUGIN_ACTIONS(plugin, context) \ | |
173 (GAIM_PLUGIN_HAS_ACTIONS(plugin)? \ | |
174 (plugin)->info->actions(plugin, context): NULL) | |
175 | |
176 | |
177 /** | |
178 * Handles the initialization of modules. | |
179 */ | |
180 #if !defined(GAIM_PLUGINS) || defined(GAIM_STATIC_PRPL) | |
181 # define GAIM_INIT_PLUGIN(pluginname, initfunc, plugininfo) \ | |
182 gboolean gaim_init_##pluginname##_plugin(void);\ | |
183 gboolean gaim_init_##pluginname##_plugin(void) { \ | |
184 GaimPlugin *plugin = gaim_plugin_new(TRUE, NULL); \ | |
185 plugin->info = &(plugininfo); \ | |
186 initfunc((plugin)); \ | |
187 gaim_plugin_load((plugin)); \ | |
188 return gaim_plugin_register(plugin); \ | |
189 } | |
190 #else /* GAIM_PLUGINS && !GAIM_STATIC_PRPL */ | |
191 # define GAIM_INIT_PLUGIN(pluginname, initfunc, plugininfo) \ | |
192 G_MODULE_EXPORT gboolean gaim_init_plugin(GaimPlugin *plugin); \ | |
193 G_MODULE_EXPORT gboolean gaim_init_plugin(GaimPlugin *plugin) { \ | |
194 plugin->info = &(plugininfo); \ | |
195 initfunc((plugin)); \ | |
196 return gaim_plugin_register(plugin); \ | |
197 } | |
198 #endif | |
199 | |
200 | |
201 #ifdef __cplusplus | |
202 extern "C" { | |
203 #endif | |
204 | |
205 /**************************************************************************/ | |
206 /** @name Plugin API */ | |
207 /**************************************************************************/ | |
208 /*@{*/ | |
209 | |
210 /** | |
211 * Creates a new plugin structure. | |
212 * | |
213 * @param native Whether or not the plugin is native. | |
214 * @param path The path to the plugin, or @c NULL if statically compiled. | |
215 * | |
216 * @return A new GaimPlugin structure. | |
217 */ | |
218 GaimPlugin *gaim_plugin_new(gboolean native, const char *path); | |
219 | |
220 /** | |
221 * Probes a plugin, retrieving the information on it and adding it to the | |
222 * list of available plugins. | |
223 * | |
224 * @param filename The plugin's filename. | |
225 * | |
226 * @return The plugin handle. | |
227 * | |
228 * @see gaim_plugin_load() | |
229 * @see gaim_plugin_destroy() | |
230 */ | |
231 GaimPlugin *gaim_plugin_probe(const char *filename); | |
232 | |
233 /** | |
234 * Registers a plugin and prepares it for loading. | |
235 * | |
236 * This shouldn't be called by anything but the internal module code. | |
237 * Plugins should use the GAIM_INIT_PLUGIN() macro to register themselves | |
238 * with the core. | |
239 * | |
240 * @param plugin The plugin to register. | |
241 * | |
242 * @return @c TRUE if the plugin was registered successfully. Otherwise | |
243 * @c FALSE is returned (this happens if the plugin does not contain | |
244 * the necessary information). | |
245 */ | |
246 gboolean gaim_plugin_register(GaimPlugin *plugin); | |
247 | |
248 /** | |
249 * Attempts to load a previously probed plugin. | |
250 * | |
251 * @param plugin The plugin to load. | |
252 * | |
253 * @return @c TRUE if successful, or @c FALSE otherwise. | |
254 * | |
255 * @see gaim_plugin_reload() | |
256 * @see gaim_plugin_unload() | |
257 */ | |
258 gboolean gaim_plugin_load(GaimPlugin *plugin); | |
259 | |
260 /** | |
261 * Unloads the specified plugin. | |
262 * | |
263 * @param plugin The plugin handle. | |
264 * | |
265 * @return @c TRUE if successful, or @c FALSE otherwise. | |
266 * | |
267 * @see gaim_plugin_load() | |
268 * @see gaim_plugin_reload() | |
269 */ | |
270 gboolean gaim_plugin_unload(GaimPlugin *plugin); | |
271 | |
272 /** | |
273 * Reloads a plugin. | |
274 * | |
275 * @param plugin The old plugin handle. | |
276 * | |
277 * @return @c TRUE if successful, or @c FALSE otherwise. | |
278 * | |
279 * @see gaim_plugin_load() | |
280 * @see gaim_plugin_unload() | |
281 */ | |
282 gboolean gaim_plugin_reload(GaimPlugin *plugin); | |
283 | |
284 /** | |
285 * Unloads a plugin and destroys the structure from memory. | |
286 * | |
287 * @param plugin The plugin handle. | |
288 */ | |
289 void gaim_plugin_destroy(GaimPlugin *plugin); | |
290 | |
291 /** | |
292 * Returns whether or not a plugin is currently loaded. | |
293 * | |
294 * @param plugin The plugin. | |
295 * | |
296 * @return @c TRUE if loaded, or @c FALSE otherwise. | |
297 */ | |
298 gboolean gaim_plugin_is_loaded(const GaimPlugin *plugin); | |
299 | |
300 /** | |
301 * Returns whether or not a plugin is unloadable. | |
302 * | |
303 * If this returns @c TRUE, the plugin is guaranteed to not | |
304 * be loadable. However, a return value of @c FALSE does not | |
305 * guarantee the plugin is loadable. | |
306 * | |
307 * @param plugin The plugin. | |
308 * | |
309 * @return @c TRUE if the plugin is known to be unloadable,\ | |
310 * @c FALSE otherwise | |
311 */ | |
312 gboolean gaim_plugin_is_unloadable(const GaimPlugin *plugin); | |
313 | |
314 /** | |
315 * Returns a plugin's id. | |
316 * | |
317 * @param plugin The plugin. | |
318 * | |
319 * @return The plugin's id. | |
320 */ | |
321 const gchar *gaim_plugin_get_id(const GaimPlugin *plugin); | |
322 | |
323 /** | |
324 * Returns a plugin's name. | |
325 * | |
326 * @param plugin The plugin. | |
327 * | |
328 * @return THe name of the plugin, or @c NULL. | |
329 */ | |
330 const gchar *gaim_plugin_get_name(const GaimPlugin *plugin); | |
331 | |
332 /** | |
333 * Returns a plugin's version. | |
334 * | |
335 * @param plugin The plugin. | |
336 * | |
337 * @return The plugin's version or @c NULL. | |
338 */ | |
339 const gchar *gaim_plugin_get_version(const GaimPlugin *plugin); | |
340 | |
341 /** | |
342 * Returns a plugin's summary. | |
343 * | |
344 * @param plugin The plugin. | |
345 * | |
346 * @return The plugin's summary. | |
347 */ | |
348 const gchar *gaim_plugin_get_summary(const GaimPlugin *plugin); | |
349 | |
350 /** | |
351 * Returns a plugin's description. | |
352 * | |
353 * @param plugin The plugin. | |
354 * | |
355 * @return The plugin's description. | |
356 */ | |
357 const gchar *gaim_plugin_get_description(const GaimPlugin *plugin); | |
358 | |
359 /** | |
360 * Returns a plugin's author. | |
361 * | |
362 * @param plugin The plugin. | |
363 * | |
364 * @return The plugin's author. | |
365 */ | |
366 const gchar *gaim_plugin_get_author(const GaimPlugin *plugin); | |
367 | |
368 /** | |
369 * Returns a plugin's homepage. | |
370 * | |
371 * @param plugin The plugin. | |
372 * | |
373 * @return The plugin's homepage. | |
374 */ | |
375 const gchar *gaim_plugin_get_homepage(const GaimPlugin *plugin); | |
376 | |
377 /*@}*/ | |
378 | |
379 /**************************************************************************/ | |
380 /** @name Plugin IPC API */ | |
381 /**************************************************************************/ | |
382 /*@{*/ | |
383 | |
384 /** | |
385 * Registers an IPC command in a plugin. | |
386 * | |
387 * @param plugin The plugin to register the command with. | |
388 * @param command The name of the command. | |
389 * @param func The function to execute. | |
390 * @param marshal The marshalling function. | |
391 * @param ret_value The return value type. | |
392 * @param num_params The number of parameters. | |
393 * @param ... The parameter types. | |
394 * | |
395 * @return TRUE if the function was registered successfully, or | |
396 * FALSE otherwise. | |
397 */ | |
398 gboolean gaim_plugin_ipc_register(GaimPlugin *plugin, const char *command, | |
399 GaimCallback func, | |
400 GaimSignalMarshalFunc marshal, | |
401 GaimValue *ret_value, int num_params, ...); | |
402 | |
403 /** | |
404 * Unregisters an IPC command in a plugin. | |
405 * | |
406 * @param plugin The plugin to unregister the command from. | |
407 * @param command The name of the command. | |
408 */ | |
409 void gaim_plugin_ipc_unregister(GaimPlugin *plugin, const char *command); | |
410 | |
411 /** | |
412 * Unregisters all IPC commands in a plugin. | |
413 * | |
414 * @param plugin The plugin to unregister the commands from. | |
415 */ | |
416 void gaim_plugin_ipc_unregister_all(GaimPlugin *plugin); | |
417 | |
418 /** | |
419 * Returns a list of value types used for an IPC command. | |
420 * | |
421 * @param plugin The plugin. | |
422 * @param command The name of the command. | |
423 * @param ret_value The returned return value. | |
424 * @param num_params The returned number of parameters. | |
425 * @param params The returned list of parameters. | |
426 * | |
427 * @return TRUE if the command was found, or FALSE otherwise. | |
428 */ | |
429 gboolean gaim_plugin_ipc_get_params(GaimPlugin *plugin, const char *command, | |
430 GaimValue **ret_value, int *num_params, | |
431 GaimValue ***params); | |
432 | |
433 /** | |
434 * Executes an IPC command. | |
435 * | |
436 * @param plugin The plugin to execute the command on. | |
437 * @param command The name of the command. | |
438 * @param ok TRUE if the call was successful, or FALSE otherwise. | |
439 * @param ... The parameters to pass. | |
440 * | |
441 * @return The return value, which will be NULL if the command doesn't | |
442 * return a value. | |
443 */ | |
444 void *gaim_plugin_ipc_call(GaimPlugin *plugin, const char *command, | |
445 gboolean *ok, ...); | |
446 | |
447 /*@}*/ | |
448 | |
449 /**************************************************************************/ | |
450 /** @name Plugins API */ | |
451 /**************************************************************************/ | |
452 /*@{*/ | |
453 | |
454 /** | |
455 * Add a new directory to search for plugins | |
456 * | |
457 * @param path The new search path. | |
458 */ | |
459 void gaim_plugins_add_search_path(const char *path); | |
460 | |
461 /** | |
462 * Unloads all loaded plugins. | |
463 */ | |
464 void gaim_plugins_unload_all(void); | |
465 | |
466 /** | |
467 * Destroys all registered plugins. | |
468 */ | |
469 void gaim_plugins_destroy_all(void); | |
470 | |
471 /** | |
472 * Attempts to load all the plugins in the specified preference key | |
473 * that were loaded when gaim last quit. | |
474 * | |
475 * @param key The preference key containing the list of plugins. | |
476 */ | |
477 void gaim_plugins_load_saved(const char *key); | |
478 | |
479 /** | |
480 * Probes for plugins in the registered module paths. | |
481 * | |
482 * @param ext The extension type to probe for, or @c NULL for all. | |
483 * | |
484 * @see gaim_plugin_set_probe_path() | |
485 */ | |
486 void gaim_plugins_probe(const char *ext); | |
487 | |
488 /** | |
489 * Returns whether or not plugin support is enabled. | |
490 * | |
491 * @return TRUE if plugin support is enabled, or FALSE otherwise. | |
492 */ | |
493 gboolean gaim_plugins_enabled(void); | |
494 | |
495 /** | |
496 * Registers a function that will be called when probing is finished. | |
497 * | |
498 * @param func The callback function. | |
499 * @param data Data to pass to the callback. | |
500 */ | |
501 void gaim_plugins_register_probe_notify_cb(void (*func)(void *), void *data); | |
502 | |
503 /** | |
504 * Unregisters a function that would be called when probing is finished. | |
505 * | |
506 * @param func The callback function. | |
507 */ | |
508 void gaim_plugins_unregister_probe_notify_cb(void (*func)(void *)); | |
509 | |
510 /** | |
511 * Registers a function that will be called when a plugin is loaded. | |
512 * | |
513 * @param func The callback function. | |
514 * @param data Data to pass to the callback. | |
515 */ | |
516 void gaim_plugins_register_load_notify_cb(void (*func)(GaimPlugin *, void *), | |
517 void *data); | |
518 | |
519 /** | |
520 * Unregisters a function that would be called when a plugin is loaded. | |
521 * | |
522 * @param func The callback function. | |
523 */ | |
524 void gaim_plugins_unregister_load_notify_cb(void (*func)(GaimPlugin *, void *)); | |
525 | |
526 /** | |
527 * Registers a function that will be called when a plugin is unloaded. | |
528 * | |
529 * @param func The callback function. | |
530 * @param data Data to pass to the callback. | |
531 */ | |
532 void gaim_plugins_register_unload_notify_cb(void (*func)(GaimPlugin *, void *), | |
533 void *data); | |
534 | |
535 /** | |
536 * Unregisters a function that would be called when a plugin is unloaded. | |
537 * | |
538 * @param func The callback function. | |
539 */ | |
540 void gaim_plugins_unregister_unload_notify_cb(void (*func)(GaimPlugin *, | |
541 void *)); | |
542 | |
543 /** | |
544 * Finds a plugin with the specified name. | |
545 * | |
546 * @param name The plugin name. | |
547 * | |
548 * @return The plugin if found, or @c NULL if not found. | |
549 */ | |
550 GaimPlugin *gaim_plugins_find_with_name(const char *name); | |
551 | |
552 /** | |
553 * Finds a plugin with the specified filename (filename with a path). | |
554 * | |
555 * @param filename The plugin filename. | |
556 * | |
557 * @return The plugin if found, or @c NULL if not found. | |
558 */ | |
559 GaimPlugin *gaim_plugins_find_with_filename(const char *filename); | |
560 | |
561 /** | |
562 * Finds a plugin with the specified basename (filename without a path). | |
563 * | |
564 * @param basename The plugin basename. | |
565 * | |
566 * @return The plugin if found, or @c NULL if not found. | |
567 */ | |
568 GaimPlugin *gaim_plugins_find_with_basename(const char *basename); | |
569 | |
570 /** | |
571 * Finds a plugin with the specified plugin ID. | |
572 * | |
573 * @param id The plugin ID. | |
574 * | |
575 * @return The plugin if found, or @c NULL if not found. | |
576 */ | |
577 GaimPlugin *gaim_plugins_find_with_id(const char *id); | |
578 | |
579 /** | |
580 * Returns a list of all loaded plugins. | |
581 * | |
582 * @return A list of all loaded plugins. | |
583 */ | |
584 GList *gaim_plugins_get_loaded(void); | |
585 | |
586 /** | |
587 * Returns a list of all valid protocol plugins. A protocol | |
588 * plugin is considered invalid if it does not contain the call | |
589 * to the GAIM_INIT_PLUGIN() macro, or if it was compiled | |
590 * against an incompatable API version. | |
591 * | |
592 * @return A list of all protocol plugins. | |
593 */ | |
594 GList *gaim_plugins_get_protocols(void); | |
595 | |
596 /** | |
597 * Returns a list of all plugins, whether loaded or not. | |
598 * | |
599 * @return A list of all plugins. | |
600 */ | |
601 GList *gaim_plugins_get_all(void); | |
602 | |
603 /*@}*/ | |
604 | |
605 /**************************************************************************/ | |
606 /** @name Plugins SubSytem API */ | |
607 /**************************************************************************/ | |
608 /*@{*/ | |
609 | |
610 /** | |
611 * Returns the plugin subsystem handle. | |
612 * | |
613 * @return The plugin sybsystem handle. | |
614 */ | |
615 void *gaim_plugins_get_handle(void); | |
616 | |
617 /** | |
618 * Initializes the plugin subsystem | |
619 */ | |
620 void gaim_plugins_init(void); | |
621 | |
622 /** | |
623 * Uninitializes the plugin subsystem | |
624 */ | |
625 void gaim_plugins_uninit(void); | |
626 | |
627 /*@}*/ | |
628 | |
629 /** | |
630 * Allocates and returns a new GaimPluginAction. | |
631 * | |
632 * @param label The description of the action to show to the user. | |
633 * @param callback The callback to call when the user selects this action. | |
634 */ | |
635 GaimPluginAction *gaim_plugin_action_new(const char* label, void (*callback)(GaimPluginAction *)); | |
636 | |
637 /** | |
638 * Frees a GaimPluginAction | |
639 * | |
640 * @param action The GaimPluginAction to free. | |
641 */ | |
642 void gaim_plugin_action_free(GaimPluginAction *action); | |
643 | |
644 #ifdef __cplusplus | |
645 } | |
646 #endif | |
647 | |
648 #endif /* _GAIM_PLUGIN_H_ */ |