~ubuntu-branches/ubuntu/saucy/cairo-dock-plug-ins/saucy

« back to all changes in this revision

Viewing changes to drop-indicator/src/applet-notifications.c

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2009-08-26 21:07:39 UTC
  • Revision ID: james.westby@ubuntu.com-20090826210739-gyjuuqezrzuluao4
Tags: upstream-2.0.8.1
ImportĀ upstreamĀ versionĀ 2.0.8.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
* This file is a part of the Cairo-Dock project
 
3
*
 
4
* Copyright : (C) see the 'copyright' file.
 
5
* E-mail    : see the 'copyright' file.
 
6
*
 
7
* This program is free software; you can redistribute it and/or
 
8
* modify it under the terms of the GNU General Public License
 
9
* as published by the Free Software Foundation; either version 3
 
10
* of the License, or (at your option) any later version.
 
11
*
 
12
* This program is distributed in the hope that it will be useful,
 
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
* GNU General Public License for more details.
 
16
* You should have received a copy of the GNU General Public License
 
17
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
18
*/
 
19
 
 
20
/******************************************************************************
 
21
 
 
22
This file is a part of the cairo-dock program, 
 
23
released under the terms of the GNU General Public License.
 
24
 
 
25
Written by Fabrice Rey (for any bug report, please mail me to fabounet@users.berlios.de)
 
26
 
 
27
******************************************************************************/
 
28
 
 
29
#include <stdlib.h>
 
30
#include <string.h>
 
31
#include <GL/gl.h> 
 
32
#include <gdk/x11/gdkglx.h>
 
33
#include <gtk/gtkgl.h>
 
34
 
 
35
#include "applet-struct.h"
 
36
#include "applet-notifications.h"
 
37
#include "bilinear-gradation-texture.h"
 
38
 
 
39
 
 
40
gboolean cd_drop_indicator_render (gpointer pUserData, CairoDock *pDock, cairo_t *pCairoContext)
 
