From ec7186627726885acc4487f5f44177281c0f3fc6 Mon Sep 17 00:00:00 2001 From: Elliot Smith Date: Wed, 11 Aug 2010 10:34:49 +0100 Subject: [PATCH 01/15] cookbook: Added basic mouse scroll recipe Added a recipe explaining the basics of mouse scroll events. --- doc/cookbook/events.xml | 115 ++++++++++++++++++++ doc/cookbook/examples/events-mouse-scroll.c | 108 ++++++++++++++++++ 2 files changed, 223 insertions(+) create mode 100644 doc/cookbook/examples/events-mouse-scroll.c diff --git a/doc/cookbook/events.xml b/doc/cookbook/events.xml index a4cc5c118..dbb76c4b5 100644 --- a/doc/cookbook/events.xml +++ b/doc/cookbook/events.xml @@ -345,4 +345,119 @@ clutter_stage_set_key_focus (stage, actor); + +
+ Detecting mouse wheel scrolling on an actor + +
+ Problem + + You want to detect when the mouse wheel is scrolled on an + actor. +
+ +
+ Solution + + Connect a callback handler to the scroll-event signal + for an actor. + + First, ensure that the actor is reactive (i.e. will + respond to events): + + + + + + + + Next, connect a callback handler to the + scroll-event signal of the actor: + + + + + + + + Finally, create a callback handler to examine the scroll + event and respond to it: + + + + + + +
+ +
+ Discussion + + A standard mouse wheel will only return up and + down movements; but in cases where the mouse has left and + right scrolling (e.g. a trackball mouse), left and right scroll + events may also be emitted. + +
+ Creating a full scrollable actor + + While the simple outline above explains the basics + of how to connect to scroll events, it doesn't do much to + help with really implementing a scrollable actor. That's what + we'll do in this section. The full code for the example we'll + walk through here is available in this + later section. +
+
+ +
+ Full example + + + Mouse scrolling over <type>ClutterActor</type> + + + a code sample should be here... but isn't + + + +
+ +
diff --git a/doc/cookbook/examples/events-mouse-scroll.c b/doc/cookbook/examples/events-mouse-scroll.c new file mode 100644 index 000000000..150848224 --- /dev/null +++ b/doc/cookbook/examples/events-mouse-scroll.c @@ -0,0 +1,108 @@ +/* + * Scroll in the y axis by moving an enclosed box (with layout) + * up and down inside a "letterbox" in the center of the stage + * + * gcc -g -O0 -DTESTS_DATA_DIR="\"/home/ell/dev/clutter_src/tests/data\"" -o events-mouse-scroll events-mouse-scroll.c `pkg-config --libs --cflags clutter-1.0 glib-2.0` -lm + */ +#include + +#define STAGE_HEIGHT 400 +#define STAGE_WIDTH STAGE_HEIGHT * 2 +#define SCROLL_AMOUNT STAGE_HEIGHT * 0.2 + +static const ClutterColor stage_color = { 0x33, 0x33, 0x55, 0xff }; +static const ClutterColor box_color = { 0xaa, 0xaa, 0x55, 0xff }; + +static gboolean +_scroll_event_cb (ClutterActor *scroll, + ClutterEvent *event, + gpointer user_data) +{ + ClutterActor *viewport = CLUTTER_ACTOR (user_data); + + gfloat y = clutter_actor_get_y (viewport); + + ClutterScrollDirection direction; + direction = clutter_event_get_scroll_direction (event); + + switch (direction) + { + case CLUTTER_SCROLL_UP: + y -= SCROLL_AMOUNT; + break; + case CLUTTER_SCROLL_DOWN: + y += SCROLL_AMOUNT; + break; + } + + y = CLAMP (y, + clutter_actor_get_height (scroll) + + clutter_actor_get_y (scroll) + - clutter_actor_get_height (viewport), + 0.0); + + clutter_actor_animate (viewport, + CLUTTER_EASE_OUT_CUBIC, + 300, + "y", y, + NULL); + + return TRUE; +} + +int +main (int argc, char *argv[]) +{ + ClutterActor *stage; + ClutterActor *scroll; + ClutterActor *viewport; + ClutterActor *texture; + + clutter_init (&argc, &argv); + + stage = clutter_stage_get_default (); + clutter_actor_set_size (stage, STAGE_WIDTH, STAGE_HEIGHT); + clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); + g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); + + /* the "letterbox" which the viewport is scrolled within */ + scroll = clutter_group_new (); + clutter_actor_set_size (scroll, STAGE_WIDTH, STAGE_HEIGHT * 0.75); + clutter_actor_add_constraint (scroll, clutter_align_constraint_new (stage, CLUTTER_BIND_Y, 0.5)); + clutter_actor_set_reactive (scroll, TRUE); + + /* this clips all actors inside the scroll group to that group's allocation */ + clutter_actor_set_clip_to_allocation (scroll, TRUE); + + viewport = clutter_box_new (clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER, + CLUTTER_BIN_ALIGNMENT_CENTER)); + clutter_box_set_color (CLUTTER_BOX (viewport), &box_color); + + /* the actor to scroll */ + texture = clutter_texture_new (); + clutter_actor_set_request_mode (texture, CLUTTER_REQUEST_HEIGHT_FOR_WIDTH); + clutter_texture_set_keep_aspect_ratio (CLUTTER_TEXTURE (texture), + TRUE); + + /* the box resizes itself to fit this texture */ + clutter_actor_set_width (texture, STAGE_WIDTH); + + clutter_texture_set_from_file (CLUTTER_TEXTURE (texture), + TESTS_DATA_DIR "/redhand.png", + NULL); + + g_signal_connect (scroll, + "scroll-event", + G_CALLBACK (_scroll_event_cb), + viewport); + + clutter_container_add_actor (CLUTTER_CONTAINER (viewport), texture); + clutter_container_add_actor (CLUTTER_CONTAINER (scroll), viewport); + clutter_container_add_actor (CLUTTER_CONTAINER (stage), scroll); + + clutter_actor_show (stage); + + clutter_main (); + + return 0; +} From 5e268e0bbb0e2dcbf6edfbf3e1725a3e61e8dbd0 Mon Sep 17 00:00:00 2001 From: Elliot Smith Date: Wed, 11 Aug 2010 11:03:02 +0100 Subject: [PATCH 02/15] cookbook: Added xmlns for XInclude to events docbook file --- doc/cookbook/events.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/cookbook/events.xml b/doc/cookbook/events.xml index dbb76c4b5..65694a3ab 100644 --- a/doc/cookbook/events.xml +++ b/doc/cookbook/events.xml @@ -1,7 +1,7 @@ - + Events From 241ceab73cbc1fa0a1f7c19ad95fdd54b1c26864 Mon Sep 17 00:00:00 2001 From: Elliot Smith Date: Wed, 11 Aug 2010 11:03:37 +0100 Subject: [PATCH 03/15] cookbook: Cleaned up redundant comments in code example Removed comments which are only relevant in my local build environment. --- doc/cookbook/examples/events-mouse-scroll.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/doc/cookbook/examples/events-mouse-scroll.c b/doc/cookbook/examples/events-mouse-scroll.c index 150848224..46dbaf1ec 100644 --- a/doc/cookbook/examples/events-mouse-scroll.c +++ b/doc/cookbook/examples/events-mouse-scroll.c @@ -1,9 +1,3 @@ -/* - * Scroll in the y axis by moving an enclosed box (with layout) - * up and down inside a "letterbox" in the center of the stage - * - * gcc -g -O0 -DTESTS_DATA_DIR="\"/home/ell/dev/clutter_src/tests/data\"" -o events-mouse-scroll events-mouse-scroll.c `pkg-config --libs --cflags clutter-1.0 glib-2.0` -lm - */ #include #define STAGE_HEIGHT 400 From f1312e118d21c293625754248c07fa1168a1732c Mon Sep 17 00:00:00 2001 From: Elliot Smith Date: Wed, 11 Aug 2010 11:09:04 +0100 Subject: [PATCH 04/15] cookbook: Build mouse scroll example with cookbook --- doc/cookbook/examples/.gitignore | 1 + doc/cookbook/examples/Makefile.am | 2 ++ 2 files changed, 3 insertions(+) diff --git a/doc/cookbook/examples/.gitignore b/doc/cookbook/examples/.gitignore index 29c14b0f1..6d18dba94 100644 --- a/doc/cookbook/examples/.gitignore +++ b/doc/cookbook/examples/.gitignore @@ -5,3 +5,4 @@ /textures-sub-texture /layouts-stacking /layouts-stacking-diff-sized-actors +/events-mouse-scroll diff --git a/doc/cookbook/examples/Makefile.am b/doc/cookbook/examples/Makefile.am index 2369e7a0f..026df7d26 100644 --- a/doc/cookbook/examples/Makefile.am +++ b/doc/cookbook/examples/Makefile.am @@ -10,6 +10,7 @@ noinst_PROGRAMS = \ textures-sub-texture \ layouts-stacking \ layouts-stacking-diff-sized-actors \ + events-mouse-scroll \ $(NULL) INCLUDES = \ @@ -38,3 +39,4 @@ textures_split_go_SOURCES = textures-split-go.c textures_sub_texture_SOURCES = textures-sub-texture.c layouts_stacking_SOURCES = layouts-stacking.c layouts_stacking_diff_sized_actors_SOURCES = layouts-stacking-diff-sized-actors.c +events_mouse_scroll_SOURCES = events-mouse-scroll.c From 0f919fcbe3b8c5afed58e082c2dd7e14756b207c Mon Sep 17 00:00:00 2001 From: Elliot Smith Date: Wed, 11 Aug 2010 11:10:53 +0100 Subject: [PATCH 05/15] cookbook: Handle all possible mouse scroll directions Added empty cases for MOUSE_SCROLL_LEFT and MOUSE_SCROLL_RIGHT to the scroll-event signal handler in the example code. --- doc/cookbook/examples/events-mouse-scroll.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/cookbook/examples/events-mouse-scroll.c b/doc/cookbook/examples/events-mouse-scroll.c index 46dbaf1ec..b9c1c31c5 100644 --- a/doc/cookbook/examples/events-mouse-scroll.c +++ b/doc/cookbook/examples/events-mouse-scroll.c @@ -27,6 +27,9 @@ _scroll_event_cb (ClutterActor *scroll, case CLUTTER_SCROLL_DOWN: y += SCROLL_AMOUNT; break; + case CLUTTER_SCROLL_LEFT: + case CLUTTER_SCROLL_RIGHT: + break; } y = CLAMP (y, From e216771a86d985631c2ee1182f1ae7c240e5c28d Mon Sep 17 00:00:00 2001 From: Elliot Smith Date: Wed, 11 Aug 2010 11:14:54 +0100 Subject: [PATCH 06/15] cookbook: Improved wording and formatting in mouse scroll intro. --- doc/cookbook/events.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/cookbook/events.xml b/doc/cookbook/events.xml index 65694a3ab..2e25d161d 100644 --- a/doc/cookbook/events.xml +++ b/doc/cookbook/events.xml @@ -359,8 +359,8 @@ clutter_stage_set_key_focus (stage, actor);
Solution - Connect a callback handler to the scroll-event signal - for an actor. + Connect a callback handler to the scroll-event + signal of an actor. First, ensure that the actor is reactive (i.e. will respond to events): From 5e0bc919c305e1825bba75277df883c231f65837 Mon Sep 17 00:00:00 2001 From: Elliot Smith Date: Wed, 11 Aug 2010 14:39:22 +0100 Subject: [PATCH 07/15] cookbook: Simplified full scroll example Removed the layout and box to simplify the scrollable actor example. --- doc/cookbook/examples/events-mouse-scroll.c | 69 +++++++++++---------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/doc/cookbook/examples/events-mouse-scroll.c b/doc/cookbook/examples/events-mouse-scroll.c index b9c1c31c5..71d66d5a2 100644 --- a/doc/cookbook/examples/events-mouse-scroll.c +++ b/doc/cookbook/examples/events-mouse-scroll.c @@ -1,20 +1,19 @@ #include #define STAGE_HEIGHT 400 -#define STAGE_WIDTH STAGE_HEIGHT * 2 -#define SCROLL_AMOUNT STAGE_HEIGHT * 0.2 +#define STAGE_WIDTH STAGE_HEIGHT +#define SCROLL_AMOUNT STAGE_HEIGHT * 0.125 static const ClutterColor stage_color = { 0x33, 0x33, 0x55, 0xff }; -static const ClutterColor box_color = { 0xaa, 0xaa, 0x55, 0xff }; static gboolean -_scroll_event_cb (ClutterActor *scroll, +_scroll_event_cb (ClutterActor *viewport, ClutterEvent *event, gpointer user_data) { - ClutterActor *viewport = CLUTTER_ACTOR (user_data); + ClutterActor *scrollable = CLUTTER_ACTOR (user_data); - gfloat y = clutter_actor_get_y (viewport); + gfloat y = clutter_actor_get_y (scrollable); ClutterScrollDirection direction; direction = clutter_event_get_scroll_direction (event); @@ -33,12 +32,11 @@ _scroll_event_cb (ClutterActor *scroll, } y = CLAMP (y, - clutter_actor_get_height (scroll) - + clutter_actor_get_y (scroll) - - clutter_actor_get_height (viewport), + clutter_actor_get_height (viewport) + - clutter_actor_get_height (scrollable), 0.0); - clutter_actor_animate (viewport, + clutter_actor_animate (scrollable, CLUTTER_EASE_OUT_CUBIC, 300, "y", y, @@ -51,7 +49,6 @@ int main (int argc, char *argv[]) { ClutterActor *stage; - ClutterActor *scroll; ClutterActor *viewport; ClutterActor *texture; @@ -62,40 +59,44 @@ main (int argc, char *argv[]) clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); - /* the "letterbox" which the viewport is scrolled within */ - scroll = clutter_group_new (); - clutter_actor_set_size (scroll, STAGE_WIDTH, STAGE_HEIGHT * 0.75); - clutter_actor_add_constraint (scroll, clutter_align_constraint_new (stage, CLUTTER_BIND_Y, 0.5)); - clutter_actor_set_reactive (scroll, TRUE); - - /* this clips all actors inside the scroll group to that group's allocation */ - clutter_actor_set_clip_to_allocation (scroll, TRUE); - - viewport = clutter_box_new (clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER, - CLUTTER_BIN_ALIGNMENT_CENTER)); - clutter_box_set_color (CLUTTER_BOX (viewport), &box_color); - - /* the actor to scroll */ + /* the scrollable actor */ texture = clutter_texture_new (); - clutter_actor_set_request_mode (texture, CLUTTER_REQUEST_HEIGHT_FOR_WIDTH); clutter_texture_set_keep_aspect_ratio (CLUTTER_TEXTURE (texture), TRUE); - /* the box resizes itself to fit this texture */ - clutter_actor_set_width (texture, STAGE_WIDTH); + /* set the texture's height so it's as tall as the stage */ + clutter_actor_set_request_mode (texture, CLUTTER_REQUEST_WIDTH_FOR_HEIGHT); + clutter_actor_set_height (texture, STAGE_HEIGHT); clutter_texture_set_from_file (CLUTTER_TEXTURE (texture), TESTS_DATA_DIR "/redhand.png", NULL); - g_signal_connect (scroll, + /* the viewport which the box is scrolled within */ + viewport = clutter_group_new (); + + /* viewport is shorter than the stage */ + clutter_actor_set_size (viewport, STAGE_WIDTH, STAGE_HEIGHT * 0.5); + + /* align the viewport to the center of the stage's y axis */ + clutter_actor_add_constraint (viewport, clutter_align_constraint_new (stage, CLUTTER_BIND_Y, 0.5)); + + /* viewport needs to respond to scroll events */ + clutter_actor_set_reactive (viewport, TRUE); + + /* clip all actors inside the viewport to that group's allocation */ + clutter_actor_set_clip_to_allocation (viewport, TRUE); + + /* put the texture inside the viewport */ + clutter_container_add_actor (CLUTTER_CONTAINER (viewport), texture); + + /* add the viewport to the stage */ + clutter_container_add_actor (CLUTTER_CONTAINER (stage), viewport); + + g_signal_connect (viewport, "scroll-event", G_CALLBACK (_scroll_event_cb), - viewport); - - clutter_container_add_actor (CLUTTER_CONTAINER (viewport), texture); - clutter_container_add_actor (CLUTTER_CONTAINER (scroll), viewport); - clutter_container_add_actor (CLUTTER_CONTAINER (stage), scroll); + texture); clutter_actor_show (stage); From 57ba89c8de1e85d52f3e6d73dade472c0da7f22e Mon Sep 17 00:00:00 2001 From: Elliot Smith Date: Wed, 11 Aug 2010 14:41:42 +0100 Subject: [PATCH 08/15] cookbook: Fixed link to example in mouse scroll recipe --- doc/cookbook/events.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/cookbook/events.xml b/doc/cookbook/events.xml index 2e25d161d..9b8050042 100644 --- a/doc/cookbook/events.xml +++ b/doc/cookbook/events.xml @@ -441,8 +441,9 @@ _scroll_event_cb (ClutterActor *actor, of how to connect to scroll events, it doesn't do much to help with really implementing a scrollable actor. That's what we'll do in this section. The full code for the example we'll - walk through here is available in this - later section. + walk through here is available + in this later + section.
From f568a68ee16ce7f59596bd1336f37eee1667b7a1 Mon Sep 17 00:00:00 2001 From: Elliot Smith Date: Wed, 11 Aug 2010 16:54:28 +0100 Subject: [PATCH 09/15] cookbook: Added walk through of code example for mouse scroll Modified the mouse scroll example to fit better with the tutorial walkthrough. Added a stepped walkthrough of the scrollable actor code example. --- doc/cookbook/events.xml | 224 +++++++++++++++++++- doc/cookbook/examples/events-mouse-scroll.c | 33 ++- 2 files changed, 243 insertions(+), 14 deletions(-) diff --git a/doc/cookbook/events.xml b/doc/cookbook/events.xml index 9b8050042..64d6a26d0 100644 --- a/doc/cookbook/events.xml +++ b/doc/cookbook/events.xml @@ -435,15 +435,225 @@ _scroll_event_cb (ClutterActor *actor, events may also be emitted.
- Creating a full scrollable actor + Creating a scrolling viewport for an actor While the simple outline above explains the basics of how to connect to scroll events, it doesn't do much to - help with really implementing a scrollable actor. That's what - we'll do in this section. The full code for the example we'll - walk through here is available - in this later - section. + help with really implementing scrolling + over an actor. That's what we'll do in this section. + + + The full code for the example we'll walk through here is + available in this later + section. + + + Scrolling over an actor actually requires coordination + between two components: + + + + + Scrollable actor + An actor which is too large to fit on the stage + or inside the area of the UI assigned to it (otherwise + there's no need to scroll over it...). + + + + + Viewport + This displays a cropped view of part of the scrollable + actor, revealing different parts of it as scroll events + occur. + + + + + Here are the steps required to set up the two actors: + + + + Create the scrollable actor; it should be larger + than the scrollview. This example uses a ClutterTexture, + but any ClutterActor will work: + + +/* get image file path, set up stage etc. */ + +ClutterActor *texture; +texture = clutter_texture_new (); +clutter_texture_set_keep_aspect_ratio (CLUTTER_TEXTURE (texture), + TRUE); + +/* + * set the texture's height so it's as tall as the stage + * (STAGE_HEIGHT is define'd at the top of the file); + * see this recipe + * for more about loading images into textures + */ +clutter_actor_set_request_mode (texture, CLUTTER_REQUEST_WIDTH_FOR_HEIGHT); +clutter_actor_set_height (texture, STAGE_HEIGHT); + +/* load the image file */ +clutter_texture_set_from_file (CLUTTER_TEXTURE (texture), + image_file_path, + NULL); + + + + + + + Create the viewport. The simplest way to do + this is with a ClutterGroup: + + + + + + + + The key here is calling + clutter_actor_set_clip_to_allocation (viewport, TRUE). + This configures the viewport group so + that any of its children are clipped: i.e. only the area of + the children which fits inside the group is visible. This + in turn requires setting an explicit size on the group, + rather than allowing it to size itself to fit its + children (the default). + + + + + Put the scrollable actor into the scroll view and + the scroll view into its container (in this case, + the default stage): + + + +clutter_container_add_actor (CLUTTER_CONTAINER (viewport), texture); + +clutter_container_add_actor (CLUTTER_CONTAINER (stage), viewport); + + + + + + + Create a callback handler for scroll event signals + emitted by the viewport: + + + + + + + + The approach taken here is to move the scrollable + actor up, relative to the viewport. Initially, the + scrollable will have a y coordinate value + of 0.0 (it is aligned to the top of the viewport). + Scrolling up subtracts from the + y coordinate (down to a minumum of + viewport_height - scrollable_height). This moves + the top of the scrollable "outside" the clip area of the + viewport; simultaneously, more of the bottom part of the + scrollable moves into the clip area, becoming visible. + + Scrolling down adds to the y coordinate + (but only up to a maximum value of 0.0). + + + + Connect the callback handler to the signal; note + that we pass the scrollable (the texture) to the callback, + as we're moving the texture inside the viewport to + create the scrolling effect: + + + +g_signal_connect (viewport, + "scroll-event", + G_CALLBACK (_scroll_event_cb), + texture); + + + + + +
@@ -451,7 +661,7 @@ _scroll_event_cb (ClutterActor *actor, Full example - Mouse scrolling over <type>ClutterActor</type> + Mouse scrolling over a <type>ClutterActor</type> a code sample should be here... but isn't diff --git a/doc/cookbook/examples/events-mouse-scroll.c b/doc/cookbook/examples/events-mouse-scroll.c index 71d66d5a2..08980f939 100644 --- a/doc/cookbook/examples/events-mouse-scroll.c +++ b/doc/cookbook/examples/events-mouse-scroll.c @@ -4,8 +4,6 @@ #define STAGE_WIDTH STAGE_HEIGHT #define SCROLL_AMOUNT STAGE_HEIGHT * 0.125 -static const ClutterColor stage_color = { 0x33, 0x33, 0x55, 0xff }; - static gboolean _scroll_event_cb (ClutterActor *viewport, ClutterEvent *event, @@ -13,6 +11,13 @@ _scroll_event_cb (ClutterActor *viewport, { ClutterActor *scrollable = CLUTTER_ACTOR (user_data); + gfloat viewport_height = clutter_actor_get_height (viewport); + gfloat scrollable_height = clutter_actor_get_height (scrollable); + + /* no need to scroll if the scrollable is shorter than the viewport */ + if (scrollable_height < viewport_height) + return TRUE; + gfloat y = clutter_actor_get_y (scrollable); ClutterScrollDirection direction; @@ -26,14 +31,23 @@ _scroll_event_cb (ClutterActor *viewport, case CLUTTER_SCROLL_DOWN: y += SCROLL_AMOUNT; break; + + /* we're only interested in up and down */ case CLUTTER_SCROLL_LEFT: case CLUTTER_SCROLL_RIGHT: break; } + /* + * the CLAMP macro returns a value for the first argument + * that falls within the range specified by the second and + * third arguments + * + * we allow the scrollable's y position to be decremented to the point + * where its base is aligned with the base of the viewport + */ y = CLAMP (y, - clutter_actor_get_height (viewport) - - clutter_actor_get_height (scrollable), + viewport_height - scrollable_height, 0.0); clutter_actor_animate (scrollable, @@ -48,6 +62,13 @@ _scroll_event_cb (ClutterActor *viewport, int main (int argc, char *argv[]) { + gchar *image_file_path = TESTS_DATA_DIR "/redhand.png"; + + if (argc > 1) + { + image_file_path = argv[1]; + } + ClutterActor *stage; ClutterActor *viewport; ClutterActor *texture; @@ -56,8 +77,6 @@ main (int argc, char *argv[]) stage = clutter_stage_get_default (); clutter_actor_set_size (stage, STAGE_WIDTH, STAGE_HEIGHT); - clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); - g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); /* the scrollable actor */ texture = clutter_texture_new (); @@ -69,7 +88,7 @@ main (int argc, char *argv[]) clutter_actor_set_height (texture, STAGE_HEIGHT); clutter_texture_set_from_file (CLUTTER_TEXTURE (texture), - TESTS_DATA_DIR "/redhand.png", + image_file_path, NULL); /* the viewport which the box is scrolled within */ From f5db4943de58cf3ac9eb4aecf2278e298deaa052 Mon Sep 17 00:00:00 2001 From: Elliot Smith Date: Wed, 11 Aug 2010 17:10:45 +0100 Subject: [PATCH 10/15] cookbook: Added video showing scrollable actor --- doc/cookbook/Makefile.am | 1 + doc/cookbook/videos/events-mouse-scroll.ogv | Bin 0 -> 49532 bytes 2 files changed, 1 insertion(+) create mode 100644 doc/cookbook/videos/events-mouse-scroll.ogv diff --git a/doc/cookbook/Makefile.am b/doc/cookbook/Makefile.am index d77f4cdc5..b07785b0f 100644 --- a/doc/cookbook/Makefile.am +++ b/doc/cookbook/Makefile.am @@ -52,6 +52,7 @@ VIDEO_FILES = \ videos/animations-rotating-z-centered.ogv \ videos/animations-rotating-container-reverses-direction.ogv \ videos/textures-split-go.ogv \ + videos/events-mouse-scroll.ogv \ $(NULL) EXTRA_DIST = \ diff --git a/doc/cookbook/videos/events-mouse-scroll.ogv b/doc/cookbook/videos/events-mouse-scroll.ogv new file mode 100644 index 0000000000000000000000000000000000000000..42f42d2ae7a78ae62e5fe092de02bc343d1b36c2 GIT binary patch literal 49532 zcmbrl1z;S#lPBsiW6aFV9LLNQJ7$cTDUO+$84@!y+c7gUGsVmtGh;k&oP4|c-?w+W zckfkqtMscXm8wTl_ei6WH#1WP0|)zuJXPe~-?Hk;%SVH`k>hYp!0P!H?grdfB*-8p@R+p%i9SegeFj832A%-RA|s?DKt@D-MG`DOqJnWYgB3D!YKT4VLkZ>qoMPJecRONFyJ5!NkIYv z#9;7lp-?VNtmVBAZVcc04VVW55*j89E7ij5Mf})e#dDAk;!>J^ny@5AP%5Qx#eO9H z9@5*rxcTKh4nn_Sj?i}rG8B-YYe=5~12(`dw13LCt!97Tga zFz0XjNA%w&sH6s0A|fKfq{9AWZ`{Bi4a7u*uinuAOv0$7{&ycfd|)M2%%^(eetE$l z_JQr@4gJr=`X4Rv|1C!f`T*?wVygdP-G5Q{^dBLpt=@DXHvJFV`ir)<{s=)0h>D6T zY?spm_{+da{~&NO#Wx{1nUdmPrlj}>DJjLg36+#$bN^vE002PPuLs=kFAMmGLH-d2 zKtcjQIuL^d{AJMKe-Je6KMWSkQ&-#3OLz4|kh!7?&y?CT2)}zC-NSxNyd|2m%X<$^ zti8KB_Gw<}{a8i+Vj$d5_bH)F(u6^M8B%1aQroi&@-T0xMT$;DH6(M4WN?|nSK~Hs z`!hpz$vQV`xO>%)!r}WRAXYKp&mKP$u*`SdOxiW_)5s=WF#Mto?Yi-Wny`>)`anr+ z0Q}caQ)LCq4qQf3$vZ!HjLYh=R&t>;1rNy#`!p+;Ds?EjNZ1YvV1)P&d*miD-ZZ^4 zQVV><{)B8!Iq6-6dmEnETa^UZYc9EjAB#+!;ix)(`F_LOA+1guK;wa{MOv8JuDWC1 zXa+SSWZ#i!i72s|;dP6T=+!G0o1Z`;z? zc&O$(mtwxd;vJz=5YAmB?nE3G^51cc_8=NcDF*ywy7S_(>CJZdk;ybV?HE z2%>kieC0-AgG{-i4z^=>3M+c1N%XH6P3eZ?xfI5MGpFT)oEguXPxA@>p|(J~Bn1_^ zd|q?7f@N9r{jGG)E`hq2TLPWWYHoq2W7V5VWC}=yNgD5id?aC-UF&)~B!AMgni229 zo!Ka8=t#T3osmP1*C$D_1$Fy$ybHqJTHc73F?zO4HN0lwN9{}qwuQ4Ex`Z>BK)5k7OrT8RzFfDv#6t|`EzZbeyI}F zAiaq)2VO6n!z8>34SH7KH?55jw_zq9l@;m{cWRfRjik~n8B%yUYWmj+a5lsF2X=uK zdr;ye#vkU{W%hES30uNz`UHu{`D5>~qNd8Ri*etNt!RIi6*R|OR91-CDd8rLeRj0r z!c^kv4BW@L5~w51>zqQIhF;E>Ws2E5GBH`Vrd_=b>I7gZtN}(YzRS{EIZp5qw;BnX z7@xZrD?J!~{4h^1RXY-@)#P;OZGcDrqOPBnP}VA}uwK9dW0||zShODcX&7<5UV7$h z@)j_Jc21(Ex?Nh~0`-PMw>yHgp(NFe`L&B%uEl?&%(WWZXhfBZf?2xDsw94#ePH)4 zRM7$K_UhYDHHq``!30{Y-{e^zQGWc0#ExULNQ1DlYkkcnEczsgA37m&6fuTtXpv@R z-nfJ*q{MU9Zy^PI2v#qx7FZ@1Jl`=6FaoB1o#nEjV#Y%Z*A2ou}y_7Ec>F@j268RH+ZloQ%$ZJ(5 zC|RSJXS5{{AqwBnuPVCq2saoN^gmKsur@UBMar(Xz9=i4AEZWLk^7w39=V zTbWQuYWr@_l+8noP8>d>HLlo?}FMN z-m_aakkT;MWBM6rBiyFzzW{U@3`+1bz~I;i_<*blbC-@}uO`%DnJzw4Cyh*bX;Vs+1RsWRB*WKU@MYV~00#7>~HB6307 zgOEfHDGjJo$WWO?-CGmi_lFO^I-y7a5*gV+g9PC$=>}+DQ_lhG>AQv|j@52^Tzxbw zGW!_tC-{Br$@N1zTG#C!4(r&LAdCRlVbV}vTOLGPvzV{PXEF~9lF#;eouBC4=t?Cn zV?|NHHXU&`C&`u;R#Pr3zTNFfdMBz~sj5WnPy~|!x(->pGsSBwo7s1Ch)+kNe>0Tt zmX=^D*=7|3&@Nf(w|nJF_*kVbX$z5pg05Em9h4 zHUwdO$PSSY4n|ZNeh@2Smv0H#e$irD`1qJguL3~Iz|f`Wq2$=0jCzkdMG4EY8F1B3XP>#gvw^%MYr`8OjY^KXGb zX>h1Nh!%v{_6d&0#Lgj%8$Y-oX!#4JQj0NxEzPo21X+X0$BBi0Ts2IW;L#RuvZ4GK z=V&>gIpKCtGHx*@QDoWOu&)U~@XujLf9jaj{Kw~84QxN_Mu*at$c+27vj2!@@%Ha{`x+g@kHJNGO2? z1qHxDXp=%+u_boIc2lzS?e$9(fRCvo=GkOcT=|N>1lIH*fdlUc&+J<8lPyFpgZyyX z0EOnLrw#AAgE&{GJ~T)a6j*ngh7ayjC=5fea6U&C7CuKy^uE`|HRxst0UW#x+PpeN zCtFOhO(c9T<+i@y6XXl1{Y+r$j231Hfd)NFjD2p6g~wb{i9@l7eK4`IwE_1K#`FQh zH?Ru-;_`;g2?)RpufQ5l^XsbI)sOSns&gJv?W^?2`VC8b>H)w*mqBe;cWz_# zqd23OPnGvfyi@KSe7s+4(OM`YYQuWBRlEO+2UNoyf~5@Ht>h<#F!s-LOoD-9fIt=R zs`I!!A-gZ?7+`qGw5%qJ=(_3L*J#7Mt(~IxCqHl8qj~&AC^Nr^B$VudWno}>%g(D7 z8v=Iq5{O6|YLaPO>Ihobqkkv!M_Do@Vx}-;b`>ynv01D0`_YZby-L@wg^uU)S}lH9 zsj_O+U$O3PK*z;)A8p!BfQ(=g-9wu;h$p%H!(we0=Jh-(YzYYE|MBR4cR8PgE8XG z`mE*cG|@Z{*`?B@QrD%@gMI$5$jq}`(mxs{ri!$iTA;xkO=vKL;kPXLa{ilQ9&?VypuNy9=tmwfg5*D z#DogC)?T7x0aGaP*^&2jl2Z!$9z#t$trcR;8WZD_%8}#n%yC4vFeJ)Ab1R#f0%lO z-0;W@Uk!orNr38v55c*$-0%`FwW>Vt_37T8urjsr7Ra0-`QPjnaumPUSPHNyDjShg zq3`{uOk&%lNs){U+Y-&Vnf_PLe=1l@|5I0fd+slGJ3WoMKf;**WLBAnL2t7O3QEU; zbMAZlFYx|wO!wp*^-|p;vLHe^@qdq%p5=fKG*dH++)7QH09A1_GG)hD=K;!%7Szmlf-+>dI2Mn_hF zN+u>vVSacmnys3vSWqjwb&%->I`#gffAjyITL0R!@4;8`vM=bIRB*0o)~-s@3y~Ql1zDBzf3a>H@&98iq!QXJ=uZJ0Wa1Z_rV7 zEr**n2+wq${~yr7q2kb`Wf8u`D!;C};fUU4Ct;d@}O ztHlg?_#$1LaM$?PFc^#6BE??r#SQ=mgs;85$Qp$y21-P-=QT2UR-}6;1$4kM;3R&|BO?N|Y!*Ju=tKdrnq>A;7rWe9Qcuj&P zGD)$y13}{u!!yp||F*WbNP2MMu8%;C`thJXiMh{Ha=UJv9D4u1&;glLW*RA}ZVZK? ze(2>il>-Z(a!I7vih&3{*5ul|`%Zd>`g4yTHKW?+?t6A#c%7Ka$$p<3dW5ZkgsabA zbR23%-wYP$6Gk@WMqB77?dkKv5U{qci_{7h^wbJ|YM4|ywA+K)($sQ}9a?`36FzYI zNOMj3=;jI3FXiV;oEAV=qK4)A{qG8O`cys#D3P3G`e*t3_3;v=5|wt9Coh55jXFH! zke1P3^EWl4j2`O;mJaoaOkYQVZS*d_CdesNnA$jOJYr-poVB1L)C=_4+E=;^AyQBZbO8fn~L)k*3Kn!1TJ0SG@-Lg8YUmdKE*qXI~jl6%FM|@QxWfqC_b_$6ZnUY3|67=Ek11#=t>yz^r&pSB3-diNA z(n|kqDT!8THp&qEn^#S;K$0rAn z?hkll5C86j{h&V|WU_~e3Vh1layS^-?(poO`2Ki_2BLW2^@T23CAxs!Kk&zrMa=iXnr>-~F8r8utAyJ9!c)N3*!GH2?%IywGf_q~?qH zk+yrh$?`5ZbdztFA+*$kLbuBX&F+~;2wBNMt z6GK4p-F_^zM@qBeTUnjev6?gsBSkqwt*$CgXlUrSzPBd+cft?po#foKotn3J7xyAS zj2xWG|0E~hE|$`a+W)p?3PU$gH+2+NMo&cT=t znNn&Ss9;F%*2RP8|B&g~stvK-Hy)M28kTw%pUuO?Kd)Gz){MIw>#G?KV2ARTq9AYm zFVwQVF58w+X|+32QKD=^1p;YqRBK_H>8GF!-P-Wb5JlQIjHR&jAVQ{nQ&Ur)&9cjC zgs8aueCr0qigd~sn?h1cp zs4>QdY+bx9!VT++aaZgA7A9VijVv}bHPtLe_M*BG8H5Its*0l8OV|5EG|hS(O!oII zbXM+%#D2UzqDp)5iDJ!H<#+0F&#)82fGlZx5H=^@pZ$f`yW~%l*|b4zr%6Y}HnT0P zS^r`P-&MYT*NP=N`LL1l?ApA)?3DlcHV-N*w7$TUd_{hNeI`#SRu{XWA^B`R&npJq z0=yS8wc8NVY!{X_7Oj*fQ=^GRKXIBT2yyq_@~pExQ-Ng@=vx7A>e_mvd1L{-=1cyeasz><4g}dka(zBu^3s={W{W%c0q!X7ysgk_65*_A(TsRO`Q3H!AUE7;B&cvNC-eH?V5Q; z2`hq1IB2)(0_ssMVA#@1lIW|*+_r&ahayC*t1dCEE#JY~D+whP=N!RM=bQ*7g#dqm zAbFluYpYdVEMUy)cVMg92!jK`AcMkKp@~^$BRd^yv{5X1@;-O;XT%XxWww-f-AE%G z5H!LW03{%WK09rS%!sMNuQzSN-cB~CBuJzfX+$u{I%b3eO5Pm41E~WdM=n9O)0&~b zct9`$DD!pxt;4bg*w zf~U=ok0x@3-rn9mWNd}o{aIOAZ2c77W63yLe*9A%g+BNhh-x{0~W0!d6P;*eE+WicyQH5j$@3*!U-Q z+?2yaQ*%PX0XaBbhOxim0aJEXkmdgk&`373^w3?XZ!bUgZFDrkIYpvkVHk~;wRYYl z>Y5bSg0~RDT6glY@`xEUXRfS_B;*2rt|X*%J#io~P4vrEDq5i=M3b-^Rgn-OSRf(vBY1&Ld!u6c%;V517RhQ^x?W1MjKq9|Yf3M47e~BUReIgzRWEW^=MW z8&Gj^u?-~8pKxd`79ks5L+2iUZINy5SPr9z6%F|!MN7eDyR`s%2uhLmhP*pFlcE4U z5o1-~5w0n{W%K_$AW3a-8zw36X!tOzwK6Bs3`W^wwLeul%46jz<)9CuP|W}n=r3C& z5M6cQm-0)wMOq>wgjWR83*3)f9Kk~)@uLQ#26m$ccI-Op7p*z*kF84#IFtU%)4sK- z9GvNu<2*jAGQlx)TBsV`l0K>F8}cHdzn5pZx2;`WR zmbo*gJEZ!ijqML$olr2F`?DpepzQ;HfB9Gbr&ImgUIIqJ^l|*MB4!F2TJkp)a2yES z0s>P(Z{u{(bqDft#IHwx!RP(%orvW#FMF)Cp_?oTVw?@ZC|DBsCfK){`RiB-@nn>* z2g;w3Vrt|}2EJxmVnyLrdAbe6C-(_ui?O@&oke7jd`9M0Vbc1sO4r$*tKR`UGpvT+DtMZ@Av8yw>sT3%{V({IgZWkxc_`AVOojP zoVC;vQ$7EXc3sv#HOePHsd>Unno&M*@)jyjmjCR9t&6=^c2TAk1!i3oSX6iZ&Z|ii zvMa?A2|!rg7=o4`x^uxhRz_@RS~G#32A3N%Q$L+u&8%{^X{;f1bb$WRO;H}csWfzm zgTLS8mvInJ5WDHPNC;SFFGM!-=2iC?bo3{ngZ0fI52Op8#(1+^#6%c=O<@NtKI+BT zTDt(pvwIwVZ0>k7ca1)|yy`~HWGLz*D7S|ce|)rC-%7&$ISB?8m$wx?s|qNuLVyK(Vql>ceSj|ICM| zJo9CNJJ6ErxAyY0rM}7}{i-wuLIz1BVqZrArc}7q85FWjsFjwtSS|zK79s&q0hN?8F)vk}_6oQefcm#&* z&MU+O{-|&pPvZJ&#P{8<}nN@Lo3?ZLJZoK62yfYVj+jm@IsbZJt$iAwq_c z?x?ko1h9XmFqoiTI`17Q$*$9*!b#j?=N;amduL*Ei};0;O#RxtD^g_$;YSH#L!wZ= z#+NT@iLGPHLH9v~>)4t#A&d+GK@!pvQ&z-97Sw2IW-akEvnDPpN)BxQw535~Ru?+X zB!Ll^H|#r?@pazg(Y|L2o&oNh7;5zVwhfP&h2Gig$f8~^z0hCnisdpgYVh5sCKsE+ z6xqh;`;NgqabZPfo-Tu=ok5WPQbOYbW*?z~C^Y`a_#Sal`MsQ1oYbB**KC$cSu4T7 zFTlFsX{Wsses%bzrha&sa6A41N#7CUnzzpNWvey8VRlxX?`pQ!I@KwYbz+S=;jT^h zY;Yao90QNziUvMY#`E3Ot~tX2rGJx-GdCYirottaHp8ardc{nx-VYZw39V zl4AbW(2{GijHaDAyCCU$eJ;QjzcYADlm~a|h#5in=}`WQETDFf=9p{boM(9-UUQHDS4K%k(B}%;>tt%z^z&!Ww;A#w@1v+3soj zXEv*Hm8WkHfvaIVBa=ZCxp5-;xL5HO46K!gl=L@ercUQHwnQA6M~Y?vttfk4A{Usd z(pFYz-tx?hYX0GIWCY_@@XCmBn#oUNaXjO8tS%0Y^Gq)G4`Hk(&4F=a9PY=9&sxO9 zN$>)6xrFk5y$)ZkjC{(hK4Ap)!(74dhwa2_qgs+B4%^p#j}Nt^@>R}jAB90#JS3*a zbNsS>z)Wl5U5;LvHjnFEZ2JSVoUViHMM_E|!j!F|g-Kc$W>C7~3vKijOpG z_gIUPR0=19RA+bVei~L}#cbZ=>sHKpjLtPdP)980A^7|G2D^jET`%0RozOqsJKfp= zVR92LR_1b8qxVAGLA0t(knieJpw$LfxkIPdn=n-ZPdsz$9R1iEUT&WYJ3MS2=h~@# zBs-cU$p1k!`XOS0Z}VE}K9q($lvKY1Wv7EFqupTw`F*C|^Y8Qftn({hhA{*%*9$N( zi)_gm4VTSL(N&y2ukEcU!gsPK#J z#EGE^7ff&QYw>n3iVl~FuQfsGk9SZGos$i>6FU$)N826?5C;`#gHT_)X90H4r{~1W zIcQcYy@N&3E5dWj;BFgIsU_>Yl0_PsB3?pD{s?|ahmJa4RS%Ny+PYfxXj>tgZ=R>B zlhg}?kjDHCwTu&~8*?9hB=z#e^hjw*xmUx^8I;56=S*YLhcudItjom}#g3cM-M|Ur z`Sx-+qK@tbQhU^C(>YlytzIuxIiSQ@^3eW`T zy9kDR?CSFwdQ7D)m31alYX`$#Xg;)rpSWreE;haNe?cio76ktOnx=SpX?O5^UiKoV za;I5ks2CQc^h+PS5NVg}ru53QiC3F{>VYTOmyW4sw)8YBu?uS!M@g3`%aymO$ghnr zohr9@2FOT|kn2b0R{)WKq2NEf%yAMiw+rb!9%l@_FevJwdy3rTBtkC~NmecgzA z;IisuObuFY zm{F;wMjqb>;$#>!_MXb}&LX>uIDB#IM*kGE#3>Ykt+a6-WnjwWrczBz%(XH>&YjZF zB-Ngd{sexN!pzLV?6w?Q_)Z_F=`Fbiy;1uKEK_`_C7x8L{|TjNE41REYQZuhDErGH z69c_9t8U%dtGZ%}$RKk0&vb-a`c7=-to8@e-+Ky;L=D84@A=j5X7Ip))pqFF^LH4h zxpk#X>(8w}Sg4apkIt&x_(iflf1%pro}f?R4q8%Wr;f}6^DSf;n{JDK@R3j6D} zF7~sp&T~3bu-tb;zUflEmuKnbPe{LeUAUhe2C{7Nyt=$b?y|H3Z*>wsMD|HQ9n%Z@ zRUAG}aWGeC;RkG>hd(;cRLqxZOL`+`x(sreC>2;WMlTHG&C!kq=Y}=gIE2@O(UGWe ztkVu$;ziV#W9r?X#4<6rHsJ7k*MFI(EWa53>?W)1lQR1;5^J*uj(p3KEVmS}2RGv< zFr0`^JIminKAtXPeX26#`>C4#XQpyK?UVV|D8U*Tnzkua0m#i9Sqh?;fXvtDu1~NT{MQ1+ghzEE z{D?ck+6hotw3|qLW?C#wMT+$+E|B>6F!yeU#5?T_Yt+a_wnD&+0R_| zvL_cRPVLu(ek#huHWJw*?q^V3b}u*ULOjB8JXEoug~#~3Et*}g_wG%4RTc+O6+a~E ze}K^RT}0|qz?)^kzo09PV#fPU^}0zCT8*V%`Yr9Ck^=fC`4@p0|YaD+PIEd#9IJyZ*YHZsyyn2nL?H2DVV~}DE zpq0zSK^*^FXLdxBjuA|$VOWd97Qd^4ust~-DoRcNN1u?FAJQ0fSH|N}9Ilt0A@2-;^t8E?2Sq)*?x08}uh z?;(yN{AO9QaqGeab3=~FQG{@uC815uOf!b?{nNJvI~Px;8PW_Jmp5#Nog z+T6vV5bawTeZU8kV*CgjqoZL+JFYb;&Ww)^%Opfd#@<`3W`fH3GYf z=)t?uSyfE^IGcGYW!jmq@@K#>hMs)Vb7}g4auJi|%lS4>5LA{eYG?PD?eK@Wl|**f zskOzh3PIG-td%6!mG0hX0+;1fS|(+l#*cGcIR3=-!=J)DDJyKqj!1;NA2IUDIrEW7 zngzPr*>=PlooGnOjG}$BzdK(X8142 zx?TEkB(D%Zn?Db)GM<0t(Tai-v63oQ%ZWyQ?4nBEj)2eRhlZtR|2vtPbzl`enhB2L z8)czGu?o?HUKw)hq`E7Z&7!baEKMv<_?HfpsDrZBiUZChJTRr;Q7UsvMF~=H>X$)=`m+ zkn<_SS|fPWTewg4_+}XAm1Sy-3dY4atC~T-E2WX;z^5EguSk8b6A>@!wfdB&Od) zh5UC-z2QQX#zKhqIe8+XLGXZGH-v-u-e=D2VTvwSztm6{Xk}c%u#xF~Tk7Ta=2LuL zKoJoVLf$q0DO70kRUp~{j=Qe=x9-+qv4O09WfFIAVp2HxkAcR;BEElDM>PIrb>wY} zQ0>LO9|jPp0tD^>foectIA}>E5OlS^Js}j@_AgrySGga0I6??&GI&jz)1SIJ}0xE(RMXakl1?TSZp3` z|A&Yg(7m}CNfHmVS-A(UIM3a`?qP22i*vLiLx0H|+EIz&*jH5p$ApgQ;ktf~Mjzmk z$60s%D0~mvGE{a>{H|i4Ey$Hrzb9K29VMZ%>%$B8(9!CV0ng#IBVyZ825F&$j@$qw z6B9G9qsww)OLhM3;c0f18X0gIc+Lj?=%>_|wuP{hku!81!5wfHbfEJ|xl}vOFWY0V z=vyq4r=xAq{A#-U1mRg81$jWGYT zVs6vE+rY6peASo7@u;wIc<%CX$>?s;t|2xs9bb^s5~xB~|0v+btKU<2_v{Mqba_v{Y#3l=PUgm_oaOb+?*0W)k7v+FJ? z7j6{_YWlu8Kw8q}$526@9rTtlMeR$0@u{)bE!cSM%AE$gl72 z_->T)e#F~JY*_I8ve@j!=4E5)zJV@kboX=IeW?loZz-;8Sy#kuk{;>EXF#)FS2mR; zjZT%;h@w#wsnXRHH*U62bkU+COI^`^pQC%u51*qzh(rko7uoDo_^mh1uy|EgrKB#? zvE3CpEw$8;3g+Xz^%79+W0?KoU|-C`&3ZMMM4nN5nPhkZpV9VPk8*IE;Itw3WnzN@ z?z0ePmL1pw5zMBC7fN0pN|-7@;~oXsZ_`^chfly)O#E@dY2|jM-scHv{Tkpoudjp| zs!xryJ+qxgpe1`PYplz9-kT-B<8oVm{dth9_HYIaOOAwRkkDgL%dw(%ndhLrMX$b9 z-u&1bBe{Gs(ny=Z^#i2=thNHoCe;IbWB1}g#=-5h2mMFh66m>RN{ghW5{x5hu7Uum z%zl`U1=ule{hwl$iQXT~;?sSOJqOrY9Bdofx%88rwk$~~hJTK`TX*2@wb|J`uFG_~ z#~)|G!9HG^vQyg4V&wFFc68#;_T+3J8W=bujd5xDwxF%Z4_~8TK@U|{&WSLxQtQ2U zv5SRWC-hr5vUH^do_i*LYwr2+dIV~*fq218G$2V6KW%`cc7f~mBKdj9>!_fGrOU?w zy#srdeRU-hw%cS(%2k%6N(%inAHm!;kBAg&x@S|hf=|tY6}4#KyJ&qWW2?7JQXvoBgi$YNi+k`=OT@ohW<`d&RG#FA57Nb0z3_Vqp+? z_-2YKE${NUqc6v}m(V4KIkvs_dkFVBTAmN9fFf4GSJTw6@Kfh#L*J=j?-VrYf{$e2 zJdGxBgg<1eyT1^|el08@{<6?7u|X+Sdw%y_#N_3Hz<4^cY$@L8N1Ec;y6FP958Rmv z+xtO?+pj@Z*^}%nft}Q}m|Ar*+MXU?QT+sT(iK>swPuWf1(c$=bH6KXez7yK^dh1r zYT%meB(6T`KpAYS1z$a<4MwLHz*aTulfrAN<6DtLyrTHE>nV1E@4;J|1Hloz<>LBN z1_^PQjnc3ds!y@9Ic1sP@o;;EzrLS*I$^hY9|gek{R-`9L0OSX%p}d;7ww7j73TpQ_tP84;9iotHG_CG!<9T3T_ifHv8+O{)- z=@!K+Y*r_2)i7wmHZclm#RxYn+78(fS>s~)th9%PlKYkEbD zEk9my{a?=CV_dGAKPs9QtBUp!*x_ z+yS*7V;7$p>|&ea{f_lTVg8v4f`o*$NgRAJty z0j0}#J9Y(S*Gfi|hGapu`I<>4ik~nO3}{dSehfT(j%X^u@6ZjPtV;m5NyRB9Zgx8U zNoy+wey_2WGT0aL6~B+OD&#H@iQ4~Gd6Zo7`~4Ox9ro>elABvM>2wNVHKlgRRmUC5 zz8xhIo;zNAA#$@;6+`xDeyrGj^gnAmXAbFRxNVcQxYUVka(e!7cVoOesRT(7i1dRhEkwO+d*E1z)6Om-^zQe-*-M$!2nNCK71vD>|Mc5>ng18U;}OH(@pr{ z5aoFBPB^wLmRDWNKKgcjQoaI_yzV}8!#(kFvIef>z2VKLMR=nyb=>vuU z(~bMp^%yUq?)Ia#V#J(ByB;6~x=0Q+2|8#hw?8^4#hpz@cBKV?V|dNd^qO?)^^L2* z15%JB7?Qr+`uFqeP}guD-IEml_A1xl64v%RP0A=WNtFo!_lP1GiMbJLz4FY0L8X$= zXspgI3UeG870Xgyr@I3vl~X7AlBaXqi~#*xL7{trvm?@mg)#71F&uonU=c4rr%o^| zWYKJ6wpFe>`LW=}lZ0{3yBL(;IRKKGPsPCz*~Mp7PpCsY`@Oa@SR&emC@D^5wF6N^ z-U~9C47KexRK?DVCR6;TLAOuxuF7HCM8NiO4xApdNq-fqkH`sHGb!E@?~W8b$P!h+ z1J$aT3gk`nX99^%%-^YE?Oaw@gWm~t!$pSW((U#elMzm*ZhaqaCoXv^#iVw<>u{H( z`kJ7n*1j9472QKerZuC>dmyfzWoxMuYS5nDMs3%pRp|A#Hs)rAr}sIMGb2m60<;@v z?I89R8z_rN%eW)YcLM&kue)L690@n_OZ)SzW!Dh#rX?pZY6uENMezj;chiHI-|6nK z)XG}ACClp0Dj_dz1X;>L zA!@>GDKc&pmzud7EQ+JROde&YYZObs_+y1#h28kh2%A?QXb;@r!N`t;m-9Lsb4JQR zguCN6tcdPDZ}ih$JU;O4=&5~GND(rqh5nri>t}O&gm7NbWPg8BRPb(3U7r2$P>*rd zUkhbc4OKcp*5){1E)c~9O?0X$YPFzlSlf_xd0lb2$VIy(7w#aZ&vl@=XSEY~9j*Bx z`oosB#+Engh?{rUb9yUrpkht9bfsBt8yT6Lv0s=JTEP-Ka#sp5vy&&1_|YJ4E(5=X z<f+ifSJGaa`sHKYbgd)+NrCOeHeO?M3X<&odN+=HoEJNROGTDt<2j`7@$; zC-^Kp+oyRB`YwGDU!C5d=EasQ13WQXBUx#M(4T7TYL~huslUo~mMd_oUX-^8J$A65 zaJ;R5u6`C0H_%bTfRqEC-&wL4##YcdQTNKX`ePiH)h{i3bF7UESnJrQOV~yV7`60T zT%5Jw{#^IKLMM!X?O3++=VHu?5nBC?OvSjm!NcC&0w2jP97y>!I!@`M`iOb%$$=D5 z>T&q*0W1LyH+RWT$bC5mUJESQHqRzH(t0?Q$u}W23ruYmKVuq1GtyOU`1f(z=F>K% zg@H~q;XbPm&tDeT)Pn0(El#xhZd^KnK*3Gv`OoYo;=zma)tceK&)0@)CGq}08 zTko+wR|)M7d>sV|;q4uNSsRs0gjk}Xv-N8ae9+-gws_%SYJ0`92z)SMM-knz@Rf=iu=>#>71+E;Wa%IuXV^hB(w~Uu@o}R8d0CMG@?z*38T;^Ot@a>O} z&$yX1^5OPl><i#t#LVZ|5+G^R(@<9nA|ibl)?}8Y>G!`;Ip?iu zcq&zJmzY*?!i@S+YJ)Fo(lG|+fOba->LGuR+%Q?lwiY$0S~ORJaL0T1%XeL)ig=R^ zf`ko%7~sc}60zm6=acC#$0-F3iPwBs;X)rH5hxZF0qX_4ZAO_ z|26=xx$7Mw*HLeGD6R&iMlS?ycngZ=zMhXCNbR*07RnYG+mcQ!oKZ8lA2gL8nvHQ1 zydyH9b?MQ%IT<_1Tt5`ppax_sp!CI&r20CbD6}M)cd%+uQcg|Lz#2+@mlfg;r7@+X z#2&C6g_98D-8)`ym~WVuJ})f;5WG9(9cS?4X4Om{z;kZE-oP8EFU&CGJ1#1??Q}iE zEfKQ88<=gg^rF{TZfJ=4VWstRaYb%%**Pjt+k#hOx-t-q{~-H?nkUmiyGgRF0t}s& zOjJw@Zln`ja(r!`JnIJJa_SS?S zB#qB0j!U{{lR@N+Q6l5#mM|ju2fkZ`PSHzLEZ)g5pO+ud^hdZvtCZ?J(zo$gd^rZJ z{x6Sn#d>hw{EDc7pG7J5wi_UYr}|w*6MfHgItp|RM2X8v46Y20vt?2TZ>~Zf_DU^y)m;qAIwMl_zH9g_Q`Frr%uL3x z+3<3R{*kIVm)ia(SJl*|71jhQtN0@83D%lt6HzK?SOyjt z<_>yK)g>TdCGd4Rn9U`4B6th~W_=tk2d9}*t%P8AMmK3B-SZeB%&XaU>&|)JD4Vg4 zX4(FbH_1e~%K5dEBuiOoSB@EM!P=MkGcvPZ{JaubjQj}rf!Af9pXxTEZU_|uSPg8% zO?t+v5+>f`QVL@Hnsu*#&>+Sz7H->N3tAYDg!M#|ndi)VrX*T~cI(%9jbQA%&Ao7^ z7DBrTuB!Jub8PfM4$pW~HX|i^x{8!E;Zj@y8~!9LQ60=tvp`Yd@5BjWr+mfDBNU#| zWjWli^F{{|nVKuX&zOwczwBJkl$wo)N?J`b=Qm-5*UQZ}mFst0slo_Dx3X(&Z$mCR zYz6aK31@g1UqWpp;#X2q=$&lMumNDcg&)!TF;OL4J^4$qx=uVQLz=ObMGc~Lx(8C~ zzJuvzv-YJT1@{F)kpvHJM4V7~SX|_y!Mx`#W9Ou%zuI3L9^ZD`ph;e~dr+8HXpJH(oIJVn3dz0QG^9>0r`+i}3ah?dO!i4ARZZPd>O5p_!=i&O|W`L8e8?9yOC;)?2pMGT`X0|9@GT~E{xe_YBMTVW7^xQhY?U!$} zpWLtTZt=wjD#D)UijEOulsOT#+8~%gGWSPUR1_lk(CHk*A#AK|3d$qW}Vn z!sMR%Vg5*t#nz)=$V|t^8zP=2y&X>u{Ixii_(s@})WTL+kB#PnGyZ(-8OYrf zGi6l8$lX>F<_c*>cf|rOALHQITnRUyIFC; z9;)C`{v5SYR`b1{LYz|F2;$3`2`I{W18EEU44j8nr4nsLFF`LtI65OLGQ)i8L^aQI z-ujc$VY-4kqZsb6+g{mdBHkMe+XDe4@`A8t?oosv>041VwCVjl`==7Wg^WiFG9-Ad zl767G#^UMEWtoYSyEZ1M3{ho$K828Bu@Lt>*h5R2`Dn=5mt_`??tS3aBC$XFB4;fp z_kPlljRp;sxFMT$;aB7bIxPwTu^AbiGid%vz9UYiw$X&%)oE<4RF72N)Uwp>*%X2P z@THwn^5|#^bb7Yr>(Rf`Nu2c-hal!NUx=_qEN_^hXf$>6zCyM0x9#S^}4jQ zJhflGh9i}d@%pityxiG_K@uz!l5%ZWqGOGqrudC!+wa z93s)a_XI<-Z@It)1iw(}vq2yRe!iKM5r|~L`^Xlc-h&5=5-P$@KsqtOLOlf6f)=Z2sXhoWGAlZERAjCc))pp&$Fm37i= zTFT_0i`+N!Vc21%Q3k6a$BIJtAnSVsp)H{XcvGG9Bg5*Z^`PtIl zxe|jH=3giC7-Bvh4Wa#f%I083`vurDZw*`IhUzxV(O1@hEgOL9t++g(HG+8J>-R5# zgsC++KQ2wOYPDvBaBL!bXOxfHsB+E!y#K|Cv=PUx+Ww=l(L4Nr`iFxxhe`M{_y8Al z4Mo&RVIFpmD|MxS2AY!jXluZ(@kh3@i~L#Y#UlPxRO=P1{VKveuv=zK@Cr%4`(`yQ zSqNQ(cRyb}48FV8JhZuNB8t@W<9c(7%1FpiH8?8u-?BPQ?RfNi=$ z+>1$=>mJ?RVx!-JPhB>i8n=7Xn!G!ZCB?7snPHiOvn#w?K|2Rv-xSOIpOo?O=K>{? zKMQ4r(m6*_!7K@hemC#JAWT8?a z65s$mp8%4iQKVFErWz?rtZJAnS)?3phB0M z!9x-b$u9q9SwZal^me3IAFS8IhkGIYi1FUb>0G#VfO({R9saDbA6-*t}bm#?OXXk9jUo$~|fI^DfF(c{=sKYd|U4_GKmcx`VHuIOjun6RXs&?4-clgwI4ZJ$RNp9 zh;&WUN)+Xi_a4awr8PoZ5A7w(cQ4%kP!AG)jz7Ww=p+RW-%#}7_30@aSguF?LHCzk z=;A=Bn;X@6pz;sdQ&|Hx_LtqyaH{9Olj`Si=dvW@C2)s)#c^d|)>0%R)XtA*E~#-A zGcOm8-|Js8H_v%%>^b>s(RAHD=LgSZKaD+^kQe;s?@uJo<<7SbuwWItEfHhe`Kl8N&hrsNGDkoWk3x0KZt7he)W z#4r58zi-&y(=!SC6B-oS0>P3J`PYs=e7ZP?;2Gbj&7S2t#q04hcX#rM1yp6%H`Yma z4eKF5H~^pg1kVo)IUc(e6d1{q%iOpq7W^b*?0R1f68qRxEZF~*Eb+t$aA4`Y_Lva6 zaew~l;LHum6wf09`U~_m|NnYNl>gbM$Cmsqxt+fA+27utCMP>^s^x1xar-qa=RAGM zZ3;b;iw9xy_^YJJY=vZ6u8Aeoc#FRMX)KRKK~PS$7Ez4IAwtbJA#~pm_wOuH8R3&E zWDI7=aEQhuszJMYQ1_2dueEo-t&{tU-p!DJPdNW>f1CTbUp;9SrSKh|!yTR$OSazR z$r|Y0yK~a3i+@74V5YGxTC$jPqA7>be=%3t6q^)US#avf|0chOq6fhu6wBj9LGMvHCd*Pqxv5; zt&8V8=y#7Hx^O2HeI0L7-gIYHc9HK`P^A9;RP#>7M zF$+KSUFKMjWcM+~iN-nDF1saL_&-0Z-#n4FcszduHci4Rn9)4n&G<%ALBUV5N4K=( zG~`dF9C5Us*Sc1eQ`n)1`>BSKDb+c>YQwN)M;U0}8n&DaCPLumvTRXNp`xw7Ed4Av zX>51WA@A-|2!ZK0a~#57-Xjd%kG22O^Lx&;)T}+l`#r3^XfuTDCj@Sfi|4KsQR{*g zxyr+!9TvvSnUT>6wCR(C(-^0y9TL7>CyW|LZ-;gB`%9bh1RvuWs{I>;q^hp0D1oJV zKnOPz72IrH0JQ^E|AXnq-C|;S?u3X<;J?1`H!w<_jb_V=YEiB{sC+?Cjg0G26CW!JS&eq_kiPQ599Ld$Y$P= zhO_J;O@gPIL~QaecgA`W6G{6xO6kF2?8RP?ksc=r@te8q9Q2O9k{>5m4#T3%im!+uT<@Zu0e(?F%r`UO4Pwga+p;d3k^mD+e)ovia=nYDjEW#QL z&o5FvF;57VZ~G+_zZrupZdym)^%b)!j7+Egd6-)VrY4kk9&OzrJcXZoLv#WA($pcX zx})p6bbr)pdd>SnE{0^i{LL1k(2h|VncBvJ#jnTB3`D z>Cja1lDzxlmVCV44Wt5qjE4dDKLwpGp~1Y+&QS2k6~?ypeGClKxaO0R6)X$o8g_Z zGYr6GEG9~lwO$v6Q?6M}%4gN?ADV04&1(4(#EtBQ0q)!9w+}!5+!^Wb(<*9jmT&R| zeqNVhY{~KsI68Wg4IV-o1WQYP6H5(GP2Jkr$koXBRXe@n(!E zjS3Z%?Wpf}8U-Msyyd3xpo&1$7{fO1S82a8Eb4)W2Oi;?LePIBqBX5bC=db+sEDG7XHg|= zG}e7>3+McLzA!Rr73TSdYQ#DPP<`419*;n+p4SwAZN7<+U`j zgQ#`-iV!)*Dmj?9BOgaG*c?5#5tv~Em7!GpY2C+l({3th?RidHDblK2T0%lBt=Q>C zTh&Ydld#>6vhXu-u3}nX>g@NIaxdSR0qxqDv2kCqdIBlxw_ZxEk*G>wHWZ49N@J zRmCb~aj@`uamA+B?6#_z?js|c^2t*2Cih) zo^86qMvzwL!LgKDq zp`Hz-tNC1!J2awa?W=%%pyZ?bkJm!F>hdI?)~cUpdA^^%P}EHVIH4d9djs_W%D0T? z<%ih)(OZ}#uN?<{?Kl)nMuO?->53_79_i_6dFkS9-0D*Gy|UarpIJNeJ)myRwig!% z=Crw6pM<));T!MAbAGk7ZDd@|@5{MgPKo!1K0cf0=&-g5lCAJBXOH0brHDbE<%o>Y zk?`)i7OywjPkaq4`QKoF?z8;)F5WLPD-9=ulyEoW4U#A4L={T2&^Bj1V7{kl6|d5x z;HTOHVfzDhf=2i1HMYQAsbv;A3~UPTCl|&u^+(f)tX|ZdUDx^Tbkv#t><>@ob3}#@ zlC+*u(eD$@h^vdprs~L&HlceFFH-p0oZdLdX3IH6Z`J-&>g0Xd=P-X7Ykm(fxe@;* zw1zYsU*%f7_Ryd9r@}eb)Ak3?JQc}tlD%cD#}?k#hZNe!+3IoUpYpf!vlqLxisKST zlGxQ?kfpzZrp%yASIylV(98BoIlhsoh6iwZQ}Qg@S9tiAzERYQ@a`4zK&EJH0|D_s zMy;SX7nuPaxBRKH&|FNe1^R{k#SMmC+XcC~0B(LSr{K})(WRLUfjEX0EEEYw+RMSMXSP4uq|H zKrzYZ18;w9z>pBekzIr9EAMf$H|cw(k%{$#ZBW@N9xd11-OEaR3SL!OG@+y_hqGMa z3#433-Mvw5aaeXm*6U$AiE1amcY(ZpMK#>kHX+J1cDYRiSf}~#uu5ljV_QsPxznxR*hF^6N={tX_pu?(NR*=x(m`D};*9tNMibBL4o4gkPt z!`;r1EV(7B7a#C|lIRZ#dU#WEFzM*$I@Mf~ z)=N)vLWuQ;2i`m>*c*5B^Yj98K)Nq`%1TO~2rZ*5qhP4P{g;2#o|RM`;_i5}>~V-O zrB5@)GDn+X4?keKqRIhGmMH z)6zRKV=G2_*JyL-i<4qOYJeZ7$9peNaCp3|n_UHk-Y7TljFlEyCN7!giYvTCbEoBF zX7Z|PL=`sP@G#E9&zv@iW-l0UQ`5*1-ITL(hJWF1KApq}`ayWt34n-Hz zEGq>F4+b#;m?K`dX!+CMG5gGiL4ivaEj5|zq=_$-I_U|^zbe(q@O>pAnl!C8I+5FK zD|UBxw^dFpHQL+T0)W|v?!S1bY;6gD+e}y1qwcN>8l!AdVa_|`SPW!rsz_UYW{{P5WV z)HchtH0jtm=syTOoV{)6zIVjhS_^uDl0Ra#sSiqC*d5j!1%P8xmr~&a^L5r-bjLu~ zxw0Ec*2L+Y>>ly~D`W`YzgF4vjinbBq-nY?7a&x~iz3zd?9N}en%WvlX!2jXCvo$I+)3GU0>#uI;b%@mAE2s@1uJkJx%!n z7w;7M;Vkp%1*|Ob>^f3D;sYo6M~h&jjs}I0ZU4D&nc>Ka++=%+xUML;0pguFv{eEBjP2f|03Ou;`%Pv}vOjIaM*I*`)d` zIuic@Jw@{ONqG=M0}-*&wA_fv)3bR__Q9>8C4#j*+h`eUvEA$gFg;*MiW{HzHeYW% z{$u@~jR~1B@bkbIk0mBF8jUR*-(JX=NZie3A5HxRxws%o9UTtv4&s5V9Uom|M07#O zeLh7SC>n;fqi{lhqh}FVBsC8ZX$`iQzHgOnLG~gmxjsYQL5&tW0j=n2phr%KR4c%S zqOF;4?IYp7k!|gf8{k9#$-sxB8J`&+m>&+9bsmO|Kj^KpvXc2RJ4j9$c*ou*aqDYt z@TS_e2-C|}b;~USb4=6ZD1)!&Y1L!lerleJ3Ux&YbcK7D*D@bPk%#<$#4Z#)v>x}$ z?ys*pIVh^dVJh-t`Lo*say<+=@c%~;LQ>=*IYP-9j20;h*y_HtVOZCUJ&S%R`m0)+ zZ)uwgV9)f#PJnf% zNYDVcE+Do$z=aXeJc4{w|CNh;={9(9s}-6i>WNfoZwrrjVF}7iN}Oq2 z#al(zot3)J3t0w1N>{1+?+pn@!G{-hx1*RsGmTFm-{&AN*_Nw^`Om}%Q|NCmTVZk= z(Ek2a))f(P5MRr{KX!&SvS2Fxb?)xFUs(dv@A=wAbC(T~2-DN$xS9>svbTdrXZ;oK zn)Z(Tf|#sstKb;S_Mi03lJ@v146=6Jkn;SS1d~yU8H$0aO4l!A9XQdr!w84K1d{>A z7ZF1IO#)zOO1(P)n%#bsK(uw(K_3+y53G!`DvP%a2O>WeQjxTjj61o1_et9CN`!!7 z!u!9GdgI42b_tf(8rKun_64yBelR_4QNY@X+d-ZFMkC+Nd$_d*@E#?+6Fq)7(TK!< z|Mq$z$97j|d0W=-+mYO?FGTy}TFOxMfw-_-BHo>+n=V+{EN3bNf^>)Fi2&8H6#PgDnfgHE@qxUZ9Gd zT0K{OPaP7UuHPXDoU)jFO|D=e-u zIX5$GKE{Y2E~@ekP&owRBme>qWfQ5NWW#o~(#bSqWKDU?&kb#c7cV1}TRx z<9FL#26Zd+I{A(dyYFEQT=BTN#Bx!P$9Pmu=rkE-L)f)eVfo5>bT_HDRw7<9 z#|bswISzDi`B0Z+^QUfq#zkZS;sk}u@IZ`6NW@Utd@>CCMb59;*V7clar(GHNZ=4E z08dTkVS&ff0qpfe2sjhc0FlYz2~HGgbCL>t1JqK!E)-s(0(tY!)bF&MS*b2kO1;5z z+Y-)Fuja}M=T}b+Y1q6>FPWc4)iCyqIJm;VG)~o6s&6gZabl0a_v=j?a>V(c@iEsn z0=G)X<@s{lvCqB`h>;k)o~lsuX1RoIiGlv?+#nMzq#g#jb(so|3vn7<;*cr7#$)k@ zB5xCxS!v0VzvoTbtKr7$f0%b!LFcj{jd~Z{=JoH>XTXF;T+ld$f&mF9(8JcMBb6PJ zm(66eUTO3pP^d$=VEAtY|7!1@3U5JE4yp7t^% z>)zy&fxgJ(nehnOMY$#VEf?pFkN)V4`KNM%cw6WXk>dC;YJ*#sSG?a;S{TA z#j~!hL3I-L)ldXMfUY;#XUyfM`kIvi`k>98BU;azPaOoX``TH=r?(uxGBeCQjtpYy z6j9^3s4q)WQ%(U-V$U27m?+#|l5D7NOd(hF0pH%2w1x_QKCv@eT}scC%|vqf)wK1X z`+h@~i_`Pr8SggX-2w%*)$_C!_gi5Jr~ew=40ibCe(+aTJpQk}wLtw(nH* zt*+@*31_2e@DyO&XLA6lSd)#LZi6e}AI%3%gUxi-e*y&|Hta{H)EP7N3O}Rumxo8j z$Lk;-Q}86E+UU`e{lz#Rb^S(a^^4j`v(CJlL~BzrUwCW4;Ei2)vv1=6&BE~jXy%uE zk;6a&+RYJiYShn|&;IA%`u`9hLjy{m07%Bve-pmi-m43!RRQotKu%AeQWvn|T21L% z&Q6uacOE<-n%prBwzmA8J(<{??HNqEa~!FVDIo+buHYk|J>BrO z#b_wua*B;&WhobiqFsv-wQ%X$ZBABPa{l2?4n3mzV@7YoPviw5&%(HMyt8w*`QY&l z0#tLc#uVmPEXN+;+GYUVhMYAB#Wc89$G>aZTHpA5_51u3kV$7U9!nzsrzy`r{5sJ- zet}3>xi*HLYJjvyQ4?!XvBD@1s|lT{NCm{sgGbFT+dD4+kzQ!*>YJe)d*STaQq_3& zMR~EkD{WlC1kcL$&ylAOn!bzl0PUCgJ|2*O5mvY|QM}`7Q;GJL|HsI{uMS8p`htiQ z35oLOPF5KhSg?O0;ZJa;-eto-dO_}BYDGi zIb-StH zlg{zK=Z@u8*Cbg*X2w|mzxnIz+kb3$4R!AYSJStO7`4*Xyd@d@8-$IOv-Q33I)xUA zVPL>1s}Eyt8zJDHL2lGMqJSbPpA+N4zK|u5B1IW4-86YV<)CHF?Yow_5*V?91Y!ai zp^ylGY=STR*gu7U&iNx)?qw7k_^fWnB(PyjL9nU%zzk9-XEs_`{vq;N1ou!2>BC$R z7xzf7$7eeB3QsoXG}((*vpHmZKRsx5Niv(>fPk%D-}l$Ycir1w-wg>W^BpsZL>W3@2uy=35O|B&Z~Sz? zEc*W{ZkOZ1dqenrI6!d~4MMw`_iJf=A*U9m&06c!a)mJ!84=R`-LkfXl+WHN?rt0{ zu8?@Ta%PCVMWDP9NEwdq<@{aPb-FJE>@N^0gX1L<37j;a*^(0WJ<_kc{`ha&9%R@~ zt{Zg8wZ0EKU}q<8?(=8Z)O>D)x}Ij`mSVg;C(xIYEM0`0YAzOe@+FhSUG+jVSMbl# z%+|&zJ6S#;O%lf>;@~(Lu%EF%=)88>y>89q8TE%)ZsQv<9pWh4CiqJpy zXY3FLNpXEt0>R*G9Bd83cof8sB!@fiH8c!3*)4`vE=&BIy&R*uJa zsC`@5SGW~#(HB*~BXBGT=tKm+dcU~z+DuT?tx`ZOfboIBhh;!``aA=KtS?2J#Z|MD zU4QJ@89&fNp7DXUca)vj4y}6=P|&X#`d>MH&(ApSD^S&Z+_d zU*vt!-uD&pQT)C(kD3ZY&XP1mMhPHg0pQMoLJe&|jDdl<0IK_cMYy{iHpbFg*QPju zmutB;7kZYFu zLHq{oBN6Co(an}B>cKrN8IfKJ{a~SM16BdppgLJ~FPgJ1M4_iKvbW7Mg^=g*!e)8P zxOG(sN`A9ATMrdLwqLfg4h-{EL7kyxF^8YH)d3+#McAS)7@D_wsmc=EmMxceIMY;l zlPXz8IHbn?Z@mXWNXeZaEq>6msWuT}qp8_a_#b6moNbVkREHyal%pjzPTBvU($gPs zAX-4?G$#~{-AG)?b#lm(0|Aik*Bn6Cy)ckWat)D0JG}mw?%;x{EH!6&0PvZT{eOfu zpC&`i>PIagcM2g#q9(cqwO9uPZfq+%%uubyvx#SK*L_Fsy@|<0k)1BlB5t7g$ffwk zqDbj*R!VbPCUJ+0w-1dtlTiGA$^0`RsV|_9qwKT5S>$G7SVs=|RK(IYWkkL?-%~&4 zM;*}T>j(sSO{K)XeD}u2A^>{6n5N5u>954LSZOMeHSeFV$u7Z>sy}n+f8ms@CH)-y zF!cqHpPG7Nh?V@gGm?P9#?(+Lq$mApgC!P&DHemxVm?jxu9+p_I0$L!D3RelaPxaRc?jbG&t8F(8Y>Q0jID@bVnK-)yk9RO&%{DWE@9}+-&1Z;2x1p2Y1PjI`L z&gf)##GBon;}aB)a4`dT6c{&79_TVRhDj^@1KOG*S{JiD%Ef^%Q)9?!8jzi+=2L^>vh|`E{-5>rBKd<)18jp63R_X zXw99%ty;IumwMRRe=0{^QL!O_CW>pc;y)BCD$bOLitEcMMxKXc_^nlVtg=T3B+%T) zb|wE|?pe72X(wu@bGF{UU>y@dcA70QL_Kn@GM#y;dBrK0$pu#q#PhXSHiTR^OtWK6 zw#uyXk=UvkMR22N9*xncAB7`ZDsA5g&D!Uqk$OM_=HQ{q0-0?ENv0^jjQR5|+=uBg zzLVI;-zIH`3I7DBDwHxdwSjkKQfhok8XhWzX$5(5Dsn zf=1t3h!ByCU-|l4n|r_ry93&S5g`C0Mnns29RX$nMZV<^P~7WV*{{+$@&BMPvu%O1 z%dA^>lgJ6Q)G2~6p1D7@T0W2D-Pfj3YXSIdvOOaEak{=6$Z5=nQ>};GbXVp3x8B_{ z`)32GO@)18H~)q}r!e``v%1q9AAWkq?3)7$?|}C*7<@s0e$QAr?`-~g^3d`G`jg`V z7@9Z?2-N5GyQLP>ByOrRQc$@Y{$Ar5ZBVD}q?^egn@yw7MBO9)q&lQq_$2l-_8frv zs2ETmG7BtNH|tZ|{orlL=6I!1&q*%P96<`5Kz^nfC)zDZ;B_Tr=i*Ib=`bReu6uLu zja2#|UR}AAT7$3IRXJgB8WK$)D>tIOGs(4!#Z@b@qF<>~jo$-N>3b5m@tPG^mm&9# zyQV-=@gixK<$L95qxX&Nl_>Vz_2oPpp`d*8R?bv3bmW*XCfizCbv)~mp#givg{x#5 z%4j1&PHdQjf(!e|*sHzau(cL0ZUDbmDaLAxpi27jyYQ);-lLo`KQ~!hY+Klc@M1P+ zdrz-J60CN_x;JP3c$aJeWTB1H1(_|ODXeXw5>Vz#VPXy8p?~hm?e*kbZ()++D57%` zxsfxF)D&>_3L|bDIVm^Lm>)VL5-t2$)(tP1i|Go5(Xk(CbG+d2_PWx~DL3gXdayp9 z^JgiFxwPR7NdeG3izD82NZHW7!>Y;m&F1eXS4ISd1U;{KCykj{3%WGkryYwC2apJ# z^pOeU#Ut>&D|bsm7xwZb6!5rT1#^iGsyb`&3CD9(n2DLr6U3n)o$CT#-Le9fS?+de zFHr9xP{jqMc=?{zD zn(co<1m7=b4v;Sp0SeIS(+HcOe11LwaDz|Y&(AVIBM7)jzU&^57znWYnOZ>F^jG)} zPxdz3X~b?urF4Latcz?V;4;U~VMl8^eRI=cisI;iUVFK_gxX5Xr$K-HFq=3u^V(Z4 z;NbnnLXs-rcNvfQARQz1OxuaA8qu^Y6@|g?G8Sh;49swv*Vq~pLw?`{_-7N2M>-%Q zAWT@uKA@3e4KJxR(RFVAFguVFP>!9vN3TD-9#?ex%U&36WKo@&kgNlZlYVjA=a0<~ z-|HWnA7g%O^7f6S@#=KxCP-S7iKc={65lF9`LovcbwA*3+??xy2*+gdd%4gJLupN0 zcV-zkJ6-rqwldD8O0B=adEpwZ>%NcF7Nxump0TIx5!uE@v=QHKvTA`o)&`oPBQ6;_ zYCbVc;Age(pO6ZDjI{c3=f%3~ufW_~@FP7CEGs(i+OE5wP6xQ*YAEgI2m6r}J(0M4?xH~2$|8Q(X8W2T zO-|ux)$}_&5e5`^9x_8*1r3dznGSdXVtAbx35kNpnco~dCT&VEPBM6V9J`uHE^Ulm znDc39pDVi$8w}h?ouNzmPzw6+ng{>J%VM3I*{e3%y%`Ow_}nY|Um(HR!)+bsoqP3w z(x$o5Ek5*~h(Tx1On;xVEO*|4zM zqzfls2{Wr1LCxf?p%wTLwW5JBGf)jC6Hz>|&%z*;;j&?8_2#RtRQaGr3`cY3TwC!3 z29FBs-S8>WLUKbP{IlA@QvlMTvF;P1{)*AlCqIFASqP6rS8}r5sQ{cbjxA zxlOD)HaIPv8Xud@#Mts4S!Ao)t?eRFjz76$c+ap;-PmJ0f)~ILO(MBMt48r_Rw2`L z{L=&E9!S?ORcv;u`ulqjDqiktLq!F|wnQNK6{3KDV9Ne?#}u{FOOFfuV84y`pf?|g zF7aX(pNq{tzUx8&vtL&1NE^N(cB1pO5vj%iK0ZB}L40DVOu0Y$KDR4BIOusrEYY=^ zH%KWuyk0k^fbER85d78bqwRE*t&E!c**T>DkIl*MH%T_1ZB+d;_?d8gX>Q$%>9=oe z%?6F!jOZ+9o!6wx*=4Zx#Sj5rPmpiI2Z8B*mNr+U{-M2tF$;eN)&%O^V?lmmU?Vv3 z7`0_|jrG8Ddjk)H^q`+!VV+#5TZQvuVzgR2HM`KdAr{z1+!-nEmg!)#3imx(y-=Wm z;8t@jw+%PE>D25I7`mR?IyRlko?F)$FVHQN99u-LNNrERM5fE+V>4!t+O~u`MdLGa zTx{*yDc?Wt*FAw*uFz8~GAW*$`KWFXdg|sIy z<~YQ_40Nh;Qu5deeDD;y*nKo6(`nqKy-@B61SvHpl_aYUdQs!0Jbqs5>y}sr5OQxSL zfiO7HLq>4rEkO5|Sci^VI1dM`8e!r0M)`+7OI*<^stQQp{B&Vx+`d%vB|}tFz=P;N z0?YImL|#)y|H_VJGvOEV8uti_Am5;H2#Mn}^eW}gO+f-4k{h_LZAdgQ;i8wL)77z8 zgU4ZR8?S%s>nXW?Rg6tCvx#$G2Ve!ZZ^P;5W4-mMvBk*HY@Datl+hY{5Ytyq4-=3} z^qzD;`tR8l46O*QwIbpWs0mToFA|R*mKk-Z1`iR$uA5>nxT3Z{;!|6li%eg$%a82Q zmFSJ1G--XQys3Gm9hzs$>D^3K0(zFU2rT%9p}DK+@hNX8KbqcE%k@X_TFlm#Tw3*S z7k7?RzMbBI$873L==>7*0wkrXJ8H9mVlNrmP`{lOvhl>8?_OU9z0b_QBork1`HF|Z z5f*3|)oP-So3Pv@deKX{y1J1-dSBq~O)E2NWK1racAa@%PyR!G9|1+mfR|F$Zc<5K zC0~#0zXLmQoMYi*Il5o-8=CsGWH4DmGg(C!VgmDG-{5)+OX8idn>0%LsoJ<7xNY4| zP2;f_u!$@Nww^-&k_CamLHkp zX?-c&k_q9k;PXRXwz45J29Am9!8p`6sOSSt8cUC z7XM{82omr%U=f$y=$Jl9(GX2hbkWt%NzFSWbkYhgYW?9;2uoRvW7vZN?mh5qv`5>b_;8BKoCoxj#Haf*LP4* zaG~}`jfVOdN`Ro;a+sCrnBJ628qWfA_yhT6*o~}QeK>UYZ=tHr?uD>*XZ%7tnNrmc z=}e*~>o~}k7v$0^Sa=6uf0yN=Eop)6KvqLTLlFq{^GD`XyxUt@-2hZ}C7 zgr@%dLsr*HY<3dM?2^96cw~uAW&%U)HF&r$U5vj&D=62n+cwfIAVJQ3^ze$rYWa2e zC7FW?h3U1M9*OrN*A^AZ`}VbMcM2Ecql-cUzc1J!ntqsWq~Yliw=I#&gusr>u(8Y!k3b9B{s6V+LFsC8c&v5ck$CLeKOMX02|xP&KAwFDf!+cZarygXkEx- zP_#J$JFdsH{=$FsCpwsml?<9Noq(py85jluCypT8%B+NrBj+HA5Ei8GpXCj%>kudF zf9QC=Ur`cmg@+0`vv!cE11U_1e;T+`QpK z+rHWId9bOfe=I_*_RG1s{(Qf%L^m8m*N8%~x5NX@*E;YFV>-bDO>c)pI^l)MyQRyY zX4M0gPomO5eud2#v3}Uf36TMV?g?hv4I4SCbfFtq`X${L*YHMA zJ~RMb6z^_-#Eo{B#1E^+JV=F`<(G5&GWfuc6iUA&9K9H%37y#eea`brwcWUdhUZlc z?Fu;lFM2QoUCm7Rhi$2FjLuZ5FWt)fT)z}Lndvrv??c{wp@D~@4E0(rUWmo0&Ou*L zSALdh+jrx!A4j89-Ce=7bP>nosY5UkPZh-{!^NPfm@7M)K{4oD3>;_0U|~5NNi~Of zAso}jsdRd0Z}h1L6sM6S0}@EUmXO)E)G+`ZaGgA7#k^$bZ;^ohzcYO z8A`GX9vqMsd_CpO-&#=D*oQBK8OB-kQ_kC8J}lfZQ_;^4T#1Pj5eY#XZ+C)m~Z?0dLoq5%Iq5<$UdB_{{=^wk3 zK+DH~3#FlLnS)MY?2lgzS%!@9mk;9LKVFb>sM+D7II8h#%tQ1 zQfK5fvt17J->+2*b42Rdwd@Ydx=6&aGOzZVq%5zCy~PxhFHR@S?q~5k)3$1psXn8+ z*o*+Qsbd?cB#%hvq*t-p6=7t@ij8ay_t`_Fm-j^RUr9pO*8qYv_nAJ7|H!O}Ze#JB zrVtF=eJhHM4<)bMgLG4uSiEftw|-7Q`20d#9Yr6Nh0P{Ef1LRihm=PX6MEAdUfD*~_9mC@*) zKchcbu+W!*mRsoItgf)V!fpv7p0OPV`dIMAGLD8^J_v6utzi>VL{=L~5y6{R1HPL& z+k)niLxsxsC06}u{JDOj&il)s{GOo&8bxj3iZm$M(nfPeq#8p@znSnaR3;?-QJMmB zUODn|Oc11Mp0L-d1q45`Y)4A9MsfunqgyT~qxX^l}TzO!4xNO62*o)A-8} zk!m{~vh!ir)wd%A{yda=RgU0gE+~ATI+iC&;rzmxQ*3$IyfP!yxHcQ_>q+E>8!VLO-?EH1SHxLMrusSKARdo$0;eiE{;#H8quqta{ zI2etAwgI51^rURYMnEO}(}O{HBCFPEa{Whn3l#V`nn_P|soJ=>9M2Q0&3$xt(2qOx zHd<$Fwk-i{kw$HQHrmgw`S>HNcZoU{i6mK`P-&<%(TGv}4a%Y6F&3IQZ=3ck1w_7& zdmHNC;gw-%L&%`!A}ZxToU{8jL&#r66ZC;f68+jd%?e^P@iv3R^@}Aj$em~Hr@bYz zshE0PLhTex#%uNfG1`K@XG{xN?&UJpiJ8vIaPq6XrSV=P8iz|*yqwv; zPJ4Rp&v@RS!0{*i@a6|9pPZr5MOb*oiB);=D*R1*W0W0$1L=D+qfzM+T$rtnI2(9~ zn&>buO>vLq=Xov*Dz8gijX}=FT9qF8gt=^RI0a_+BPN28HgR*bc>n%AM)}ZC(nd>i zxwL-sPqQjR@A0ePa@moehml(_ZYz}Z$mOwRjNZ!7z|16Bor_Ah=LemzHtVVGmKx>1 z0D}-BU_%0sFM#12pw%KiM#BI6WCVZ;{~savwEm>}GAt*{FSdbgnE%+hkk*=KunP7d-yoj|(5QwE-V}z}t^eAVX(|n3;iB>%t5Y(W5O9^N5pB>wJ%P-L)=0duPLp*ta>zT>bi5iQ!iX0<2Fk-ClJF zx;bfC_Cab=8LO#qpb7a0Tp7P;qjDN3dz`jI3RpeEj!yHAd?RTDB58j7l3rrpdcX%% zARbdx95}fAo$la&z_sc*>g!E1YDS;__?`)&frPLHV?nE3Hl054jzT6Q!3p6Ansj((CQ4?K{3Q9me6Q_)Q@w#&^nb|R(XC$Nfb@N}boiI& zy$%51zX$!EX8dFt)5B%Tp?*A-*BbV*QprSubOiVmY?ug}(X#DPr z1Nw+I_PGnz@CUEQV5AM%1{F0XPGW0!)G1f@2Pl?D(>V+>JRPXml)TLwU##p-t3z7U z=pPJ?iZi3F;&RkNVnd5)@ci=1ss$skK|;R2)zo}{YrLPz5*(KIC^lvUDp^52|6yB< zx;qU=g!e-JGQFnvS2ZhjlCK`wYsk$WdiODC=&wC2g*g9`@~*A;i}I#o|8OBdIoe$f zoi42)2CHDCrO&toY5ph?Tc+Ci3VNVLo*Lp2S#Ps9A~5XZ0#_rV+S^9-)QdGP-(zxJ zaLOb{KfK79!0HL+ARG`%E+j;{+wu5sJn|nWo(-;|f(wYLy4f&Dqi3PEY_=tkmMPug zAMt`R*k)X(bS+-QP>Cj4XWLNd!nfMJ{Y;{zJ(hOD8YVIZxZ(eK@%G5c4H18ci+%Ur_s&M+kx4qT5D&mgcHU?SMp z{%Q(KY0f!AU^l{z5Ux#y84nkq@MQ&v9D3-MPN&R(G$J{Xd>*L)ui6VE|HI?|kqEa= zKYOsH;dNe9?2v#a?TcdH?}=E2ZMLPh4)}a``V54>a!F=fek6;jA&9rCEEX(#_ z)HA%$8`2zkLbV=|_J7NG4mp^#%CSQ2eaB|m)5g5Q!YV209D4YN9ljV~)dDjs5=?qE z0HXL_cKd7nH|?$Rg?ua$&h*m?2W68;D0z3p$57P9K=$_!*5h0UqVuCdk+||mPwB4+ zCjbb%0!I!CXdy>%`W*Nvr)z)^1xzEhHoDnvTOxx}>$|W0L7U*t1PsV{$aoOya)-&+ z^s9q@&c9{^X6|=3T}38iPWbR7=O2QH$~8T{j#sMc69c2_Ejs)qZ=LVzV6Mhz zYt&G;&HXg6ljC>GZ+hEOb*hrTP8^~3?OxQuxR)ll!x8g}A>r0?Udvlkg!txP{yp{} ztcVQuVB5U!2Iy-<8R!}4fm<6ij<@c(-vMmgq4Y(dv~P*IZ;5Zk-`5wnC=~4@9Gcom zKVXUD^c(mTf7BBS?`Mwz!=Zh&pZfig0Cv0~wDI3cY@ceXW;12Th7kMK~M zhWMYL2Lm-sWt5|WZzsEc)y#1Vc{_5`+?pPYVRl3_dK7F3&Z{Jkp2zjz!Z9?RP zYz4g(WvCH)d=E$B|F^EX&0zyUk}yDb?|K>GlQC>o%2bI@bd13jifT#QO!E%F!yhFG z7P4ky{`kP_cADh)jUY=B;Y-82>$NLgYW3z*9qbDJ951K~@2p!e%A|xr$iR3G#?6#2 zLRT^0qDLgurFQiHnj|kVI`AtM;~vi4VHf( z=Ea5_iu55nb=bFkh2DzbV2zxAjCq#8e=FyS`6cU{(q&8eX-!{oN7ys1iF1Ut+8@c~N)}Ml8ylM$$5k6TWX=9w)L#=m_bLA-(G4N{wo89> ziG2ERe;0tr-zq@;(cbHDBmHiXJF--KCxP}n%Jk2XAl84Z>Hmr@-(3pBZj1gDE_f;( z0nM}!v6vYPJe8a>K47`XydBO?~Aley>@qp=7>T1fBpP znwb|?grtcdI)zjg|MxheXVZK;@#Zhe{GV@Cp^w2gn(h6>aT zufnCx7*I$$zzl|l29dh?7`#y);Ho_%X;ni~E8BX1r;4-@NI>5Za(s4%AX9REcJoy1 zW_QkBILt`+*5!RJ6cDmPA_Ro2grWlXgdt&oKFR+9c7DA1ZWe6|RbZBloDHP0RWmnw zb6vD$3~M02BmyEgap>SVFcr`q`0J$Ew=)GrBaraBIE8wQPpt1dY-sk_J_LXI>~u>~ z^^V)OC5dz<-!N%&>BOP_BY=*G>y2*(fhHREL5Ww_bn)Ndw zoeYYdvP@bwp*;mEAnggA*vZy+lh}kX0WuksIE}YSgvZ`$&tkcTaZ=OLFGKaEFlEz* zPDfw(5~}5b=>m((zq{y%nhh#ne)Jsbmdt6&L(3{5-=>TIjXmE6n0xwgP9IgSLlW** z@yh;jq(i$yWt;Xg+4A-Z<7YtKV+run)j65_jp<(*X^*Rzj5gM~N!I@btp72d9U6es z0b;%QE%j2OOwr`-#eINq&Nn9u9j9LwI>t$wS9}joR%o01#Yn(t$n>FFjz+ zSW$d%#vD?kj@RAK_D&D(P1-UpJ$%;4;XcKQix{SnUhx;?Jz1$?NmInXG4LQf_GtFP z_UUuakY>vj8~*6zuCEVfu1<>y!~!i-t)J(E_unr z29_vMNvW`zpk-BGb`yX9dwFQX5)p~Rn`GjhDYWOsvEE+b+y0Kn+k z&j9;B^z?(Coq$go7`^wg1wyrRD((N>S3e~$CttV`U@XL%It;h4EIxVgQ&FYX|b`EY@$bM>9KgIhPj zhN2^~D_S>cgMCz5m((@zhyb+O69ON)^HqLtk6Kx$5mirGYB1K>js`}4n=L$ot${8) zOrwy39uvUWCD(u)82@b8gQK|FGx*w`O?B@!+?qQDVx;El_h>aaoBb9K}^@^|#mdSB3)IQ=Wt5W>2C4GOc<+i2_NW22u@^Q-026#p++g#PeN1SlA)nSQz%LJe+9Bm{Fi2W zerOsgN^5@TQER9n9_!4$wzNP4sQi+d>MSUWhgi^q_|Y^jhRO};b`|a-Z#y5&NqKq`&*UIm`o*wUVUQh*Met$2J`cz}g9IfrW z_8Ev73V{G)aj7#h@N@LRaJ@9p(yx^>;8s`17a5HENjM&rmMULT==J`V`VPm6{;9xR zYvp}XT511%c7OlRk^ZEN5#4n+D_oVVV6wcS*FWilB=E(7C3#1&7W_HOz)2xEH0qc{E@5* zoUmzGd$r}82#@{TQ>!bW15UV}1^A4^BO!k>c%E^Y=YduswX-Sd$R>t)#;H{aJgLSe zCd?ZBMxWI5Q6o@Q3oX@Dec?cW-|j>Rf_TL=fbEWcV5GY`pZN_0L90-dP7L0T?mxnr zw|>F=96##|shr>o(riVo;%jMX`Ua9wPN8=?2eQ=UfD#J$60UO#MCcJxw;LG)(>~L!6c%r2K z2EdQ)vsFgA@+&JumPNU+v0 zY4>E7)Oz}i_GWBhj>;BaENSv5@;bo1$G=w>^_R#Pok;|)ZOB~1vD3uN;zaC$|evNGy*yf=u zR#X*Ru7qTMxxKxfFZg=l-ruEo%iG&$5@si?Lw60GLQqmOH8Q4;)V=XmCRMIbg*E}G zxSpm1-ezY#_n6Q951MHr{^fD)YBCGx0^OKksM%mzR3{_j(fn@+`af#! z|H0OGk9L3OtUL73nq7SpB=HjGtszBmfA~iiSQ>}Le#7!L&~#%rYm^}((MRu$wj}^$ z44$Yb_Ly}}mOj){Qvj&R_`l$gc717ME zq4Sp3WMsy!@ALPdUXHhzn37{zn{YR?y-s0T!QWWqNTaWc|C)TE1x(}Xk`>sd8cGcZb+D!2aJ9uaK2 zwAI6XnTkh)DvfA<-mCx8;fdweiB@4lzPFrWHPf5_1E;J`@ajOjKE3S~wC~P|d_IB% zWnPp*9UYsp$s>PPsEi-#^(k{YHgm>-C8x8R7q-mSXr-^Of2cLTHCN>V@EXE^AK8C4 z`^l1Ane(4raE^tgn8GI=s<> zH#+%Z_4e4h&Iws0dt}IiPy17uG@D2E+07cKnLSlej(&gPD!S+ebse7n8(J(9scF#f zdIK|4pf+M?p%b8{H(oEr9}6@i7MvJym>D zjk;#5807giN%p|WZiCLWrNb(20o|>hOA)!Cl?#aUdQGa#y>g3D&NbB}nP|={g~L{N z0yYfu+H(iUpG@#ZLn~kJowLJDf6YkRP}M3KD*uv*DS~|8P7MAoXs1}@#oVWF)?`{1 z!BHulfg*JPHvlz9Vq9G@FZ$q5va+&AM%^M&iu{voOTm((@Pjm-+8frV$lqb$4rb4e zPbWUbRllTS7wdfQyDO(#NTR}y&#~^G_CCLEF{Sxlwq<7Uv};_ck`eCL!Js%YRC;gf zmj?~m1D_V#ryrah3)*=8j=KzD%N9yz7L@}|P^=C*uMp?op^AY)sJ4g*=)L-S?_eN& z^_=fIf#(m7@ac)-(9=4r^G|S(4evyfubNrtjWU#ZGA!&-%&eQ^zFgw{$KNN5ezCq0~-<@9c{`@U@ z2RT$yr?GZrVL;^JZBd0O>|~60v~lVJtgcergL-=4NKg{dnhSFr5yLPWP`4XaAM;|1 zwXI~3X?J3$QP>RB=G;GUZ1Qz$@$nTvGs7GKQ8U?J8lEU44C;?7lWC9}N8 zRvhTrG0~a|Kz?m7tEdF5%wLIAp^0i{e-}PLG=N*m%*>yamPiXflpWH%L~dOKVOia` ziG2-3HM#cVq1dw=P4rC|wV)Kh7F9Jcox9aUU15vK&98a*b#p z2BKFWy6Vzf`j)6?t_ijl_{uh{Ar82ZC0mZ6fvT@d%c|nl3TOjlbo8pwSOmO#7}#=W zIcorNc6HCW(9_;;vnq$3{t>H?Y&p^}MCd5O%glG8Z|6;?9Y-@8wj}ZWHM0B#reL5T zf$~ODYVUfE%J#}h@LQ`>w$Kc31A{btowC3;n|3ZtMGg_USeuRIo5A!7*bZex=kOJu z4hW@ZpTO4+8>F(ZQa|*3zIa3%ViSmzA zk&l?g%_iL0pv7pp#jBy15aK!3{HjK_KLg>Xm!^W*=R&A@$u?+5gfaLLM-U0GZac>Z zITupA`b#6f4j&b2?%E$ZRFyRC_-qr?b-&s_LW&aj?k;UNpffPssq+DK|lpmYFY_UE7*%>nkn z^_vdxo^>&=9+bO7{~bLNQb;I%>6%ru^6=iJvmN3WfBO`mk~+rnWPi%DRmMpOfv*7L z$~c~)0wf0bPr_K8th~~gcCa|?y!6+vy?uhc)4r!EDBj=cL%h$XxEumi7EHu$k)Pi&wTT4C+aAT9BuF;0DHG*;i;1jl|c zD2+_*mvRPj?L&unHmb3P@`@Q6k;RH&VW0-K`vGk6$J@0-2ndf-NnLj)R`yDvvJ)f` zUnxw5DSB2FAjypp;=@R9yulRZs}Wdz=X*Pw&N%#-nbsV=tnySZhT;6B+g06(9QYuEL%-l*vM$82-FJc~M&K^`rtkfe@MeeP$=;j2S!ENwMB4ukI}i`f`YZ5<>b78)D0ToC>1!cNs*CZJRZ(gHrA z##vx7oUNai_ibvr&X=*?CcvCKPf3PKs>#S7ykakc88qwe=sqQzku}oYorvi~g8cA` zIK2}-@NA$9s)pV9o;{zE=#UU9R`!Zfo{Hrm%{Y|SiyY$9^{erH-i@S%|RWRgCjm~{&XvktF_2$H@qCn z7G1{I44?ZayWam<67Y;}bKh1=XK~kXd)ajQ&2L_LwPwR^_shY#wPE!TJUSciXG7mc zN%kF_a(^7V8`5k{$nCb(y=pu6Xm_dOP9e>hUOi1UArA|n#|e1ZPi=|;W*3PMxoUbI zgldRtP>GY#>@uug=k{1sJWX)|^>p)?*P{o54-wfQ7$|mRG8~1FAM8B?;x6w4^4dj5 z9}sdJ1u;*Jr<$uQtc6E;N>)0Yw4zbBK0Cbke|L|1`(|X?hQXEE~RYv1GGUdt5tB?E@RqCn71yw@Sx%%t+ymL*_&6c;5S_C zDP>fR7&fcU_h;PHXq#3!VkT7;Bkz;&Y5Zf{u!Y)=jXPqv+4@7ycuiPd5G}dH>Zj+i zu{DqQM9T>M%n6TuC5VCc9@RMW3Ax{&Ou2=^A%xnL#s7Bfb{p~3@!Co6V5^G^BQ*0$ zYWjSqZF|eIHgfLcm0Ko@ZZp*_c>9n2?uPM>8Iso73e_OF|u5 zx>y0o(mIQ^vT0+&QZ!zN;hzx$iNAzTKSc0&w%a-}eqcH_EbDnFsGV#J`!Uo_q=wi{jZV9_eD=3T{t>(t6)nx);ZfoQI%-m6o|2-t|KN)X`(r@T|@o-ghT*r zk#8+p`z-Wadh^HmgX#+_-DQk*lZ#ws86v`E{RUHRx2pMG8FnNr76NXsrELzZ*A2d34*Vn}Fxi6#t7Qfu zZMm0f(^IE=8^bh|!8P1t^NhKawM0~=!*WSe`TOe4?lI|ij$QGOd>%>iV@mY5qCcK$ z?PUo^EE`zx6ycM~8qnyhg_}M682Bz(!J}bhzV(aHql*=R=vN>8T`UIaO8QUiMdEU9 zAA~3CHpRus&_okmt(o!82tK`OR}Cc~D+zU)u;1J5w7f|Uok?*+Nr5&PmKce*LTbs+ z&s8@%Vp`=As<{+ETv}WVv0M^rW*X*JcP-Aa#>>=OcZuUpV=Z40%kMtz{bNJ*>o@#) zFxG^u1aC1%)Ov_{@hi4x8e|;t+po4X3_5fht{mR9WzF7si^RS&#+&Lzp~JMxjqmY; zNP^PKQu+pu$HKSX&I3;z1oj;g8l+Bu^i}Fh0}>&6+GFxJSL{DLz45?uh4+PS+q!gh zW!7tg%@fDP3+}w+4DJ>tjSz)!&{L;>*}bY?Rnd(QWJr{x{kEJ6F|K!rb!ujXZ;}5P zowVchM}e53Je0Xo7}&-q_4o=*3~Td_>6qn0b`bxH5oXXRG6dlM?#Uyx%2^ z2-(Cthp7H|#=FDzrbRVxzAgXl!9(3zTV`mwk{D$KH)8;QnjZ8fwj{Sovo6|%zdj_k zU)`Ge3_b1$5{h<_Dd*{v}45-2P?jV$6l**$D=Ai9p7efSc11dDr((wF4D@(PO-a`~17iiQk%@8n!Xr_J^Dg_;)O)mi8F=;fu0CG_RFAk5U}=_KKW2-CnM>ENLHFcX1{ee)!cc)&pS9o}-x zdo4Lb|7~$H&7725Er{r?%H|hA^l(IT%P*dv#VQmz+Gst7blxTtC#Jl@gd7P5~(QCy`D1)?->MmN1&X z=U5;Pgb+C@u$j5$%cSMvq*00RF+eqX79zsAN7>AQfhmzk#Ak9iM(_B|u$zg?T~`!6)~P<7Zvrg-BAv z;vEbA(xs>`2!aPgWW@PlO)l*uLt!y$T$w25c;K?+O@!nLO7ctxzE64f{`6y1Y35C~ z$)xg*kxIx&`Hg03*{+00KJF}J!?p>cTP3Fk>%?$CBVtLrcz(2nOz zHl^fvrtGVz*s^ugQ2-8Sg9DB>QTWamQUeOWlgZ~^%@>Ip2Z?W6PgklyzkZ~1?*w-j&g>bhR2cH_&z?O<|^&>!uQ!4iUnb`!Nw_@8mM|a0ybYr z-}>3Le_h~B{NCpTF}A(TD~P#vQ!-BHr*1RJ*$Hm1; zUTr-+`9u&{5Et}hs2|tcZwY}nR{qeyECp+EqB1-QB}v10%9w&ZV1{aAhTuPJ*9HGU z;$R+M3+J6KOf8Q?Ydp3?10C|d?W1pYzw0y?3cm^a%+-9>+I8#Gj`o-Go2gsX%a31? zbBg6>WzYpM_m)E_$y)t!g}$vLOS;CNli7Pt5({8)&C|svOcVmC*-cJct=-~KM_v&z zEav=K7@G17th})LV{=h+2s8!EWCX4}lEFAum>!*YteXt(l)ckz8yj+0N>A z%7XInX7lZ^9Ckx27KJwr*qHR~e>OAzaGe1RZAi^>k<2M(DMv@eh&pjRLejBuw3 zm<8;$gHo&NwZ6P&%hN0AEPmM2u!8?{nV6egdRvG3-46%n>d*L8dE`pq2vL!_DZ zV-$Jnh7l*U0VyG^T~xjpfu#)|)F}zC$3Y1i8eN+pu~!i@PZN zaJ~cPDZD@T0UBKvT?i5eEV4-wc*=isG^81?SNZpkYy#k}z#dA?wa%=)$*&_Awk&g5 zeL(dPxOs>?jv~&x%+>I7S$U}_^9-Z+S6jQx8H{w)TZ8h8OcSSlaVQjvlR=@z zF$EK?&+?;Y1#M6&DlP>oI$+M_NW09Q{qsz(PF%(>q_>#gnm1hBDfvkq?}qC&G|nH; z3^-X0y4MX@bNE3pqugShorv|6)|B0{xte%TMl6}czkleJr!eY`sBWQNk_qEgu`&@ zFZPDWg<*kbuu&IY^b7BHuOoQLw&aaxz{acc0n2*F6p8#}BV!Av%N-7bdLri$gj@Xt z`1j#V**bg}(#-L&axVz!Xr9nkeze{D4oGnbkncfqgyyWsU}E_78bD>0JQ~&}n$8pw zvpsMoH2&kPX5wa4u<$Npqt%Ew?I+UxxLpIm>p?BlthMyR!kx1;s6Z#tO z#_KqJ;g@HYg3#MC{_Onu)s+euQpJ+OG?f((s8ve2FR@x0HO}+(pX;8)!T^>{C{PCM z{|4Me6Wyk}chg2$3AH=Ur`Xrf5F2?P??3x_AA!l^a;LYWo-$6)oW+PnkKb#}CFAiG znY3W&>P7EuZ+j>){?&&89ABcHrpUXXZq6mCvOH4abX7S7g@v?tbi&J$*4Djj-FrGQR~%i!ALEU-0YEs%pfzfGGnSlM;{Fm{)-}ZKeoidcY2I zHs&zBMC{AZuSg3xbJz*-MI)G7%odIp>vH_r*iVAgc|_r`H9LC5K-$CizPg!-11>_S z6oE3*S7)(A_-IT}8JrN_Xxo*zj!rOcW0Hi^jl(U+A^K0h;_>lEj#6HjAZHR1pFjwN z;JR1qfoHu4r2STjYHPAFp3^j6gLrMDWUo=`0Lv~5h0H@B?H*Ly!Dtf&Pv(9@L=MmJ9Gqz5O55^kqY*oX;%hN3UP%=hK2u~~iVH3~`_ z>834E;vC43%^lD4@-?7u`~vBHEIfvUN_pd%ylloKc(!`wn*Q47sgwYVI@=cNmxjR& z?|bA_J-aRL%TcFvt95CE%er~_iZB8TdV9)=X_v1xX%lK2($v<~Ulyk4M;wC9smZSz z%EWwu)!*gK_JumZ^c-6buxv=)&g-ar4cjhFk&uCC2EC%?PbE}I$GL_8^Z1ZJV1wWk)UY)wD~8Xr;h>h4rHHMRl_qzXqDMXK^6+NzH-0^>wT)=kN0}wvt*+~Uk=c3m zs}U!ZUwv7^>ZO_Gsq<#b)@!?IeeSjG#aR^@XSa(D0UYyk$69V8x9d)^^KOv>yVu#~ zWep5r{PK0l1xXQ%_1pM5S$ys;9$MaoS!MHP43=hJ=bpD#e96>3CSeE6jH%58OGolO zL7IG>zaL@10!}ui*buQRjBcY?hW{q}Y$=wKqRW+9zJ%5uy-9^1{u)uy$VZUQV5^A4Ksg%fS+?1V1cLtuXX4$IRK@ zhK+><=e*GlS+GkO)YGl4E@O2LqaDI5?Zmcd(y*Luq8ws4T8kT=co!%ATo%MPtPI{0 z==5==Z^y~QIDUi76-fpKStEqYMDN>L@qo^iu-6WGE|(evIA^?vXNf|7EE7&}I3MsA z{`&0Z>_)0>uT>CBMO91+ zi4A3lKSTnzN*r(7oJF3%SLH#nK43ksCOLfKp!x)uDY~oeny0N9%C8gj`!Ww~ T^0&)8MBoZe)hBfb0`z|XZcKkT literal 0 HcmV?d00001 From 1cfa87853a3fe1edf569a91c60528ee2d85679f7 Mon Sep 17 00:00:00 2001 From: Elliot Smith Date: Wed, 11 Aug 2010 17:11:29 +0100 Subject: [PATCH 11/15] cookbook: Made stage slightly smaller for scroll event example Reduced the size of the stage to make for a smaller video. --- doc/cookbook/examples/events-mouse-scroll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/cookbook/examples/events-mouse-scroll.c b/doc/cookbook/examples/events-mouse-scroll.c index 08980f939..d8d6163f6 100644 --- a/doc/cookbook/examples/events-mouse-scroll.c +++ b/doc/cookbook/examples/events-mouse-scroll.c @@ -1,6 +1,6 @@ #include -#define STAGE_HEIGHT 400 +#define STAGE_HEIGHT 300 #define STAGE_WIDTH STAGE_HEIGHT #define SCROLL_AMOUNT STAGE_HEIGHT * 0.125 From a421f0ae429bcf666dbfa1d44b15bfdbb06f898f Mon Sep 17 00:00:00 2001 From: Elliot Smith Date: Wed, 11 Aug 2010 17:12:42 +0100 Subject: [PATCH 12/15] cookbook: Included video of the scroll example running Inlined the video of the mouse scroll example code running to the docbook file for events. --- doc/cookbook/events.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/cookbook/events.xml b/doc/cookbook/events.xml index 64d6a26d0..5b6683b39 100644 --- a/doc/cookbook/events.xml +++ b/doc/cookbook/events.xml @@ -654,6 +654,17 @@ g_signal_connect (viewport, + Here's a video of the result: + + + + + + + Video showing a scrollable actor + + + From a74d585fc522d010d4c8cbcffc566afc9ce495ca Mon Sep 17 00:00:00 2001 From: Elliot Smith Date: Wed, 11 Aug 2010 17:14:09 +0100 Subject: [PATCH 13/15] cookbook: Mentioned the animation in the sample code Put in comments to make it clear where the animation for the mouse scroll is coming from in the sample code. --- doc/cookbook/events.xml | 1 + doc/cookbook/examples/events-mouse-scroll.c | 1 + 2 files changed, 2 insertions(+) diff --git a/doc/cookbook/events.xml b/doc/cookbook/events.xml index 5b6683b39..802885fab 100644 --- a/doc/cookbook/events.xml +++ b/doc/cookbook/events.xml @@ -609,6 +609,7 @@ _scroll_event_cb (ClutterActor *viewport, viewport_height - scrollable_height, 0.0); + /* animate the change to the scrollable's y coordinate */ clutter_actor_animate (scrollable, CLUTTER_EASE_OUT_CUBIC, 300, diff --git a/doc/cookbook/examples/events-mouse-scroll.c b/doc/cookbook/examples/events-mouse-scroll.c index d8d6163f6..bce9c40b4 100644 --- a/doc/cookbook/examples/events-mouse-scroll.c +++ b/doc/cookbook/examples/events-mouse-scroll.c @@ -50,6 +50,7 @@ _scroll_event_cb (ClutterActor *viewport, viewport_height - scrollable_height, 0.0); + /* animate the change to the scrollable's y coordinate */ clutter_actor_animate (scrollable, CLUTTER_EASE_OUT_CUBIC, 300, From 8db96675d4332bc81edb1f5f4dfe237ab81a4d9e Mon Sep 17 00:00:00 2001 From: Elliot Smith Date: Thu, 12 Aug 2010 10:05:27 +0100 Subject: [PATCH 14/15] cookbook: Added more explanation about setting y coord on scrollable Added some extra explanation, referencing the sample code, to try to make the scrollable actor example easier to follow. Basically demonstrates the principles described in the paragraph about setting the y coordinate for the scrollable actor, but using actual numbers. --- doc/cookbook/events.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/cookbook/events.xml b/doc/cookbook/events.xml index 802885fab..77784e0dc 100644 --- a/doc/cookbook/events.xml +++ b/doc/cookbook/events.xml @@ -635,6 +635,17 @@ _scroll_event_cb (ClutterActor *viewport, Scrolling down adds to the y coordinate (but only up to a maximum value of 0.0). + + To see how this works in practice, look at + the code + sample. There, the height of the scrollable actor is + set to 300 and the height of the viewport to + 150. This means that the y + coordinate value for the scrollable actor will vary between + -150.0 (150 - 300), making + its base visible and clipping the top; and + 0.0, where its top is visible and its base + clipped. From 1ed5d5cab0af5617b566465b943615d3c7f1058c Mon Sep 17 00:00:00 2001 From: Elliot Smith Date: Thu, 12 Aug 2010 10:16:56 +0100 Subject: [PATCH 15/15] cookbook: Cleaning up grammar and wording in mouse scroll recipe --- doc/cookbook/events.xml | 86 +++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 41 deletions(-) diff --git a/doc/cookbook/events.xml b/doc/cookbook/events.xml index 77784e0dc..a15c57625 100644 --- a/doc/cookbook/events.xml +++ b/doc/cookbook/events.xml @@ -347,13 +347,14 @@ clutter_stage_set_key_focus (stage, actor);
- Detecting mouse wheel scrolling on an actor + Detecting mouse scrolling on an actor
Problem - You want to detect when the mouse wheel is scrolled on an - actor. + You want to detect when the mouse is scrolled on an + actor (e.g. the pointer is over an actor when a mouse + wheel is scrolled).
@@ -373,21 +374,7 @@ clutter_actor_set_reactive (actor, TRUE); - Next, connect a callback handler to the - scroll-event signal of the actor: - - - - - - - - Finally, create a callback handler to examine the scroll + Next, create a callback handler to examine the scroll event and respond to it: @@ -398,7 +385,7 @@ _scroll_event_cb (ClutterActor *actor, ClutterEvent *event, gpointer user_data) { - /* determine the direction the mouse wheel was scrolled */ + /* determine the direction the mouse was scrolled */ ClutterScrollDirection direction; direction = clutter_event_get_scroll_direction (event); @@ -424,6 +411,21 @@ _scroll_event_cb (ClutterActor *actor, ]]> + + Finally, connect the callback handler to the + scroll-event signal of the actor: + + + + + + +
@@ -431,8 +433,8 @@ _scroll_event_cb (ClutterActor *actor, A standard mouse wheel will only return up and down movements; but in cases where the mouse has left and - right scrolling (e.g. a trackball mouse), left and right scroll - events may also be emitted. + right scrolling (e.g. a trackball mouse or trackpad), left and + right scroll events may also be emitted.
Creating a scrolling viewport for an actor @@ -475,7 +477,7 @@ _scroll_event_cb (ClutterActor *actor, Create the scrollable actor; it should be larger - than the scrollview. This example uses a ClutterTexture, + than the viewport. This example uses a ClutterTexture, but any ClutterActor will work: @@ -488,14 +490,15 @@ clutter_texture_set_keep_aspect_ratio (CLUTTER_TEXTURE (texture), /* * set the texture's height so it's as tall as the stage - * (STAGE_HEIGHT is define'd at the top of the file); - * see this recipe - * for more about loading images into textures + * (STAGE_HEIGHT is define'd at the top of the file) */ clutter_actor_set_request_mode (texture, CLUTTER_REQUEST_WIDTH_FOR_HEIGHT); clutter_actor_set_height (texture, STAGE_HEIGHT); -/* load the image file */ +/* + * load the image file; + * see this recipe for more about loading images into textures + */ clutter_texture_set_from_file (CLUTTER_TEXTURE (texture), image_file_path, NULL); @@ -533,17 +536,17 @@ clutter_actor_set_clip_to_allocation (viewport, TRUE); The key here is calling clutter_actor_set_clip_to_allocation (viewport, TRUE). This configures the viewport group so - that any of its children are clipped: i.e. only the area of - the children which fits inside the group is visible. This + that any of its children are clipped: i.e. only parts of + its children which fit inside its allocation are visible. This in turn requires setting an explicit size on the group, rather than allowing it to size itself to fit its - children (the default). + children (the latter is the default). - Put the scrollable actor into the scroll view and - the scroll view into its container (in this case, + Put the scrollable actor into the viewport; and + the viewport into its container (in this case, the default stage): @@ -557,8 +560,8 @@ clutter_container_add_actor (CLUTTER_CONTAINER (stage), viewport); - Create a callback handler for scroll event signals - emitted by the viewport: + Create a callback handler for scroll-event + signals emitted by the viewport: @@ -625,15 +628,15 @@ _scroll_event_cb (ClutterActor *viewport, The approach taken here is to move the scrollable actor up, relative to the viewport. Initially, the scrollable will have a y coordinate value - of 0.0 (it is aligned to the top of the viewport). - Scrolling up subtracts from the + of 0.0 (aligned to the top of the viewport). + Scrolling up decrements the y coordinate (down to a minumum of viewport_height - scrollable_height). This moves - the top of the scrollable "outside" the clip area of the + the top of the scrollable actor "outside" the clip area of the viewport; simultaneously, more of the bottom part of the scrollable moves into the clip area, becoming visible. - Scrolling down adds to the y coordinate + Scrolling down increments the y coordinate (but only up to a maximum value of 0.0). To see how this works in practice, look at @@ -642,16 +645,17 @@ _scroll_event_cb (ClutterActor *viewport, set to 300 and the height of the viewport to 150. This means that the y coordinate value for the scrollable actor will vary between - -150.0 (150 - 300), making - its base visible and clipping the top; and + -150.0: 150 (the viewport's height) + - 300 (the scrollable actor's height), making + its base visible and clipping its top; and 0.0, where its top is visible and its base clipped. Connect the callback handler to the signal; note - that we pass the scrollable (the texture) to the callback, - as we're moving the texture inside the viewport to + that we pass the scrollable actor (the texture) to the callback, + as we're moving the texture relative to the viewport to create the scrolling effect: