Camera tracking: backport refactoring made in local branches with masking and dopeshe...
[blender.git] / source / blender / editors / space_clip / clip_graph_ops.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2011 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * Contributor(s): Blender Foundation,
23  *                 Sergey Sharybin
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/space_clip/clip_graph_ops.c
29  *  \ingroup spclip
30  */
31
32 #include "DNA_object_types.h"   /* SELECT */
33 #include "DNA_scene_types.h"
34
35 #include "MEM_guardedalloc.h"
36
37 #include "BLI_utildefines.h"
38 #include "BLI_math.h"
39 #include "BLI_listbase.h"
40 #include "BLI_rect.h"
41
42 #include "BKE_context.h"
43 #include "BKE_movieclip.h"
44 #include "BKE_tracking.h"
45 #include "BKE_depsgraph.h"
46
47 #include "WM_api.h"
48 #include "WM_types.h"
49
50 #include "ED_screen.h"
51 #include "ED_clip.h"
52
53 #include "UI_interface.h"
54
55 #include "RNA_access.h"
56 #include "RNA_define.h"
57
58 #include "UI_view2d.h"
59
60 #include "clip_intern.h"        // own include
61
62 /******************** common graph-editing utilities ********************/
63
64 static int ED_space_clip_graph_poll(bContext *C)
65 {
66         if (ED_space_clip_tracking_poll(C)) {
67                 ARegion *ar = CTX_wm_region(C);
68
69                 return ar->regiontype == RGN_TYPE_PREVIEW;
70         }
71
72         return FALSE;
73 }
74
75 typedef struct {
76         int action;
77 } SelectUserData;
78
79 static void toggle_selection_cb(void *userdata, MovieTrackingMarker *marker)
80 {
81         SelectUserData *data = (SelectUserData *)userdata;
82
83         switch (data->action) {
84                 case SEL_SELECT:
85                         marker->flag |= MARKER_GRAPH_SEL;
86                         break;
87                 case SEL_DESELECT:
88                         marker->flag &= ~MARKER_GRAPH_SEL;
89                         break;
90                 case SEL_INVERT:
91                         marker->flag ^= MARKER_GRAPH_SEL;
92                         break;
93         }
94 }
95
96 /******************** mouse select operator ********************/
97
98 typedef struct {
99         int coord,              /* coordinate index of found entuty (0 = X-axis, 1 = Y-axis) */
100             has_prev;           /* if there's valid coordinate of previous point of curve segment */
101
102         float min_dist,         /* minimal distance between mouse and currently found entuty */
103               mouse_co[2],      /* mouse coordinate */
104               prev_co[2],       /* coordinate of previeous point of segment */
105               min_co[2];        /* coordinate of entity with minimal distance */
106
107         MovieTrackingTrack *track;      /* nearest found track */
108         MovieTrackingMarker *marker;    /* nearest found marker */
109 } MouseSelectUserData;
110
111 static void find_nearest_tracking_segment_cb(void *userdata, MovieTrackingTrack *track,
112                                              MovieTrackingMarker *marker, int coord, float val)
113 {
114         MouseSelectUserData *data = userdata;
115         float co[2] = {marker->framenr, val};
116
117         if (data->has_prev) {
118                 float d = dist_to_line_segment_v2(data->mouse_co, data->prev_co, co);
119
120                 if (data->track == NULL || d < data->min_dist) {
121                         data->track = track;
122                         data->min_dist = d;
123                         data->coord = coord;
124                         copy_v2_v2(data->min_co, co);
125                 }
126         }
127
128         data->has_prev = TRUE;
129         copy_v2_v2(data->prev_co, co);
130 }
131
132 void find_nearest_tracking_segment_end_cb(void *userdata)
133 {
134         MouseSelectUserData *data = userdata;
135
136         data->has_prev = FALSE;
137 }
138
139 static void find_nearest_tracking_knot_cb(void *userdata, MovieTrackingTrack *track,
140                                           MovieTrackingMarker *marker, int coord, float val)
141 {
142         MouseSelectUserData *data = userdata;
143         float dx = marker->framenr - data->mouse_co[0], dy = val - data->mouse_co[1];
144         float d = dx * dx + dy * dy;
145
146         if (data->marker == NULL || d < data->min_dist) {
147                 float co[2]= {marker->framenr, val};
148
149                 data->track = track;
150                 data->marker = marker;
151                 data->min_dist = d;
152                 data->coord = coord;
153                 copy_v2_v2(data->min_co, co);
154         }
155
156 }
157
158 static void mouse_select_init_data(MouseSelectUserData *userdata, float *co)
159 {
160         memset(userdata, 0, sizeof(MouseSelectUserData));
161         userdata->min_dist = FLT_MAX;
162         copy_v2_v2(userdata->mouse_co, co);
163 }
164
165 static int mouse_select_knot(bContext *C, float co[2], int extend)
166 {
167         SpaceClip *sc = CTX_wm_space_clip(C);
168         MovieClip *clip= ED_space_clip(sc);
169         ARegion *ar = CTX_wm_region(C);
170         View2D *v2d = &ar->v2d;
171         MovieTracking *tracking = &clip->tracking;
172         MovieTrackingTrack *act_track = BKE_tracking_active_track(tracking);
173         static const int delta = 6;
174
175         if (act_track) {
176                 MouseSelectUserData userdata;
177
178                 mouse_select_init_data(&userdata, co);
179                 clip_graph_tracking_values_iterate_track(sc, act_track, &userdata,
180                                                          find_nearest_tracking_knot_cb, NULL, NULL);
181
182                 if (userdata.marker) {
183                         int x1, y1, x2, y2;
184
185                         UI_view2d_view_to_region(v2d, co[0], co[1], &x1, &y1);
186                         UI_view2d_view_to_region(v2d, userdata.min_co[0], userdata.min_co[1], &x2, &y2);
187
188                         if (abs(x2 - x1) <= delta && abs(y2 - y1) <= delta) {
189                                 if (!extend) {
190                                         SelectUserData selectdata = {SEL_DESELECT};
191
192                                         clip_graph_tracking_iterate(sc, &selectdata, toggle_selection_cb);
193                                 }
194
195                                 if (userdata.coord == 0)
196                                         userdata.marker->flag |= MARKER_GRAPH_SEL_X;
197                                 else
198                                         userdata.marker->flag |= MARKER_GRAPH_SEL_Y;
199
200                                 return TRUE;
201                         }
202                 }
203         }
204
205         return FALSE;
206 }
207
208 static int mouse_select_curve(bContext *C, float co[2], int extend)
209 {
210         SpaceClip *sc = CTX_wm_space_clip(C);
211         MovieClip *clip = ED_space_clip(sc);
212         MovieTracking *tracking = &clip->tracking;
213         MovieTrackingTrack *act_track = BKE_tracking_active_track(tracking);
214         MouseSelectUserData userdata;
215
216         mouse_select_init_data(&userdata, co);
217         clip_graph_tracking_values_iterate(sc, &userdata, find_nearest_tracking_segment_cb,
218                                            NULL, find_nearest_tracking_segment_end_cb);
219
220         if (userdata.track) {
221                 if (extend) {
222                         if (act_track == userdata.track) {
223                                 /* currently only single curve can be selected (selected curve represents active track) */
224                                 act_track = NULL;
225                         }
226                 }
227                 else if (act_track != userdata.track) {
228                         MovieTrackingMarker *marker;
229                         SelectUserData selectdata = {SEL_DESELECT};
230
231                         tracking->act_track = userdata.track;
232
233                         /* make active track be centered to screen */
234                         marker = BKE_tracking_get_marker(userdata.track, sc->user.framenr);
235
236                         clip_view_center_to_point(sc, marker->pos[0], marker->pos[1]);
237
238                         /* deselect all knots on newly selected curve */
239                         clip_graph_tracking_iterate(sc, &selectdata, toggle_selection_cb);
240                 }
241
242                 return TRUE;
243         }
244
245         return FALSE;
246 }
247
248 static int mouse_select(bContext *C, float co[2], int extend)
249 {
250         int sel = FALSE;
251
252         /* first try to select knot on selected curves */
253         sel = mouse_select_knot(C, co, extend);
254
255         if (!sel) {
256                 /* if there's no close enough knot to mouse osition, select nearest curve */
257                 sel = mouse_select_curve(C, co, extend);
258         }
259
260         if (sel)
261                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
262
263         return OPERATOR_FINISHED;
264 }
265
266 static int select_exec(bContext *C, wmOperator *op)
267 {
268         float co[2];
269         int  extend = RNA_boolean_get(op->ptr, "extend");
270
271         RNA_float_get_array(op->ptr, "location", co);
272
273         return mouse_select(C, co, extend);
274 }
275
276 static int select_invoke(bContext *C, wmOperator *op, wmEvent *event)
277 {
278         ARegion *ar = CTX_wm_region(C);
279         float co[2];
280
281         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
282         RNA_float_set_array(op->ptr, "location", co);
283
284         return select_exec(C, op);
285 }
286
287 void CLIP_OT_graph_select(wmOperatorType *ot)
288 {
289         /* identifiers */
290         ot->name = "Select";
291         ot->description = "Select graph curves";
292         ot->idname = "CLIP_OT_graph_select";
293
294         /* api callbacks */
295         ot->exec = select_exec;
296         ot->invoke = select_invoke;
297         ot->poll = ED_space_clip_graph_poll;
298
299         /* flags */
300         ot->flag = OPTYPE_UNDO;
301
302         /* properties */
303         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
304                 "Location", "Mouse location to select nearest entity", -100.0f, 100.0f);
305         RNA_def_boolean(ot->srna, "extend", 0,
306                 "Extend", "Extend selection rather than clearing the existing selection");
307 }
308
309 /********************** border select operator *********************/
310
311 typedef struct BorderSelectuserData {
312         rctf rect;
313         int change, mode, extend;
314 } BorderSelectuserData;
315
316 static void border_select_cb(void *userdata, MovieTrackingTrack *UNUSED(track),
317                              MovieTrackingMarker *marker, int coord, float val)
318 {
319         BorderSelectuserData *data = (BorderSelectuserData *) userdata;
320
321         if (BLI_in_rctf(&data->rect, marker->framenr, val)) {
322                 int flag = 0;
323
324                 if (coord == 0)
325                         flag = MARKER_GRAPH_SEL_X;
326                 else
327                         flag = MARKER_GRAPH_SEL_Y;
328
329                 if (data->mode == GESTURE_MODAL_SELECT)
330                         marker->flag |= flag;
331                 else
332                         marker->flag &= ~flag;
333
334                 data->change = TRUE;
335         }
336         else if (!data->extend) {
337                 marker->flag&= ~MARKER_GRAPH_SEL;
338         }
339 }
340
341 static int border_select_graph_exec(bContext *C, wmOperator *op)
342 {
343         SpaceClip *sc = CTX_wm_space_clip(C);
344         ARegion *ar = CTX_wm_region(C);
345         MovieClip *clip = ED_space_clip(sc);
346         MovieTracking *tracking = &clip->tracking;
347         MovieTrackingTrack *act_track = BKE_tracking_active_track(tracking);
348         BorderSelectuserData userdata;
349         rcti rect;
350
351         /* get rectangle from operator */
352         rect.xmin = RNA_int_get(op->ptr, "xmin");
353         rect.ymin = RNA_int_get(op->ptr, "ymin");
354         rect.xmax = RNA_int_get(op->ptr, "xmax");
355         rect.ymax = RNA_int_get(op->ptr, "ymax");
356
357         UI_view2d_region_to_view(&ar->v2d, rect.xmin, rect.ymin, &userdata.rect.xmin, &userdata.rect.ymin);
358         UI_view2d_region_to_view(&ar->v2d, rect.xmax, rect.ymax, &userdata.rect.xmax, &userdata.rect.ymax);
359
360         userdata.change = FALSE;
361         userdata.mode = RNA_int_get(op->ptr, "gesture_mode");
362         userdata.extend = RNA_boolean_get(op->ptr, "extend");
363
364         clip_graph_tracking_values_iterate_track(sc, act_track, &userdata, border_select_cb, NULL, NULL);
365
366         if (userdata.change) {
367                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
368
369                 return OPERATOR_FINISHED;
370         }
371
372         return OPERATOR_CANCELLED;
373 }
374
375 void CLIP_OT_graph_select_border(wmOperatorType *ot)
376 {
377         /* identifiers */
378         ot->name = "Border Select";
379         ot->description = "Select curve points using border selection";
380         ot->idname = "CLIP_OT_graph_select_border";
381
382         /* api callbacks */
383         ot->invoke = WM_border_select_invoke;
384         ot->exec = border_select_graph_exec;
385         ot->modal = WM_border_select_modal;
386         ot->poll = ED_space_clip_graph_poll;
387
388         /* flags */
389         ot->flag = OPTYPE_UNDO;
390
391         /* properties */
392         WM_operator_properties_gesture_border(ot, TRUE);
393 }
394
395 /********************** select all operator *********************/
396
397 static int graph_select_all_markers_exec(bContext *C, wmOperator *op)
398 {
399         SpaceClip *sc = CTX_wm_space_clip(C);
400         MovieClip *clip = ED_space_clip(sc);
401         MovieTracking *tracking = &clip->tracking;
402         MovieTrackingTrack *act_track = BKE_tracking_active_track(tracking);
403         MovieTrackingMarker *marker;
404         int action = RNA_enum_get(op->ptr, "action");
405         int a;
406
407         if (!act_track)
408                 return OPERATOR_CANCELLED;
409
410         if (action == SEL_TOGGLE) {
411                 action = SEL_SELECT;
412
413                 for (a = 0; a < act_track->markersnr; a++) {
414                         marker = &act_track->markers[a];
415
416                         if (marker->flag & MARKER_GRAPH_SEL) {
417                                 action = SEL_DESELECT;
418                                 break;
419                         }
420                 }
421         }
422
423         for (a = 0; a < act_track->markersnr; a++) {
424                 marker = &act_track->markers[a];
425
426                 switch (action) {
427                         case SEL_SELECT:
428                                 marker->flag |= MARKER_GRAPH_SEL;
429                                 break;
430                         case SEL_DESELECT:
431                                 marker->flag &= ~MARKER_GRAPH_SEL;
432                                 break;
433                         case SEL_INVERT:
434                                 marker->flag ^= MARKER_GRAPH_SEL;
435                                 break;
436                 }
437         }
438
439         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
440
441         return OPERATOR_FINISHED;
442 }
443
444 void CLIP_OT_graph_select_all_markers(wmOperatorType *ot)
445 {
446         /* identifiers */
447         ot->name = "(De)select All Markers";
448         ot->description = "Change selection of all markers of active track";
449         ot->idname = "CLIP_OT_graph_select_all_markers";
450
451         /* api callbacks */
452         ot->exec = graph_select_all_markers_exec;
453         ot->poll = ED_space_clip_graph_poll;
454
455         /* flags */
456         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
457
458         WM_operator_properties_select_all(ot);
459 }
460
461 /******************** delete curve operator ********************/
462
463 static int delete_curve_exec(bContext *C, wmOperator *UNUSED(op))
464 {
465         SpaceClip *sc = CTX_wm_space_clip(C);
466         MovieClip *clip = ED_space_clip(sc);
467         MovieTracking *tracking = &clip->tracking;
468         ListBase *tracksbase = BKE_tracking_get_tracks(tracking);
469         MovieTrackingTrack *act_track = BKE_tracking_active_track(tracking);
470
471         if (act_track)
472                 clip_delete_track(C, clip, tracksbase, act_track);
473
474         return OPERATOR_FINISHED;
475 }
476
477 void CLIP_OT_graph_delete_curve(wmOperatorType *ot)
478 {
479         /* identifiers */
480         ot->name = "Delete Curve";
481         ot->description = "Delete selected curves";
482         ot->idname = "CLIP_OT_graph_delete_curve";
483
484         /* api callbacks */
485         ot->invoke = WM_operator_confirm;
486         ot->exec = delete_curve_exec;
487         ot->poll = ED_space_clip_tracking_poll;
488
489         /* flags */
490         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
491 }
492
493 /******************** delete knot operator ********************/
494
495 static int delete_knot_exec(bContext *C, wmOperator *UNUSED(op))
496 {
497         SpaceClip *sc = CTX_wm_space_clip(C);
498         MovieClip *clip= ED_space_clip(sc);
499         MovieTracking *tracking = &clip->tracking;
500         ListBase *tracksbase = BKE_tracking_get_tracks(tracking);
501         MovieTrackingTrack *act_track = BKE_tracking_active_track(tracking);
502
503         if (act_track) {
504                 int a = 0;
505
506                 while (a < act_track->markersnr) {
507                         MovieTrackingMarker *marker = &act_track->markers[a];
508
509                         if (marker->flag & MARKER_GRAPH_SEL)
510                                 clip_delete_marker(C, clip, tracksbase, act_track, marker);
511                         else
512                                 a++;
513                 }
514         }
515
516         return OPERATOR_FINISHED;
517 }
518
519 void CLIP_OT_graph_delete_knot(wmOperatorType *ot)
520 {
521         /* identifiers */
522         ot->name = "Delete Knot";
523         ot->description = "Delete curve knots";
524         ot->idname = "CLIP_OT_graph_delete_knot";
525
526         /* api callbacks */
527         ot->exec = delete_knot_exec;
528         ot->poll = ED_space_clip_graph_poll;
529
530         /* flags */
531         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
532 }
533
534 /******************** view all operator ********************/
535
536 typedef struct {
537         float min, max;
538 } ViewAllUserData;
539
540 static void view_all_cb(void *userdata, MovieTrackingTrack *UNUSED(track), MovieTrackingMarker *UNUSED(marker),
541                         int UNUSED(coord), float val)
542 {
543         ViewAllUserData *data = (ViewAllUserData *) userdata;
544
545         if (val < data->min)
546                 data->min = val;
547
548         if (val > data->max)
549                 data->max = val;
550 }
551
552 static int view_all_exec(bContext *C, wmOperator *UNUSED(op))
553 {
554         Scene *scene = CTX_data_scene(C);
555         ARegion *ar = CTX_wm_region(C);
556         SpaceClip *sc = CTX_wm_space_clip(C);
557         View2D *v2d = &ar->v2d;
558         ViewAllUserData userdata;
559         float extra;
560
561         userdata.max = -FLT_MAX;
562         userdata.min = FLT_MAX;
563
564         clip_graph_tracking_values_iterate(sc, &userdata, view_all_cb, NULL, NULL);
565
566         /* set extents of view to start/end frames */
567         v2d->cur.xmin = (float) SFRA;
568         v2d->cur.xmax = (float) EFRA;
569
570         if (userdata.min < userdata.max) {
571                 v2d->cur.ymin = userdata.min;
572                 v2d->cur.ymax = userdata.max;
573         }
574         else {
575                 v2d->cur.ymin = -10;
576                 v2d->cur.ymax = 10;
577         }
578
579         /* we need an extra "buffer" factor on either side so that the endpoints are visible */
580         extra = 0.01f * (v2d->cur.xmax - v2d->cur.xmin);
581         v2d->cur.xmin -= extra;
582         v2d->cur.xmax += extra;
583
584         extra = 0.01f * (v2d->cur.ymax - v2d->cur.ymin);
585         v2d->cur.ymin -= extra;
586         v2d->cur.ymax += extra;
587
588         ED_region_tag_redraw(ar);
589
590         return OPERATOR_FINISHED;
591 }
592
593 void CLIP_OT_graph_view_all(wmOperatorType *ot)
594 {
595         /* identifiers */
596         ot->name = "View All";
597         ot->description = "View all curves in editor";
598         ot->idname = "CLIP_OT_graph_view_all";
599
600         /* api callbacks */
601         ot->exec = view_all_exec;
602         ot->poll = ED_space_clip_graph_poll;
603 }
604
605 /******************** jump to current frame operator ********************/
606
607 void ED_clip_graph_center_current_frame(Scene *scene, ARegion *ar)
608 {
609         View2D *v2d = &ar->v2d;
610         float extra = (v2d->cur.xmax - v2d->cur.xmin) / 2.0f;
611
612         /* set extents of view to start/end frames */
613         v2d->cur.xmin = (float)CFRA - extra;
614         v2d->cur.xmax = (float)CFRA + extra;
615 }
616
617 static int center_current_frame_exec(bContext *C, wmOperator *UNUSED(op))
618 {
619         Scene *scene = CTX_data_scene(C);
620         ARegion *ar = CTX_wm_region(C);
621
622         ED_clip_graph_center_current_frame(scene, ar);
623
624         ED_region_tag_redraw(ar);
625
626         return OPERATOR_FINISHED;
627 }
628
629 void CLIP_OT_graph_center_current_frame(wmOperatorType *ot)
630 {
631         /* identifiers */
632         ot->name = "Center Current Frame";
633         ot->description = "Scroll view so current frame would be centered";
634         ot->idname = "CLIP_OT_graph_center_current_frame";
635
636         /* api callbacks */
637         ot->exec = center_current_frame_exec;
638         ot->poll = ED_space_clip_graph_poll;
639 }
640
641 /********************** disable markers operator *********************/
642
643 static int graph_disable_markers_exec(bContext *C, wmOperator *op)
644 {
645         SpaceClip *sc = CTX_wm_space_clip(C);
646         MovieClip *clip = ED_space_clip(sc);
647         MovieTracking *tracking = &clip->tracking;
648         MovieTrackingTrack *act_track = BKE_tracking_active_track(tracking);
649         MovieTrackingMarker *marker;
650         int action = RNA_enum_get(op->ptr, "action");
651         int a;
652
653         if (!act_track || (act_track->flag & TRACK_LOCKED))
654                 return OPERATOR_CANCELLED;
655
656         for (a = 0; a < act_track->markersnr; a++) {
657                 marker = &act_track->markers[a];
658
659                 if (marker->flag & MARKER_GRAPH_SEL) {
660                         if (action==0)
661                                 marker->flag |= MARKER_DISABLED;
662                         else if (action==1)
663                                 marker->flag &= ~MARKER_DISABLED;
664                         else
665                                 marker->flag ^= MARKER_DISABLED;
666                 }
667         }
668
669         DAG_id_tag_update(&clip->id, 0);
670
671         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
672
673         return OPERATOR_FINISHED;
674 }
675
676 void CLIP_OT_graph_disable_markers(wmOperatorType *ot)
677 {
678         static EnumPropertyItem actions_items[] = {
679                         {0, "DISABLE", 0, "Disable", "Disable selected markers"},
680                         {1, "ENABLE", 0, "Enable", "Enable selected markers"},
681                         {2, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"},
682                         {0, NULL, 0, NULL, NULL}
683         };
684
685         /* identifiers */
686         ot->name = "Disable Markers";
687         ot->description = "Disable/enable selected markers";
688         ot->idname = "CLIP_OT_graph_disable_markers";
689
690         /* api callbacks */
691         ot->exec = graph_disable_markers_exec;
692         ot->poll = ED_space_clip_graph_poll;
693
694         /* flags */
695         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
696
697         /* properties */
698         RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Disable action to execute");
699 }