41
{
 
42
        CDDropIndicatorData *pData = CD_APPLET_GET_MY_DOCK_DATA (pDock);
 
43
        if (pData == NULL)
 
44
                return CAIRO_DOCK_LET_PASS_NOTIFICATION;
 
45
        
 
46
        if (pCairoContext != NULL)
 
47
        {
 
48
                cairo_save (pCairoContext);
 
49
                double fX = pDock->iMouseX - myData.fDropIndicatorWidth / 2;
 
50
                if (pDock->bHorizontalDock)
 
51
                        cairo_rectangle (pCairoContext,
 
52
                                (int) pDock->iMouseX - myData.fDropIndicatorWidth/2,
 
53
                                (int) (pDock->bDirectionUp ? 0 : pDock->iCurrentHeight - 2*myData.fDropIndicatorHeight),
 
54
                                (int) myData.fDropIndicatorWidth,
 
55
                                (int) (pDock->bDirectionUp ? 2*myData.fDropIndicatorHeight : pDock->iCurrentHeight));
 
56
                else
 
57
                        cairo_rectangle (pCairoContext,
 
58
                                (int) (pDock->bDirectionUp ? 0 : pDock->iCurrentHeight - 2*myData.fDropIndicatorHeight),
 
59
                                (int) pDock->iMouseX - myData.fDropIndicatorWidth/2,
 
60
                                (int) (pDock->bDirectionUp ? 2*myData.fDropIndicatorHeight : pDock->iCurrentHeight),
 
61
                                (int) myData.fDropIndicatorWidth);
 
62
                cairo_clip (pCairoContext);
 
63
                
 
64
                //cairo_move_to (pCairoContext, fX, 0);
 
65
                if (pDock->bHorizontalDock)
 
66
                        cairo_translate (pCairoContext, fX, (pDock->bDirectionUp ? 0 : pDock->iCurrentHeight));
 
67
                else
 
68
                        cairo_translate (pCairoContext, (pDock->bDirectionUp ? 0 : pDock->iCurrentHeight), fX);
 
69
                double fRotationAngle = (pDock->bHorizontalDock ? (pDock->bDirectionUp ? 0 : G_PI) : (pDock->bDirectionUp ? -G_PI/2 : G_PI/2));
 
70
                cairo_rotate (pCairoContext, fRotationAngle);
 
71
                
 
72
                cairo_translate (pCairoContext, 0, pData->iDropIndicatorOffset);
 
73
                cairo_pattern_t* pPattern = cairo_pattern_create_for_surface (myData.pDropIndicatorSurface);
 
74
                g_return_val_if_fail (cairo_pattern_status (pPattern) == CAIRO_STATUS_SUCCESS, CAIRO_DOCK_LET_PASS_NOTIFICATION);
 
75
                cairo_pattern_set_extend (pPattern, CAIRO_EXTEND_REPEAT);
 
76
                cairo_set_source (pCairoContext, pPattern);
 
77
                
 
78
                cairo_translate (pCairoContext, 0, - pData->iDropIndicatorOffset);
 
79
                cairo_pattern_t *pGradationPattern = cairo_pattern_create_linear (0.,
 
80
                        0.,
 
81
                        0.,
 
82
                        2*myData.fDropIndicatorHeight);  // de haut en bas.
 
83
                g_return_val_if_fail (cairo_pattern_status (pGradationPattern) == CAIRO_STATUS_SUCCESS, CAIRO_DOCK_LET_PASS_NOTIFICATION);
 
84
        
 
85
                cairo_pattern_set_extend (pGradationPattern, CAIRO_EXTEND_NONE);
 
86
                cairo_pattern_add_color_stop_rgba (pGradationPattern,
 
87
                        0.,
 
88
                        0.,
 
89
                        0.,
 
90
                        0.,
 
91
                        0.);
 
92
                cairo_pattern_add_color_stop_rgba (pGradationPattern,
 
93
                        0.4,
 
94
                        0.,
 
95
                        0.,
 
96
                        0.,
 
97
                        pData->fAlpha);
 
98
                cairo_pattern_add_color_stop_rgba (pGradationPattern,
 
99
                        0.5,
 
100
                        0.,
 
101
                        0.,
 
102
                        0.,
 
103
                        pData->fAlpha);
 
104
                cairo_pattern_add_color_stop_rgba (pGradationPattern,
 
105
                        1.,
 
106
                        0.,
 
107
                        0.,
 
108
                        0.,
 
109
                        0.);
 
110
        
 
111
                cairo_mask (pCairoContext, pGradationPattern);
 
112
                //cairo_paint (pCairoContext);
 
113
                
 
114
                cairo_pattern_destroy (pPattern);
 
115
                cairo_pattern_destroy (pGradationPattern);
 
116
                cairo_restore (pCairoContext);
 
117
                
 
118
                if (pData->fAlphaHover > 0 && myData.pHoverIndicatorSurface != NULL)
 
119
                {
 
120
                        Icon *pIcon = cairo_dock_get_pointed_icon (pDock->icons);
 
121
                        if (pIcon != NULL && ! CAIRO_DOCK_IS_SEPARATOR (pIcon))
 
122
                        {
 
123
                                cairo_save (pCairoContext);
 
124
                                if (pDock->bHorizontalDock)
 
125
                                        cairo_translate (pCairoContext,
 
126
                                                pIcon->fDrawX + 2./3*pIcon->fWidth*pIcon->fScale,
 
127
                                                pIcon->fDrawY);
 
128
                                else
 
129
                                        cairo_translate (pCairoContext,
 
130
                                                pIcon->fDrawY,
 
131
                                                pIcon->fDrawX + 2./3*pIcon->fWidth*pIcon->fScale);
 
132
                                cairo_set_source_surface (pCairoContext, myData.pHoverIndicatorSurface, 0., 0.);
 
133
                                cairo_paint_with_alpha (pCairoContext, pData->fAlphaHover);
 
134
                                cairo_restore (pCairoContext);
 
135
                        }
 
136
                }
 
137
        }
 
138
        else
 
139
        {
 
140
                double fX = pDock->iMouseX;
 
141
                double fY = (pDock->bDirectionUp ? pDock->iCurrentHeight - myData.fDropIndicatorHeight : myData.fDropIndicatorHeight);
 
142
                glPushMatrix();
 
143
                glLoadIdentity();
 
144
                
 
145
                if (pDock->bHorizontalDock)
 
146
                {
 
147
                        fX = pDock->iMouseX;
 
148
                        fY = (pDock->bDirectionUp ? pDock->iCurrentHeight - myData.fDropIndicatorHeight : myData.fDropIndicatorHeight);
 
149
                        glTranslatef (fX, fY, - myData.fDropIndicatorWidth-1.);
 
150
                        if (! pDock->bDirectionUp)
 
151
                                glScalef (1., -1., 1.);
 
152
                }
 
153
                else
 
154
                {
 
155
                        fX = pDock->iCurrentWidth - pDock->iMouseX;
 
156
                        fY = (! pDock->bDirectionUp ? pDock->iCurrentHeight - myData.fDropIndicatorHeight : myData.fDropIndicatorHeight);
 
157
                        glTranslatef (fY, fX, - myData.fDropIndicatorWidth-1.);
 
158
                        glRotatef ((pDock->bDirectionUp ? 90. : -90.), 0., 0., 1.);
 
159
                }
 
160
                
 
161
                glRotatef (pData->iDropIndicatorRotation, 0., 1., 0.);
 
162
                
 
163
                //\_________________ On decale la texture vers le bas.
 
164
                glMatrixMode(GL_TEXTURE); // On selectionne la matrice des textures
 
165
                glPushMatrix();
 
166
                glLoadIdentity(); // On la reset
 
167
                glTranslatef(.0, - pData->iDropIndicatorOffset / myData.fDropIndicatorHeight, 0.);
 
168
                glScalef (1., -2., 1.);
 
169
                glMatrixMode(GL_MODELVIEW); // On revient sur la matrice d'affichage
 
170
                
 
171
                //\_________________ On dessine l'indicateur.
 
172
                glEnable (GL_BLEND);
 
173
                if (pData->fAlpha != 1)
 
174
                        _cairo_dock_set_blend_alpha ();
 
175
                else
 
176
                        _cairo_dock_set_blend_over();
 
177
                
 
178
                //glEnable(GL_DEPTH_TEST);
 
179
                glScalef (myData.fDropIndicatorWidth, myData.fDropIndicatorHeight, myData.fDropIndicatorWidth);
 
180
                glColor4f(1.0f, 1.0f, 1.0f, pData->fAlpha);
 
181
                glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
 
182
                
 
183
                glEnable(GL_TEXTURE);
 
184
                glActiveTextureARB(GL_TEXTURE0_ARB); // Go pour le multitexturing 1ere passe
 
185
                glEnable(GL_TEXTURE_2D); // On active le texturing sur cette passe
 
186
                glBindTexture(GL_TEXTURE_2D, myData.iDropIndicatorTexture);
 
187
                glActiveTextureARB(GL_TEXTURE1_ARB); // Go pour le texturing 2eme passe
 
188
                glEnable(GL_TEXTURE_2D);
 
189
                glBindTexture(GL_TEXTURE_2D, myData.iBilinearGradationTexture);
 
190
                glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); // Le mode de combinaison des textures
 
191
                ///glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_MODULATE);  // multiplier les alpha.
 
192
                //glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_ONE_MINUS_SRC_ALPHA);
 
193
                
 
194
                glBegin(GL_QUADS);
 
195
                glNormal3f(0,0,1);
 
196
                glMultiTexCoord2fARB( GL_TEXTURE0_ARB,0., 0.); glMultiTexCoord2fARB( GL_TEXTURE1_ARB,0., 0.); glVertex3f(-0.5, -1., 0.);  // Bottom Left Of The Texture and Quad
 
197
                glMultiTexCoord2fARB( GL_TEXTURE0_ARB,1., 0.); glMultiTexCoord2fARB( GL_TEXTURE1_ARB,1., 0.); glVertex3f( 0.5, -1., 0.);  // Bottom Right Of The Texture and Quad
 
198
                glMultiTexCoord2fARB( GL_TEXTURE0_ARB,1., 1.); glMultiTexCoord2fARB( GL_TEXTURE1_ARB,1., 1.); glVertex3f( 0.5, 1., 0.);  // Top Right Of The Texture and Quad
 
199
                glMultiTexCoord2fARB( GL_TEXTURE0_ARB,0., 1.); glMultiTexCoord2fARB( GL_TEXTURE1_ARB,0., 1.); glVertex3f(-0.5, 1., 0.);  // Top Left Of The Texture and Quad
 
200
                glNormal3f(1,0,0);
 
201
                glMultiTexCoord2fARB( GL_TEXTURE0_ARB,0., 0.); glMultiTexCoord2fARB( GL_TEXTURE1_ARB,0., 0.); glVertex3f(0., -1., -0.5);  // Bottom Left Of The Texture and Quad
 
202
                glMultiTexCoord2fARB( GL_TEXTURE0_ARB,1., 0.); glMultiTexCoord2fARB( GL_TEXTURE1_ARB,1., 0.); glVertex3f(0., -1.,  0.5);  // Bottom Right Of The Texture and Quad
 
203
                glMultiTexCoord2fARB( GL_TEXTURE0_ARB,1., 1.); glMultiTexCoord2fARB( GL_TEXTURE1_ARB,1., 1.); glVertex3f(0.,  1.,  0.5);  // Top Right Of The Texture and Quad
 
204
                glMultiTexCoord2fARB( GL_TEXTURE0_ARB,0., 1.); glMultiTexCoord2fARB( GL_TEXTURE1_ARB,0., 1.); glVertex3f(0.,  1., -0.5);  // Top Left Of The Texture and Quad
 
205
                glEnd();
 
206
                
 
207
                glActiveTextureARB(GL_TEXTURE1_ARB);
 
208
                glDisable(GL_TEXTURE_2D);
 
209
                glDisable(GL_TEXTURE_GEN_S);
 
210
                glDisable(GL_TEXTURE_GEN_T);
 
211
                glActiveTextureARB(GL_TEXTURE0_ARB);
 
212
                glDisable(GL_TEXTURE_2D);
 
213
                glDisable(GL_TEXTURE_GEN_S);
 
214
                glDisable(GL_TEXTURE_GEN_T);
 
215
                glDisable (GL_BLEND);
 
216
                _cairo_dock_set_blend_alpha ();
 
217
                glPopMatrix();
 
218
                
 
219
                //\_________________ On remet la matrice des textures.
 
220
                glMatrixMode(GL_TEXTURE);
 
221
                glPopMatrix();
 
222
                glMatrixMode(GL_MODELVIEW);
 
223
                
 
224
                if (pData->fAlphaHover > 0 && myData.iHoverIndicatorTexture != 0)
 
225
                {
 
226
                        Icon *pIcon = cairo_dock_get_pointed_icon (pDock->icons);
 
227
                        if (pIcon != NULL && ! CAIRO_DOCK_IS_SEPARATOR (pIcon))
 
228
                        {
 
229
                                _cairo_dock_enable_texture ();
 
230
                                _cairo_dock_set_blend_over ();
 
231
                                glPushMatrix ();
 
232
                                if (pDock->bHorizontalDock)
 
233
                                        glTranslatef (pIcon->fDrawX + 5./6*pIcon->fWidth*pIcon->fScale,
 
234
                                                pDock->iCurrentHeight - pIcon->fDrawY - 1./6*pIcon->fHeight*pIcon->fScale,
 
235
                                                0.);
 
236
                                else
 
237
                                        glTranslatef (pDock->iCurrentHeight - pIcon->fDrawY - 1./6*pIcon->fHeight*pIcon->fScale,
 
238
                                                pDock->iCurrentWidth - (pIcon->fDrawX + 5./6*pIcon->fWidth*pIcon->fScale),
 
239
                                                0.);
 
240
                                _cairo_dock_apply_texture_at_size_with_alpha (myData.iHoverIndicatorTexture,
 
241
                                        myData.fHoverIndicatorWidth,
 
242
                                        myData.fHoverIndicatorHeight,
 
243
                                        pData->fAlphaHover);
 
244
                                glPushMatrix ();
 
245
                                _cairo_dock_disable_texture ();
 
246
                        }
 
247
                }
 
248
        }
 
