Support more folding icon styles: arrows, +/- and no lines
[geany-mirror.git] / doc / plugins.dox
blobdf156eb7960dd028747eb866946ef1dcb7e32c23
1 /*
2  *      plugins.dox - this file is part of Geany, a fast and lightweight IDE
3  *
4  *      Copyright 2008-2010 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
5  *      Copyright 2008-2010 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
6  *      Copyright 2009-2010 Frank Lanitz <frank(at)frank(dot)uvena(dot)de>
7  *
8  *      This program is free software; you can redistribute it and/or modify
9  *      it under the terms of the GNU General Public License as published by
10  *      the Free Software Foundation; either version 2 of the License, or
11  *      (at your option) any later version.
12  *
13  *      This program is distributed in the hope that it will be useful,
14  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *      GNU General Public License for more details.
17  *
18  *      You should have received a copy of the GNU General Public License
19  *      along with this program; if not, write to the Free Software
20  *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21  *      MA 02110-1301, USA.
22  *
23  * $Id$
24  *
25  * This file contains additional plugin documentation like the signal system and a small howto.
26  * It is best viewed when filetype is set to C or C++.
27  */
30 /**
31  *
32  * @mainpage Geany Plugin API Documentation
33  *
34  * @author Enrico Tröger, Nick Treleaven, Frank Lanitz
35  * $Date$
36  *
37  * @section Intro
38  * This is the Geany API documentation. It should be considered work in progress.
39  * We will try to document as many functions and structs as possible.
40  *
41  * @warning Do not use any symbol not in the documentation - it may change.
42  *
43  * @section pluginsupport Plugin Support
44  * - @link howto Plugin HowTo @endlink - get started
45  * - @link pluginsymbols.c Plugin Symbols @endlink
46  * - @link plugindata.h Main Datatypes and Macros @endlink
47  * - @link signals Plugin Signals @endlink
48  * - @link pluginutils.h Plugin Utility Functions @endlink
49  * - @link guidelines Plugin Writing Guidelines @endlink
50  * - <b>plugins/demoplugin.c</b> - in Geany's source, bigger than the howto example
51  *
52  * @section common Common API files
53  * - @link dialogs.h @endlink
54  * - @link document.h @endlink
55  * - @link editor.h @endlink
56  * - @link filetypes.h @endlink
57  * - @link keybindings.h @endlink
58  * - @link msgwindow.h @endlink
59  * - @link project.h @endlink
60  * - @link sciwrappers.h Scintilla Wrapper Functions @endlink
61  * - @link stash.h Stash Pref/Setting Functions @endlink
62  * - @link utils.h General Utility Functions @endlink
63  * - @link ui_utils.h Widget Utility Functions @endlink
65  * @section More
66  * - All API functions and types - see <b>Files</b> link at the top
67  * - Deprecated symbols - see <b>Related Pages</b> link at the top
68  *
69  * @note See the HACKING file for information about developing the plugin API and
70  * other useful notes.
71  */
73 /**
74  *  @page signals Plugin Signals
75  *
76  *
77  *  @section Usage
78  *
79  *  To use plugin signals in Geany, you have two options:
80  *
81  *  -# Create a PluginCallback array with the @ref plugin_callbacks symbol. List the signals
82  *     you want to listen to and create the appropiate signal callbacks for each signal.
83  *     The callback array is read @a after plugin_init() has been called.
84  *  -# Use plugin_signal_connect(), which can be called at any time and can also connect
85  *     to non-Geany signals (such as GTK widget signals).
86  *
87  *  The following code demonstrates how to use signals in Geany plugins. The code can be inserted
88  *  in your plugin code at any desired position.
89  *
90  *  @code
91 static void on_document_open(GObject *obj, GeanyDocument *doc, gpointer user_data)
93         printf("Example: %s was opened\n", DOC_FILENAME(doc));
96 PluginCallback plugin_callbacks[] =
98         { "document-open", (GCallback) &on_document_open, FALSE, NULL },
99         { NULL, NULL, FALSE, NULL }
101  *  @endcode
102  *  @note The PluginCallback array has to be ended with a final @c NULL entry.
104  *      @section Signals
106  *  @signaldef document-new
107  *  @signalproto
108  *  void user_function(GObject *obj, GeanyDocument *doc, gpointer user_data);
109  *  @endsignalproto
110  *  @signaldesc
111  *  Sent when a new document is created.
113  *  You need to include "document.h" for the declaration of GeanyDocument.
115  *  @param obj a GeanyObject instance, should be ignored.
116  *  @param doc the new document.
117  *  @param user_data user data.
118  *  @endsignaldef
120  *  @signaldef document-open
121  *  @signalproto
122  *  void user_function(GObject *obj, GeanyDocument *doc, gpointer user_data);
123  *  @endsignalproto
124  *  @signaldesc
125  *  Sent when a new document is opened.
127  *  You need to include "document.h" for the declaration of GeanyDocument.
129  *  @param obj a GeanyObject instance, should be ignored.
130  *  @param doc the opened document.
131  *  @param user_data user data.
132  *  @endsignaldef
134  *  @signaldef document-before-save
135  *  @signalproto
136  *  void user_function(GObject *obj, GeanyDocument *doc, gpointer user_data);
137  *  @endsignalproto
138  *  @signaldesc
139  *  Sent before a document is saved.
141  *  You need to include "document.h" for the declaration of GeanyDocument.
143  *  @param obj a GeanyObject instance, should be ignored.
144  *  @param doc the document to be saved.
145  *  @param user_data user data.
146  *  @endsignaldef
148  *  @signaldef document-save
149  *  @signalproto
150  *  void user_function(GObject *obj, GeanyDocument *doc, gpointer user_data);
151  *  @endsignalproto
152  *  @signaldesc
153  *  Sent when a new document is saved.
155  *  You need to include "document.h" for the declaration of GeanyDocument.
157  *  @param obj a GeanyObject instance, should be ignored.
158  *  @param doc the saved document.
159  *  @param user_data user data.
160  *  @endsignaldef
162  *  @signaldef document-filetype-set
163  *  @signalproto
164  *  void user_function(GObject *obj, GeanyDocument *doc, GeanyFiletype *filetype_old, gpointer user_data);
165  *  @endsignalproto
166  *  @signaldesc
167  *  Sent after the filetype of a document has been changed.
168  *  The previous filetype object is passed but it can be NULL (e.g. at startup).
169  *  The new filetype can be read with: @code
170  *     GeanyFiletype *ft = doc->file_type;
171  *  @endcode
173  *  @param obj a GeanyObject instance, should be ignored.
174  *  @param doc the saved document.
175  *  @param filetype_old the previous filetype of the document.
176  *  @param user_data user data.
177  *  @endsignaldef
179  *  @signaldef document-activate
180  *  @signalproto
181  *  void user_function(GObject *obj, GeanyDocument *doc, gpointer user_data);
182  *  @endsignalproto
183  *  @signaldesc
184  *  Sent when switching notebook pages.
186  *  You need to include "document.h" for the declaration of GeanyDocument.
188  *  @param obj a GeanyObject instance, should be ignored.
189  *  @param doc the current document.
190  *  @param user_data user data.
191  *  @endsignaldef
193  *  @signaldef document-close
194  *  @signalproto
195  *  void user_function(GObject *obj, GeanyDocument *doc, gpointer user_data);
196  *  @endsignalproto
197  *  @signaldesc
198  *  Sent before closing a document.
200  *  You need to include "document.h" for the declaration of GeanyDocument.
202  *  @param obj a GeanyObject instance, should be ignored.
203  *  @param doc the document about to be closed.
204  *  @param user_data user data.
205  *  @endsignaldef
207  *  @signaldef project-open
208  *  @signalproto
209  *  void user_function(GObject *obj, GKeyFile *config, gpointer user_data);
210  *  @endsignalproto
211  *  @signaldesc
212  *  Sent after a project is opened but before session files are loaded.
213  *  @param obj a GeanyObject instance, should be ignored.
214  *  @param config an exising GKeyFile object which can be used to read and write data.
215  *    It must not be closed or freed.
216  *  @param user_data user data.
217  *  @endsignaldef
219  *  @signaldef project-save
220  *  @signalproto
221  *  void user_function(GObject *obj, GKeyFile *config, gpointer user_data);
222  *  @endsignalproto
223  *  @signaldesc
224  *  Sent when a project is saved(happens when the project is created, the properties
225  *  dialog is closed or Geany is exited). This signal is emitted shortly before Geany
226  *  will write the contents of the GKeyFile to the disc.
227  *  @param obj a GeanyObject instance, should be ignored.
228  *  @param config an exising GKeyFile object which can be used to read and write data.
229  *    It must not be closed or freed.
230  *  @param user_data user data.
231  *  @endsignaldef
233  *  @signaldef project-close
234  *  @signalproto
235  *  void user_function(GObject *obj, gpointer user_data);
236  *  @endsignalproto
237  *  @signaldesc
238  *  Sent after a project is closed.
239  *  @param obj a GeanyObject instance, should be ignored.
240  *  @param user_data user data.
241  *  @endsignaldef
243  *  @signaldef geany-startup-complete
244  *  @signalproto
245  *  void user_function(GObject *obj, gpointer user_data);
246  *  @endsignalproto
247  *  @signaldesc
248  *  Sent once Geany has finished all initialization and startup tasks and the GUI has been
249  *  realized. This signal is the very last step in the startup process and is sent once
250  *  the GTK main event loop has been entered.
252  *  @param obj a GeanyObject instance, should be ignored.
253  *  @param user_data user data.
254  *  @endsignaldef
256  *  @signaldef update-editor-menu
257  *  @signalproto
258  *  void user_function(GObject *obj, const gchar *word, gint pos, GeanyDocument *doc,
259  *              gpointer user_data);
260  *  @endsignalproto
261  *  @signaldesc
262  *  Sent before the popup menu of the editing widget is shown. This can be used to modify or extend
263  *  the popup menu.
265  *  @note You can add menu items from @c plugin_init() using @c geany->main_widgets->editor_menu,
266  *  remembering to destroy them in @c plugin_cleanup().
268  *  You need to include "document.h" for the declaration of GeanyDocument.
270  *  @param obj a GeanyObject instance, should be ignored.
271  *  @param word the current word (in UTF-8 encoding) below the cursor position
272                    where the popup menu will be opened.
273  *  @param click_pos the cursor position where the popup will be opened.
274  *  @param doc the current document.
275  *  @param user_data user data.
276  *  @endsignaldef
278  *  @signaldef editor-notify
279  *  @signalproto
280  *  gboolean user_function(GObject *obj, GeanyEditor *editor, SCNotification *nt,
281  *              gpointer user_data);
282  *  @endsignalproto
283  *  @signaldesc
284  *  This signal is sent whenever something in the editor widget changes (character added,
285  *  fold level changes, clicks to the line number margin, ...).
286  *  A detailed description of possible notifications and the SCNotification can be found at
287  *  http://www.scintilla.org/ScintillaDoc.html#Notifications.
289  *  If you connect to this signal, you must check @c nt->nmhdr.code for the notification type
290  *  to prevent handling unwanted notifications. This is important because for instance SCN_UPDATEUI
291  *  is sent very often whereas you probably don't want to handle this notification.
293  *  By default, the signal is sent before Geany's default handler is processing the event.
294  *  Your callback function should return FALSE to allow Geany processing the event as well. If you
295  *  want to prevent this for some reason, return TRUE.
296  *  Please use this with care as it can break basic functionality of Geany.
298  *  The signal can be sent after Geany's default handler has been run when you set
299  *  PluginCallback::after field to TRUE.
301  *  An example callback implemention of this signal can be found in the Demo plugin.
303  *  @warning This signal has much power and should be used carefully. You should especially
304  *           care about the return value; make sure to return TRUE only if it is necessary
305  *           and in the correct situations.
307  *  You need to include "editor.h" for the declaration of GeanyEditor and "Scintilla.h" for
308  *  SCNotification.
310  *  @param obj a GeanyObject instance, should be ignored.
311  *  @param editor The current GeanyEditor.
312  *  @param nt A pointer to the SCNotification struct which holds additional information for
313  *            the event.
314  *  @param user_data user data.
315  *  @return @c TRUE to stop other handlers from being invoked for the event.
316  *          @c FALSE to propagate the event further.
318  *  @since 0.16
319  *  @endsignaldef
323  *  @page guidelines Plugin Writing Guidelines
325  *  @section intro Introduction
327  *  The following hints and guidelines are only recommendations. Nobody is forced to follow
328  *  them at all.
330  *  @section general General notes
332  *  @subsection ideas Getting a plugin idea
334  *  If you want to write a plugin but don't know yet what it should do, have a look at
335  *  http://www.geany.org/Support/PluginWishlist to get an idea about what users wish.
337  *  @subsection code Managing the source code
339  *  For authors of plugins for Geany, we created a dedicated @a geany-plugins project at
340  *  Sourceforge to ease development of plugins and help new authors.
341  *  Project website: http://sourceforge.net/projects/geany-plugins
343  *  Each plugin author is welcome to use these services. To do so, you need an account at
344  *  Sourceforge. You can easily register at (http://sourceforge.net/account/registration/).
345  *  After you successfully created an account,
346  *  tell your account name Enrico or Nick and you will write access to the SVN repository
347  *  (http://geany-plugins.svn.sourceforge.net/viewvc/geany-plugins/).
348  *  Then you can use the repository for your own plugin.
350  *  Authors using this service should subscribe to the
351  *  geany-plugins-commits at uvena.de and geany-plugins-tracker at uvena.de
352  *  mailing lists(see my previous post) to stay up to date with changes.
353  *  General plugin discussion can happen on the normal geany at uvena.de or
354  *  geany-devel at uvena.de lists.
356  *  At time of writing, there are some plugins already available in the
357  *  repository. Feel free to use any of these plugins as a start for your own,
358  *  maybe by copying the directory structure and the autotools files
359  *  (Makefile.am, configure.in, ...). Most of the available plugins are also ready for
360  *  i18n support, just for reference.
362  *  New plugins should be imported into a new directory inside the trunk/
363  *  directory. There are also the common branches and tags directories, use
364  *  them as needed, use always a subdirectory for your own plugin.
366  *  We encourage authors using this service to only commit changes to their
367  *  own plugin and not to others' plugins. Instead just send patches to
368  *  geany-devel at uvena.de or the plugin author directly.
370  *  (the full announcement of this service can be found at
371  *  http://lists.uvena.de/geany/2008-April/003225.html)
374  *  @section paths Installation paths
376  *   - The plugin binary (@c pluginname.so) should be installed in Geany's libdir. This is
377  *     necessary so that Geany can find the plugin.
378  *     An easy way to retrieve Geany's libdir is to use the pkg-config tool, e.g. @code
379  *     `$PKG_CONFIG --variable=libdir geany`/ geany
380  *     @endcode
381  *   - If your plugin creates other binary files like helper programs or helper libraries,
382  *     they should go into @c $prefix/bin (for programs, ideally prefixed with @a geany),
383  *     additional libraries should be installed in Geany's libdir, maybe in a subdirectory.
384  *   - Plugins should install their documentation files (README, NEWS, ChangeLog, licences and
385  *     other documentation files) into the common documentation directory
386  *     @c $prefix/share/doc/geany-plugins/$pluginname/
387  *   - Translation files should be installed normally into @c $prefix/share/locale. There is no
388  *     need to use Geany's translation directory. To set up translation support properly and
389  *     for additional information, see main_locale_init().
390  *   - Do @a never install anything into a user's home directory like installing
391  *     the plugin binary in @c ~/.config/geany/plugins/.
394  *  @page howto Plugin HowTo
396  *  @section intro Introduction
398  *  Since Geany 0.12 there is a plugin interface to extend Geany's functionality and
399  *  add new features. This document gives a brief overview about how to add new
400  *  plugins by writing a simple "Hello World" plugin in C.
403  *  @section buildenv Build environment
405  *  To be able to write plugins for Geany, you need the source code and some development
406  *  packages for GTK and its dependencies. The following will only describe the way to compile and
407  *  build plugins on Unix-like systems [1].
408  *  If you already have the Geany source code and compiled it from them, you can skip the
409  *  following.
411  *  First you need to have Geany installed. Then install the development files for GTK
412  *  and its dependencies. The easiest way to do this is to use your distribution's package
413  *  management system, e.g. on Debian and Ubuntu systems you can use
414  *  @code apt-get install libgtk2.0-dev intltool @endcode
415  *  This will install all necessary files to be able to compile plugins for Geany. On other
416  *  distributions, the package names and commands to use may differ.
418  *  Basically, you are done at this point and could continue with writing the plugin code.
420  *  [1] For Windows, it is basically the same but you might have some more work on setting up
421  *  the general build environment(compiler, GTK development files, ...). This is described on
422  *  Geany's website at http://www.geany.org/Support/BuildingOnWin32.
424  *  @section helloworld "Hello World"
426  *  When writing a plugin, you will find a couple of functions or macros which are mandatory
427  *  and some which are free to use for implementing some useful feature once your plugin
428  *  becomes more powerful like including a configuration or help dialog.
430  *  You should start your plugin with including some of the needed C header files and defining
431  *  some basic global variables which will help you to access all needed functions of the plugin
432  *  API in a more comfortable way.
434  *  Let's start with the very basic headers and add more later if necessary.
435  *  @code
436 #include "geanyplugin.h"
437  *  @endcode
439  *  @a geanyplugin.h includes all of the Geany API and also the necessary GTK header files,
440  *  so there is no need to include @a gtk/gtk.h yourself.
442  *  @note
443  *  @a plugindata.h contains the biggest part of the plugin API and provides some basic macros.
444  *  @a geanyfunctions.h provides some macros for convenient access to plugin API functions.
446  *  The you should define three basic variables which will give access to data fields and
447  *  functions provided by the plugin API.
448  *  @code
449 GeanyPlugin                     *geany_plugin;
450 GeanyData                       *geany_data;
451 GeanyFunctions          *geany_functions;
452  *  @endcode
454  *  Now you can go on and write your first lines for your new plugin. As mentioned before,
455  *  you will need to implement and fill out a couple of functions/macros to make the plugin work.
456  *  So let's start with PLUGIN_VERSION_CHECK().
458  *  PLUGIN_VERSION_CHECK() is a convenient way to tell Geany which version of Geany's plugin API
459  *  is needed at minimum to run your plugin. The value is defined in
460  *  @a plugindata.h by @a GEANY_API_VERSION. In most cases this should be your minimum.
461  *  Nevertheless when setting this value, you should choose the lowest possible version here to
462  *  make the plugin compatible with a bigger number of versions of Geany.
464  *  For the next step, you will need to tell Geany some basic information about your plugin
465  *  which will be shown in the plugin manager dialog.
467  *  For doing this, you should use PLUGIN_SET_INFO() which expects 4 values:
468  *  - Plugin name
469  *  - Short description
470  *  - Version
471  *  - Author
473  *  Based on this, the line could look like:
474  *  @code
475 PLUGIN_SET_INFO("HelloWorld", "Just another tool to say hello world",
476                                 "1.0", "John Doe <john.doe@example.org>");
477  *  @endcode
479  *  Once this is done, you will need to implement the function which will be executed when the
480  *  plugin is loaded. Part of that function could be adding and removing of an item to
481  *  Geany's Tools menu, setting up keybindings or registering some callbacks. Also you will
482  *  need to implement the function that is called when your plugin is unloaded.
483  *  These functions are called plugin_init() and plugin_cleanup(). Let's see how it could look like:
484  *  @code
485 PLUGIN_VERSION_CHECK(147)
487 PLUGIN_SET_INFO("HelloWorld", "Just another tool to say hello world",
488                                 "1.0", "Joe Doe <joe.doe@example.org>");
490 void plugin_init(GeanyData *data)
494 void plugin_cleanup(void)
497  *  @endcode
499  *  If you think this plugin seems not to implement any functionality right now and only wastes
500  *  some memory, you are right. But it should compile and load/unload in Geany nicely.
501  *  Now you have the very basic layout of a new plugin. Great, isn't it?
503  *  @section building Building
505  *  First make plugin.o:
507  *  @code gcc -c plugin.c -fPIC `pkg-config --cflags geany` @endcode
509  *  Then make the plugin library plugin.so (or plugin.dll on Windows):
511  *  @code gcc plugin.o -o plugin.so -shared `pkg-config --libs geany` @endcode
513  *  If all went OK, put the library into one of the paths Geany looks for plugins,
514  *  e.g. $prefix/lib/geany. See @ref paths "Installation paths" for details.
516  *  @section realfunc Adding functionality
518  *  Let's go on and implement some real functionality.
520  *  As mentioned before, plugin_init() will be called when the plugin is loaded in Geany.
521  *  So it should implement everything that needs to be done during startup. In this case,
522  *  we'd like to add a menu item to Geany's Tools menu which runs a dialog printing "Hello World".
523  *  @code
524 void plugin_init(GeanyData *data)
526         GtkWidget *main_menu_item;
528         // Create a new menu item and show it
529         main_menu_item = gtk_menu_item_new_with_mnemonic("Hello World");
530         gtk_widget_show(main_menu_item);
532         // Attach the new menu item to the Tools menu
533         gtk_container_add(GTK_CONTAINER(geany->main_widgets->tools_menu),
534                 main_menu_item);
536         // Connect the menu item with a callback function
537         // which is called when the item is clicked
538         g_signal_connect(main_menu_item, "activate",
539                 G_CALLBACK(item_activate_cb), NULL);
541  *  @endcode
543  *  This will add an item to the Tools menu and connect this item to a function which implements
544  *  what should be done when the menu item is activated by the user.
545  *  This is done by g_signal_connect(). The Tools menu can be accessed with
546  *  geany->main_widgets->tools_menu. The structure @a main_widgets contains pointers to the
547  *  main GUI elements in Geany.
549  *  Geany has a simple API for showing message dialogs. So our function contains
550  *  only a few lines:
551  *  @code
552 void item_activate_cb(GtkMenuItem *menuitem, gpointer user_data)
554         dialogs_show_msgbox(GTK_MESSAGE_INFO, "Hello World");
556  *  @endcode
558  *  For the moment you don't need to worry about the parameters of that function.
560  *  Now we need to clean up properly when the plugin is unloaded.
562  *  To remove the menu item from the Tools menu, you can use gtk_widget_destroy().
563  *  gtk_widget_destroy() expects a pointer to a GtkWidget object.
565  *  First you should add gtk_widget_destroy() to your plugin_cleanup() function.
566  *  The argument for gtk_widget_destroy() is the widget object you created earlier in
567  *  plugin_init(). To be able to access this pointer in plugin_cleanup(), you need to move
568  *  its definition from plugin_init() into the global context so its visibility will increase
569  *  and it can be accessed in all functions.
570  *  @code
571 static GtkWidget *main_menu_item = NULL;
573 // ...
574 void plugin_init(GeanyData *data)
576         main_menu_item = gtk_menu_item_new_with_mnemonic("Hello World");
577         gtk_widget_show(main_menu_item);
578 // ...
581 void plugin_cleanup(void)
583         gtk_widget_destroy(main_menu_item);
585  *  @endcode
587  *  This will ensure your menu item is removed from the Tools menu as well as from
588  *  memory once your plugin is unloaded, so you don't leave any memory leaks.
589  *  Once this is done, your first plugin is ready. Congratulations!
591  *  @section listing Complete listing (without comments)
593  *  @code
594 #include "geanyplugin.h"
596 GeanyPlugin             *geany_plugin;
597 GeanyData               *geany_data;
598 GeanyFunctions  *geany_functions;
600 PLUGIN_VERSION_CHECK(147)
602 PLUGIN_SET_INFO("HelloWorld", "Just another tool to say hello world",
603                                 "1.0", "John Doe <john.doe@example.org>");
606 static GtkWidget *main_menu_item = NULL;
608 static void item_activate_cb(GtkMenuItem *menuitem, gpointer gdata)
610         dialogs_show_msgbox(GTK_MESSAGE_INFO, "Hello World");
613 void plugin_init(GeanyData *data)
615         main_menu_item = gtk_menu_item_new_with_mnemonic("Hello World");
616         gtk_widget_show(main_menu_item);
617         gtk_container_add(GTK_CONTAINER(geany->main_widgets->tools_menu),
618                 main_menu_item);
619         g_signal_connect(main_menu_item, "activate",
620                 G_CALLBACK(item_activate_cb), NULL);
623 void plugin_cleanup(void)
625         gtk_widget_destroy(main_menu_item);
627  *  @endcode
630  * Now you might like to look at Geany's source code for core plugins such as
631  * @a plugins/demoplugin.c.
632  **/