104 ListBase *markers,
Scene *scene,
int mode,
float value,
char side)
116 if (marker->flag &
SELECT) {
121 if ((side ==
'B') || (side ==
'L' && marker->frame < cfra) ||
122 (side ==
'R' && marker->frame >= cfra))
131 marker->frame = cfra +
round_fl_to_int(
float(marker->frame - cfra) * value);
147 float dist, min_dist = 1000000;
151 dist =
fabsf(
float(marker->frame) -
x);
153 if (dist < min_dist) {
184 if (!sel || (marker->flag &
SELECT)) {
185 if (marker->frame <
min) {
188 if (marker->frame >
max) {
206 if (area ==
nullptr) {
252 fabsf(nearest_marker->
frame - frame_at_position);
265 if (only_selected && ((marker->
flag &
SELECT) == 0)) {
308 if (markers ==
nullptr) {
345 if (marker->flag &
SELECT) {
360 if (markers ==
nullptr) {
361 printf(
"No markers list to print debug for\n");
365 printf(
"List of markers follows: -----\n");
369 "\t'%s' on %d at %p with %u\n", marker->name, marker->frame, (
void *)marker, marker->flag);
372 printf(
"End of list ------------------\n");
400 const char *name = marker->
name;
401 uchar final_text_color[4];
405#ifdef DURIAN_CAMERA_SWITCH
408 name =
camera->id.name + 2;
410 final_text_color[3] = 100;
421 rect.
xmin = marker_x + icon_half_width;
422 rect.
xmax = xmax - icon_half_width;
426 UI_fontstyle_draw(fstyle, &rect, name, strlen(name), final_text_color, &fs_params);
436 float viewport_size[4];
456 return (marker->
flag &
SELECT) ? ICON_PMARKER_SEL : ICON_PMARKER;
458#ifdef DURIAN_CAMERA_SWITCH
460 return (marker->
flag &
SELECT) ? ICON_OUTLINER_OB_CAMERA : ICON_CAMERA_DATA;
463 return (marker->
flag &
SELECT) ? ICON_MARKER_HLT : ICON_MARKER;
474 uchar line_color[4], text_color[4];
484 uchar marker_color[4];
533 if (marker->
frame < frame_range[0]) {
536 if (marker->
frame > frame_range[1]) {
554 r_range[1] = v2d->
cur.
xmax + font_width_max;
578 rctf markers_region_rect;
589 int clip_frame_range[2];
604 const int ELEVATED = 0x10;
606 const bool is_elevated = (marker->flag &
SELECT) ||
607 (cfra >= marker->frame &&
608 (marker->next ==
nullptr || cfra < marker->
next->frame));
622 const int xmax = marker->next ? marker->next->frame : clip_frame_range[1] + 1;
624 fstyle, marker, marker->frame * xscale, xmax * xscale,
flag, region->
winy,
false);
633 marker = marker->next;
640 while (next_marker !=
nullptr && (next_marker->
flag & ELEVATED) == 0) {
641 next_marker = next_marker->
next;
644 const int xmax = next_marker ? next_marker->
frame : clip_frame_range[1] + 1;
645 draw_marker(fstyle, marker, marker->frame * xscale, xmax * xscale,
flag, region->
winy,
true);
647 marker = next_marker;
652 marker->flag &= ~ELEVATED;
724 return (markers && markers->
first);
740 if (markers ==
nullptr) {
747 if (marker->
frame == frame) {
759 marker->
frame = frame;
772 ot->name =
"Add Time Marker";
773 ot->description =
"Add a new time marker";
774 ot->idname =
"MARKER_OT_add";
847 marker = marker->
next)
865 if (totmark == 1 && selmarker) {
891 if (markers ==
nullptr) {
895 for (totmark = 0, marker =
static_cast<TimeMarker *
>(markers->
first); marker;
896 marker = marker->
next)
910 mm->
oldframe =
static_cast<int *
>(
MEM_callocN(totmark *
sizeof(
int),
"MarkerMove oldframe"));
919 for (a = 0, marker =
static_cast<TimeMarker *
>(markers->
first); marker; marker = marker->
next) {
960 mm->
evtx =
event->xy[0];
961 mm->
firstx =
event->xy[0];
982#ifdef DURIAN_CAMERA_SWITCH
993 marker = marker->
next)
1004#ifdef DURIAN_CAMERA_SWITCH
1045 bool handled =
false;
1046 switch (event->
type) {
1071 if (!has_numinput) {
1076 if (event->
xy[0] != mm->
evtx) {
1079 mm->
evtx =
event->xy[0];
1128 ot->name =
"Move Time Marker";
1129 ot->description =
"Move selected time marker(s)";
1130 ot->idname =
"MARKER_OT_move";
1143 RNA_def_int(
ot->srna,
"frames", 0, INT_MIN, INT_MAX,
"Frames",
"", INT_MIN, INT_MAX);
1145 ot->srna,
"tweak",
false,
"Tweak",
"Operator has been activated using a click-drag event");
1175 if (markers ==
nullptr) {
1183 if (marker->flag &
SELECT) {
1191 newmarker->
frame = marker->frame;
1194#ifdef DURIAN_CAMERA_SWITCH
1195 newmarker->
camera = marker->camera;
1198 if (marker->prop !=
nullptr) {
1226 ot->name =
"Duplicate Time Marker";
1227 ot->description =
"Duplicate selected time marker(s)";
1228 ot->idname =
"MARKER_OT_duplicate";
1241 RNA_def_int(
ot->srna,
"frames", 0, INT_MIN, INT_MAX,
"Frames",
"", INT_MIN, INT_MAX);
1262 bool wait_to_deselect_others)
1264 TimeMarker *marker, *marker_cycle_selected =
nullptr;
1268 wait_to_deselect_others =
false;
1273 if (marker->
frame == frame) {
1282 if (wait_to_deselect_others && marker_cycle_selected) {
1287 if (extend ==
false) {
1293 if (marker->
frame == frame) {
1308#ifdef DURIAN_CAMERA_SWITCH
1321 if (marker->frame == cfra) {
1322 sel = (marker->flag &
SELECT);
1329 if (marker->camera) {
1330 if (marker->frame == cfra) {
1351 bContext *
C,
const int mval[2],
bool extend,
bool camera,
bool wait_to_deselect_others)
1378 const bool wait_to_deselect_others =
RNA_boolean_get(op->
ptr,
"wait_to_deselect_others");
1380#ifdef DURIAN_CAMERA_SWITCH
1404 ot->name =
"Select Time Marker";
1405 ot->description =
"Select time marker(s)";
1406 ot->idname =
"MARKER_OT_select";
1418 prop =
RNA_def_boolean(
ot->srna,
"extend",
false,
"Extend",
"Extend the selection");
1420#ifdef DURIAN_CAMERA_SWITCH
1421 prop =
RNA_def_boolean(
ot->srna,
"camera",
false,
"Camera",
"Select the camera");
1461 if (tweak && over_marker) {
1477 if (markers ==
nullptr) {
1502 ot->name =
"Marker Box Select";
1503 ot->description =
"Select all time markers using box selection";
1504 ot->idname =
"MARKER_OT_select_box";
1522 ot->srna,
"tweak",
false,
"Tweak",
"Operator has been activated using a click-drag event");
1535 if (markers ==
nullptr) {
1551 ot->name =
"(De)select all Markers";
1552 ot->description =
"Change selection of all time markers";
1553 ot->idname =
"MARKER_OT_select_all";
1580 {0,
nullptr, 0,
nullptr,
nullptr},
1590 if (markers ==
nullptr) {
1628 ot->name =
"Select Markers Before/After Current Frame";
1629 ot->description =
"Select markers on and left/right of the current frame";
1630 ot->idname =
"MARKER_OT_select_leftright";
1658 bool changed =
false;
1660 if (markers ==
nullptr) {
1664 for (marker =
static_cast<TimeMarker *
>(markers->
first); marker; marker = nmarker) {
1665 nmarker = marker->
next;
1667 if (marker->
prop !=
nullptr) {
1689 IFACE_(
"Delete selected markers?"),
1701 ot->name =
"Delete Markers";
1702 ot->description =
"Delete selected time marker(s)";
1703 ot->idname =
"MARKER_OT_delete";
1748 C, op, event,
IFACE_(
"Rename Selected Time Marker"),
IFACE_(
"Rename"));
1754 ot->name =
"Rename Marker";
1755 ot->description =
"Rename first selected time marker";
1756 ot->idname =
"MARKER_OT_rename";
1768 ot->srna,
"name",
"RenamedMarker",
sizeof(
TimeMarker::name),
"Name",
"New name for marker");
1774 "Ensure that new name is unique within collection of markers");
1792 if (scene_to ==
nullptr) {
1809 if (marker->flag &
SELECT) {
1811 marker_new->
prev = marker_new->
next =
nullptr;
1825 ot->name =
"Copy Markers to Scene";
1826 ot->description =
"Copy selected markers to another scene";
1827 ot->idname =
"MARKER_OT_make_links_scene";
1850#ifdef DURIAN_CAMERA_SWITCH
1861 if (ob ==
nullptr) {
1867 if (markers ==
nullptr) {
1872 if ((marker ==
nullptr) || (marker->
frame != scene->
r.
cfra)) {
1907 ot->name =
"Bind Camera to Markers";
1908 ot->description =
"Bind the selected camera to a marker on the current frame";
1909 ot->idname =
"MARKER_OT_camera_bind";
1939#ifdef DURIAN_CAMERA_SWITCH
bScreen * CTX_wm_screen(const bContext *C)
void CTX_wm_operator_poll_msg_set(bContext *C, const char *msg)
ScrArea * CTX_wm_area(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
SpaceLink * CTX_wm_space_data(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
ToolSettings * CTX_data_tool_settings(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
enum eContextObjectMode CTX_data_mode_enum(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
void IDP_FreePropertyContent(IDProperty *prop)
IDProperty * IDP_CopyProperty(const IDProperty *prop) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
void BKE_view_layer_base_deselect_all(const Scene *scene, ViewLayer *view_layer)
Base * BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
void BKE_report(ReportList *reports, eReportType type, const char *message)
bool BKE_scene_camera_switch_update(Scene *scene)
void BKE_screen_view3d_scene_sync(bScreen *screen, Scene *scene)
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
#define LISTBASE_FOREACH(type, var, list)
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
#define LISTBASE_CIRCULAR_FORWARD_BEGIN(type, lb, lb_iter, lb_init)
void void void void void void BLI_duplicatelist(struct ListBase *dst, const struct ListBase *src) ATTR_NONNULL(1
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
void void BLI_listbase_sort(struct ListBase *listbase, int(*cmp)(const void *, const void *)) ATTR_NONNULL(1
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
#define LISTBASE_CIRCULAR_FORWARD_END(type, lb, lb_iter, lb_init)
MINLINE int round_fl_to_int(float a)
MINLINE void copy_v4_v4_uchar(unsigned char r[4], const unsigned char a[4])
bool BLI_rctf_isect_x(const rctf *rect, float x)
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
#define STRNCPY(dst, src)
#define SNPRINTF(dst, format,...)
#define SET_FLAG_FROM_TEST(value, test, flag)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
@ SACTION_POSEMARKERS_SHOW
Object is a sort of wrapper for general info.
void ED_area_status_text(ScrArea *area, const char *str)
#define SEL_OP_USE_PRE_DESELECT(sel_op)
void apply_keyb_grid(bool shift, bool ctrl, float *val, float fac1, float fac2, float fac3, int invert)
void GPU_matrix_scale_2f(float x, float y)
@ GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR
@ GPU_SHADER_3D_UNIFORM_COLOR
void GPU_blend(eGPUBlend blend)
void GPU_line_width(float width)
void GPU_viewport_size_get_f(float coords[4])
Read Guarded memory(de)allocation.
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a color
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between camera
const EnumPropertyItem * RNA_scene_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *prop, bool *r_free)
void UI_fontstyle_draw(const uiFontStyle *fs, const rcti *rect, const char *str, size_t str_len, const uchar col[4], const uiFontStyleDraw_Params *fs_params)
#define UI_NO_ICON_OVERLAY_TEXT
void UI_icon_draw_ex(float x, float y, int icon_id, float aspect, float alpha, float desaturate, const uchar mono_color[4], bool mono_border, const IconTextOverlay *text_overlay, const bool inverted=false)
@ TH_TIME_SCRUB_BACKGROUND
@ TH_TIME_MARKER_LINE_SELECTED
void UI_GetThemeColor4ubv(int colorid, unsigned char col[4])
#define UI_MARKER_MARGIN_Y
View2D * UI_view2d_fromcontext(const bContext *C)
void UI_view2d_scale_get(const View2D *v2d, float *r_x, float *r_y)
float UI_view2d_region_to_view_x(const View2D *v2d, float x)
void UI_view2d_region_to_view_rctf(const View2D *v2d, const rctf *rect_src, rctf *rect_dst) ATTR_NONNULL()
float UI_view2d_scale_get_x(const View2D *v2d)
bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
static int ed_marker_box_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static ListBase * context_get_markers(Scene *scene, ScrArea *area)
static void draw_markers_background(const rctf *rect)
static void ed_marker_duplicate_apply(bContext *C)
static int markers_frame_sort(const void *a, const void *b)
void ED_keymap_marker(wmKeyConfig *keyconf)
static void ed_marker_move_update_header(bContext *C, wmOperator *op)
static void ed_marker_move_exit(bContext *C, wmOperator *op)
static int ed_marker_move_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void marker_color_get(const TimeMarker *marker, uchar *r_text_color, uchar *r_line_color)
static int ed_marker_rename_invoke(bContext *C, wmOperator *op, const wmEvent *event)
eMarkers_LeftRightSelect_Mode
static bool ED_operator_markers_region_active(bContext *C)
static int ed_marker_select_exec(bContext *C, wmOperator *op)
int ED_markers_post_apply_transform(ListBase *markers, Scene *scene, int mode, float value, char side)
static void MARKER_OT_move(wmOperatorType *ot)
static int ed_marker_make_links_scene_exec(bContext *C, wmOperator *op)
static int ed_marker_camera_bind_exec(bContext *C, wmOperator *op)
static void select_marker_camera_switch(bContext *C, bool camera, bool extend, ListBase *markers, int cfra)
static void get_marker_region_rect(View2D *v2d, rctf *r_rect)
static int ed_marker_delete_exec(bContext *C, wmOperator *)
static void MARKER_OT_select_leftright(wmOperatorType *ot)
ListBase * ED_animcontext_get_markers(const bAnimContext *ac)
static void MARKER_OT_add(wmOperatorType *ot)
static void draw_marker_line(const uchar *color, int xpos, int ymin, int ymax)
static int ed_marker_select_leftright_exec(bContext *C, wmOperator *op)
void ED_markers_get_minmax(ListBase *markers, short sel, float *r_first, float *r_last)
static const EnumPropertyItem prop_markers_select_leftright_modes[]
static void add_marker_to_cfra_elem(ListBase *lb, TimeMarker *marker, const bool only_selected)
static bool ed_markers_poll_selected_no_locked_markers(bContext *C)
static int ed_marker_duplicate_exec(bContext *C, wmOperator *op)
static int ed_marker_rename_exec(bContext *C, wmOperator *op)
void ED_operatortypes_marker()
int ED_markers_find_nearest_marker_time(ListBase *markers, float x)
static void draw_marker_name(const uchar *text_color, const uiFontStyle *fstyle, TimeMarker *marker, float marker_x, float xmax, float text_y)
static void MARKER_OT_camera_bind(wmOperatorType *ot)
static void deselect_markers(ListBase *markers)
static bool ed_markers_poll_selected_markers(bContext *C)
static int ed_marker_add_exec(bContext *C, wmOperator *)
static bool ed_marker_move_init(bContext *C, wmOperator *op)
static void MARKER_OT_duplicate(wmOperatorType *ot)
static void ed_marker_move_apply(bContext *C, wmOperator *op)
static int ed_marker_delete_invoke(bContext *C, wmOperator *op, const wmEvent *)
static void ED_markers_select_leftright(bAnimContext *ac, const eMarkers_LeftRightSelect_Mode mode, const bool extend)
static void MARKER_OT_delete(wmOperatorType *ot)
static void draw_marker(const uiFontStyle *fstyle, TimeMarker *marker, int xpos, int xmax, int flag, int region_height, bool is_elevated)
static bool region_position_is_over_marker(View2D *v2d, ListBase *markers, float region_x)
static void MARKER_OT_select_all(wmOperatorType *ot)
static void MARKER_OT_rename(wmOperatorType *ot)
static int ed_marker_move_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void MARKER_OT_make_links_scene(wmOperatorType *ot)
static void MARKER_OT_select(wmOperatorType *ot)
static bool marker_is_in_frame_range(TimeMarker *marker, const int frame_range[2])
static bool ed_markers_poll_markers_exist(bContext *C)
ListBase * ED_context_get_markers(const bContext *C)
static int ed_marker_box_select_exec(bContext *C, wmOperator *op)
TimeMarker * ED_markers_find_nearest_marker(ListBase *markers, float x)
static void MARKER_OT_select_box(wmOperatorType *ot)
static int ed_marker_move_exec(bContext *C, wmOperator *op)
static int ed_marker_select(bContext *C, const int mval[2], bool extend, bool camera, bool wait_to_deselect_others)
static bool ed_marker_move_use_time(MarkerMove *mm)
TimeMarker * ED_markers_get_first_selected(ListBase *markers)
void ED_markers_deselect_all(ListBase *markers, int action)
void ED_markers_make_cfra_list(ListBase *markers, ListBase *lb, const bool only_selected)
static int ed_marker_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void debug_markers_print_list(ListBase *markers)
static int select_timeline_marker_frame(ListBase *markers, int frame, bool extend, bool wait_to_deselect_others)
static int marker_get_icon_id(TimeMarker *marker, int flag)
static void ed_marker_move_cancel(bContext *C, wmOperator *op)
static void get_marker_clip_frame_range(View2D *v2d, float xscale, int r_range[2])
static int ed_marker_select_all_exec(bContext *C, wmOperator *op)
void ED_markers_draw(const bContext *C, int flag)
local_group_size(16, 16) .push_constant(Type b
draw_view in_light_buf[] float
void MEM_freeN(void *vmemh)
void *(* MEM_callocN)(size_t len, const char *str)
void *(* MEM_dupallocN)(const void *vmemh)
ccl_device_inline float4 select(const int4 mask, const float4 a, const float4 b)
void base_activate(bContext *C, Base *base)
void base_select(Base *base, eObjectSelect_Mode mode)
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
int RNA_int_get(PointerRNA *ptr, const char *name)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, const int maxlen, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
const EnumPropertyItem rna_enum_dummy_NULL_items[]
struct ToolSettings * toolsettings
struct ReportList * reports
bool WM_event_is_modal_drag_exit(const wmEvent *event, const short init_event_type, const short init_event_val)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
int WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmKeyMap * WM_keymap_ensure(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid)
void WM_operator_properties_gesture_box(wmOperatorType *ot)
void WM_operator_properties_confirm_or_exec(wmOperatorType *ot)
void WM_operator_properties_select_operation_simple(wmOperatorType *ot)
void WM_operator_properties_border_to_rctf(wmOperator *op, rctf *r_rect)
void WM_operator_properties_generic_select(wmOperatorType *ot)
void WM_operator_properties_select_all(wmOperatorType *ot)
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))
int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *)
int WM_operator_confirm_ex(bContext *C, wmOperator *op, const char *title, const char *message, const char *confirm_text, int icon, bool cancel_default)
int WM_operator_props_popup_confirm_ex(bContext *C, wmOperator *op, const wmEvent *, std::optional< std::string > title, std::optional< std::string > confirm_text, const bool cancel_default)
int WM_generic_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int WM_generic_select_modal(bContext *C, wmOperator *op, const wmEvent *event)