249
        return CAIRO_DOCK_LET_PASS_NOTIFICATION;
 
250
}
 
251
 
 
252
 
 
253
gboolean cd_drop_indicator_mouse_moved (gpointer pUserData, CairoDock *pDock, gboolean *bStartAnimation)
 
254
{
 
255
        CDDropIndicatorData *pData = CD_APPLET_GET_MY_DOCK_DATA (pDock);
 
256
        
 
257
        if (pDock->bIsDragging)
 
258
        {
 
259
                if (pData == NULL)
 
260
                {
 
261
                        pData = g_new0 (CDDropIndicatorData, 1);
 
262
                        CD_APPLET_SET_MY_DOCK_DATA (pDock, pData);
 
263
                }
 
264
                if (pDock->bCanDrop)
 
265
                        pData->fAlpha = 1.;
 
266
                else
 
267
                        pData->fAlphaHover = 1.;
 
268
        }
 
269
        else if (pData != NULL && pData->fAlpha <= 0 && pData->fAlphaHover <= 0)
 
270
        {
 
271
                g_free (pData);
 
272
                pData = NULL;
 
273
                CD_APPLET_SET_MY_DOCK_DATA (pDock, NULL);
 
274
        }
 
275
        
 
276
        *bStartAnimation = (pData != NULL);
 
277
        return CAIRO_DOCK_LET_PASS_NOTIFICATION;
 
278
}
 
279
 
 
280
 
 
281
gboolean cd_drop_indicator_update_dock (gpointer pUserData, CairoDock *pDock, gboolean *bContinueAnimation)
 
282
{
 
283
        CDDropIndicatorData *pData = CD_APPLET_GET_MY_DOCK_DATA (pDock);
 
284
        if (pData == NULL)
 
285
                return CAIRO_DOCK_LET_PASS_NOTIFICATION;
 
286
        
 
287
        pData->iDropIndicatorOffset += myConfig.iSpeed;
 
288
        if (pData->iDropIndicatorOffset > 2*myData.fDropIndicatorHeight)
 
289
                pData->iDropIndicatorOffset -= 2*myData.fDropIndicatorHeight;
 
290
        double dt = (CAIRO_CONTAINER_IS_OPENGL (CAIRO_CONTAINER (pDock)) ? mySystem.iGLAnimationDeltaT : mySystem.iCairoAnimationDeltaT);
 
291
        pData->iDropIndicatorRotation += myConfig.fRotationSpeed * 360. * dt/1e3;
 
292
        if (pDock->bCanDrop)
 
293
        {
 
294
                pData->fAlphaHover -= .05;
 
295
                *bContinueAnimation = TRUE;
 
296
        }
 
297
        else
 
298
        {
 
299
                pData->fAlpha -= .05;
 
300
                if (!pDock->bIsDragging)
 
301
                        pData->fAlphaHover -= .05;
 
302
                
 
303
                if (pData->fAlpha <= 0 && pData->fAlphaHover <= 0)
 
304
                {
 
305
                        g_free (pData);
 
306
                        CD_APPLET_SET_MY_DOCK_DATA (pDock, NULL);
 
307
                }
 
308
                else
 
309
                        *bContinueAnimation = TRUE;
 
310
        }
 
311
        
 
312
        GdkRectangle rect = {(int) pDock->iMouseX - myData.fDropIndicatorWidth/2,
 
313
                (int) (pDock->bDirectionUp ? 0 : pDock->iCurrentHeight - 2*myData.fDropIndicatorHeight),
 
314
                (int) myData.fDropIndicatorWidth,
 
315
                (int) 2*myData.fDropIndicatorHeight};
 
316
        if (! pDock->bHorizontalDock)
 
317
        {
 
318
                rect.x = (int) (pDock->bDirectionUp ? 0 : pDock->iCurrentHeight - 2*myData.fDropIndicatorHeight);
 
319
                rect.y = (int) pDock->iMouseX - myData.fDropIndicatorWidth/2;
 
320
                rect.width = (int) 2*myData.fDropIndicatorHeight;
 
321
                rect.height =(int) myData.fDropIndicatorWidth;
 
322
        }
 
323
        //g_print ("rect (%d;%d) (%dx%d)\n", rect.x, rect.y, rect.width, rect.height);
 
324
        if (rect.width > 0 && rect.height > 0)
 
325
        {
 
326
                gdk_window_invalidate_rect (pDock->pWidget->window, &rect, FALSE);
 
327
        }
 
328
        
 
329
        if (pData->fAlphaHover > 0)
 
330
        {
 
331
                Icon *pIcon = cairo_dock_get_pointed_icon (pDock->icons);
 
332
                if (pIcon != NULL)
 
333
                        cairo_dock_redraw_icon (pIcon, pDock);
 
334
        }
 
335
        
 
336
        return CAIRO_DOCK_LET_PASS_NOTIFICATION;
 
337
}
 
338
 
 
339
 
 
340
void cd_drop_indicator_load_drop_indicator (gchar *cImagePath, cairo_t* pSourceContext, int iWidth, int iHeight)
 
341
{
 
342
        cd_message ("%s (%s)\n", __func__, cImagePath);
 
343
        if (myData.pDropIndicatorSurface != NULL)
 
344
                cairo_surface_destroy (myData.pDropIndicatorSurface);
 
345
        if (myData.iDropIndicatorTexture != 0)
 
346
        {
 
347
                _cairo_dock_delete_texture (myData.iDropIndicatorTexture);
 
348
                myData.iDropIndicatorTexture = 0;
 
349
        }
 
350
        myData.pDropIndicatorSurface = cairo_dock_create_surface_from_image (cImagePath,
 
351
                pSourceContext,
 
352
                1.,
 
353
                iWidth,
 
354
                iHeight,
 
355
                CAIRO_DOCK_KEEP_RATIO,
 
356
                &myData.fDropIndicatorWidth, &myData.fDropIndicatorHeight,
 
357
                NULL, NULL);
 
358
        if (g_bUseOpenGL && myData.pDropIndicatorSurface != NULL)
 
359
        {
 
360
                myData.iDropIndicatorTexture = cairo_dock_create_texture_from_surface (myData.pDropIndicatorSurface);
 
361
                
 
362
                if (myData.iBilinearGradationTexture == 0)
 
363
                        myData.iBilinearGradationTexture = cairo_dock_load_texture_from_raw_data (gradationTex, 1, 32);
 
364
        }
 
365
}
 
366
 
 
367
void cd_drop_indicator_load_hover_indicator (gchar *cImagePath, cairo_t* pSourceContext, int iWidth, int iHeight)
 
368
{
 
369
        cd_message ("%s (%s)\n", __func__, cImagePath);
 
370
        if (myData.pHoverIndicatorSurface != NULL)
 
371
                cairo_surface_destroy (myData.pHoverIndicatorSurface);
 
372
        if (myData.iHoverIndicatorTexture != 0)
 
373
        {
 
374
                _cairo_dock_delete_texture (myData.iHoverIndicatorTexture);
 
375
                myData.iHoverIndicatorTexture = 0;
 
376
        }
 
377
        myData.pHoverIndicatorSurface = cairo_dock_create_surface_from_image (cImagePath,
 
378
                pSourceContext,
 
379
                1.,
 
380
                iWidth,
 
381
                iHeight,
 
382
                CAIRO_DOCK_KEEP_RATIO,
 
383
                &myData.fHoverIndicatorWidth, &myData.fHoverIndicatorHeight,
 
384
                NULL, NULL);
 
385
        if (g_bUseOpenGL && myData.pHoverIndicatorSurface != NULL)
 
386
        {
 
387
                myData.iHoverIndicatorTexture = cairo_dock_create_texture_from_surface (myData.pHoverIndicatorSurface);
 
388
        }
 
389
}
 
390
 
 
391
 
 
392
gboolean cd_drop_indicator_stop_dock (gpointer data, CairoDock *pDock)
 
393
{
 
394
        CDDropIndicatorData *pData = CD_APPLET_GET_MY_DOCK_DATA (pDock);
 
395
        if (pData != NULL)
 
396
        {
 
397
                g_free (pData);
 
398
                CD_APPLET_SET_MY_DOCK_DATA (pDock, NULL);
 
399
        }
 
400
        return CAIRO_DOCK_LET_PASS_NOTIFICATION;
 
401
}